diff --git a/libultraship/libultraship/Controller.h b/libultraship/libultraship/Controller.h index c78142af4..256b31fee 100644 --- a/libultraship/libultraship/Controller.h +++ b/libultraship/libultraship/Controller.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "stdint.h" #include "UltraController.h" #include "ControllerAttachment.h" @@ -19,12 +20,17 @@ namespace Ship { void Read(OSContPad* pad); virtual void ReadFromSource() = 0; virtual void WriteToSource(ControllerCallback* controller) = 0; + virtual bool Connected() const = 0; + virtual bool CanRumble() const = 0; bool isRumbling; void SetButtonMapping(const std::string& szButtonName, int32_t dwScancode); std::shared_ptr GetAttachment() { return Attachment; } int32_t GetControllerNumber() { return dwControllerNumber; } + virtual bool HasPadConf() const = 0; + virtual std::optional GetPadConfSection() = 0; + protected: int32_t dwPressedButtons; std::map ButtonMapping; diff --git a/libultraship/libultraship/GameSettings.cpp b/libultraship/libultraship/GameSettings.cpp index 029e2a1a2..244e1a394 100644 --- a/libultraship/libultraship/GameSettings.cpp +++ b/libultraship/libultraship/GameSettings.cpp @@ -15,6 +15,8 @@ #include #include "SohHooks.h" +#include "Window.h" + #define ABS(var) var < 0 ? -(var) : var using namespace Ship; @@ -64,7 +66,7 @@ namespace Game { CVar_SetS32("gPauseLiveLink", Settings.enhancements.animated_pause_menu); Settings.enhancements.dynamic_wallet_icon = stob(Conf[EnhancementSection]["dynamic_wallet_icon"]); - CVar_SetS32(const_cast("gDynamicWalletIcon"), Settings.enhancements.dynamic_wallet_icon); + CVar_SetS32("gDynamicWalletIcon", Settings.enhancements.dynamic_wallet_icon); Settings.enhancements.minimal_ui = stob(Conf[EnhancementSection]["minimal_ui"]); CVar_SetS32("gMinimalUI", Settings.enhancements.minimal_ui); @@ -99,91 +101,88 @@ namespace Game { CVar_SetFloat("gFanfareVolume", Settings.audio.fanfare); // Controllers - Settings.controller.gyro_sensitivity = Ship::stof(Conf[ControllerSection]["gyro_sensitivity"]); - CVar_SetFloat("gGyroSensitivity", Settings.controller.gyro_sensitivity); - - Settings.controller.rumble_strength = Ship::stof(Conf[ControllerSection]["rumble_strength"]); - CVar_SetFloat("gRumbleStrength", Settings.controller.rumble_strength); + Settings.controller.rumble_enabled = Ship::stof(Conf[ControllerSection]["rumble_enabled"]); + CVar_SetS32("gRumbleEnabled", Settings.controller.rumble_enabled); Settings.controller.input_scale = Ship::stof(Conf[ControllerSection]["input_scale"]); CVar_SetFloat("gInputScale", Settings.controller.input_scale); Settings.controller.input_enabled = stob(Conf[ControllerSection]["input_enabled"]); - CVar_SetS32(const_cast("gInputEnabled"), Settings.controller.input_enabled); + CVar_SetS32("gInputEnabled", Settings.controller.input_enabled); //Tunics Settings.cosmetic.tunic_kokiri_red = (Conf[CosmeticsSection]["tunic_kokiri_red"] != "") ? Ship::stoi(Conf[CosmeticsSection]["tunic_kokiri_red"]) : Settings.cosmetic.tunic_kokiri_red; - CVar_SetS32(const_cast("gTunic_Kokiri_Red"), Settings.cosmetic.tunic_kokiri_red); + CVar_SetS32("gTunic_Kokiri_Red", Settings.cosmetic.tunic_kokiri_red); Settings.cosmetic.tunic_kokiri_green = (Conf[CosmeticsSection]["tunic_kokiri_green"] != "") ? Ship::stoi(Conf[CosmeticsSection]["tunic_kokiri_green"]) : Settings.cosmetic.tunic_kokiri_green; - CVar_SetS32(const_cast("gTunic_Kokiri_Green"), Settings.cosmetic.tunic_kokiri_green); + CVar_SetS32("gTunic_Kokiri_Green", Settings.cosmetic.tunic_kokiri_green); Settings.cosmetic.tunic_kokiri_blue = (Conf[CosmeticsSection]["tunic_kokiri_blue"] != "") ? Ship::stoi(Conf[CosmeticsSection]["tunic_kokiri_blue"]) : Settings.cosmetic.tunic_kokiri_blue; - CVar_SetS32(const_cast("gTunic_Kokiri_Blue"), Settings.cosmetic.tunic_kokiri_blue); + CVar_SetS32("gTunic_Kokiri_Blue", Settings.cosmetic.tunic_kokiri_blue); Settings.cosmetic.tunic_goron_red = (Conf[CosmeticsSection]["tunic_goron_red"] != "") ? Ship::stoi(Conf[CosmeticsSection]["tunic_goron_red"]) : Settings.cosmetic.tunic_goron_red; - CVar_SetS32(const_cast("gTunic_Goron_Red"), Settings.cosmetic.tunic_goron_red); + CVar_SetS32("gTunic_Goron_Red", Settings.cosmetic.tunic_goron_red); Settings.cosmetic.tunic_goron_green = (Conf[CosmeticsSection]["tunic_goron_green"] != "") ? Ship::stoi(Conf[CosmeticsSection]["tunic_goron_green"]) : Settings.cosmetic.tunic_goron_green; - CVar_SetS32(const_cast("gTunic_Goron_Green"), Settings.cosmetic.tunic_goron_green); + CVar_SetS32("gTunic_Goron_Green", Settings.cosmetic.tunic_goron_green); Settings.cosmetic.tunic_goron_blue = (Conf[CosmeticsSection]["tunic_goron_blue"] != "") ? Ship::stoi(Conf[CosmeticsSection]["tunic_goron_blue"]) : Settings.cosmetic.tunic_goron_blue; - CVar_SetS32(const_cast("gTunic_Goron_Blue"), Settings.cosmetic.tunic_goron_blue); + CVar_SetS32("gTunic_Goron_Blue", Settings.cosmetic.tunic_goron_blue); Settings.cosmetic.tunic_zora_red = (Conf[CosmeticsSection]["tunic_zora_green"] != "") ? Ship::stoi(Conf[CosmeticsSection]["tunic_zora_red"]) : Settings.cosmetic.tunic_zora_red; - CVar_SetS32(const_cast("gTunic_Zora_Red"), Settings.cosmetic.tunic_zora_red); + CVar_SetS32("gTunic_Zora_Red", Settings.cosmetic.tunic_zora_red); Settings.cosmetic.tunic_zora_green = (Conf[CosmeticsSection]["tunic_zora_green"] != "") ? Ship::stoi(Conf[CosmeticsSection]["tunic_zora_green"]) : Settings.cosmetic.tunic_zora_green; - CVar_SetS32(const_cast("gTunic_Zora_Green"), Settings.cosmetic.tunic_zora_green); + CVar_SetS32("gTunic_Zora_Green", Settings.cosmetic.tunic_zora_green); Settings.cosmetic.tunic_zora_blue = (Conf[CosmeticsSection]["tunic_zora_blue"] != "" ) ? Ship::stoi(Conf[CosmeticsSection]["tunic_zora_blue"]) : Settings.cosmetic.tunic_zora_blue; - CVar_SetS32(const_cast("gTunic_Zora_Blue"), Settings.cosmetic.tunic_zora_blue); + CVar_SetS32("gTunic_Zora_Blue", Settings.cosmetic.tunic_zora_blue); //Navi Settings.cosmetic.navi_idle_inner_red = (Conf[CosmeticsSection]["navi_idle_inner_red"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_idle_inner_red"]) : Settings.cosmetic.navi_idle_inner_red; - CVar_SetS32(const_cast("gNavi_Idle_Inner_Red"), Settings.cosmetic.navi_idle_inner_red); + CVar_SetS32("gNavi_Idle_Inner_Red", Settings.cosmetic.navi_idle_inner_red); Settings.cosmetic.navi_idle_inner_green = (Conf[CosmeticsSection]["navi_idle_inner_green"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_idle_inner_green"]) : Settings.cosmetic.navi_idle_inner_green; - CVar_SetS32(const_cast("gNavi_Idle_Inner_Green"), Settings.cosmetic.navi_idle_inner_green); + CVar_SetS32("gNavi_Idle_Inner_Green", Settings.cosmetic.navi_idle_inner_green); Settings.cosmetic.navi_idle_inner_blue = (Conf[CosmeticsSection]["navi_idle_inner_blue"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_idle_inner_blue"]) : Settings.cosmetic.navi_idle_inner_blue; - CVar_SetS32(const_cast("gNavi_Idle_Inner_Blue"), Settings.cosmetic.navi_idle_inner_blue); + CVar_SetS32("gNavi_Idle_Inner_Blue", Settings.cosmetic.navi_idle_inner_blue); Settings.cosmetic.navi_idle_outer_red = (Conf[CosmeticsSection]["navi_idle_outer_red"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_idle_outer_red"]) : Settings.cosmetic.navi_idle_outer_red; - CVar_SetS32(const_cast("gNavi_Idle_Outer_Red"), Settings.cosmetic.navi_idle_outer_red); + CVar_SetS32("gNavi_Idle_Outer_Red", Settings.cosmetic.navi_idle_outer_red); Settings.cosmetic.navi_idle_outer_green = (Conf[CosmeticsSection]["navi_idle_outer_green"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_idle_outer_green"]) : Settings.cosmetic.navi_idle_outer_green; - CVar_SetS32(const_cast("gNavi_Idle_Outer_Green"), Settings.cosmetic.navi_idle_outer_green); + CVar_SetS32("gNavi_Idle_Outer_Green", Settings.cosmetic.navi_idle_outer_green); Settings.cosmetic.navi_idle_outer_blue = (Conf[CosmeticsSection]["navi_idle_outer_blue"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_idle_outer_blue"]) : Settings.cosmetic.navi_idle_outer_blue; - CVar_SetS32(const_cast("gNavi_Idle_Outer_Blue"), Settings.cosmetic.navi_idle_outer_blue); + CVar_SetS32("gNavi_Idle_Outer_Blue", Settings.cosmetic.navi_idle_outer_blue); Settings.cosmetic.navi_npc_inner_red = (Conf[CosmeticsSection]["navi_npc_inner_red"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_npc_inner_red"]) : Settings.cosmetic.navi_npc_inner_red; - CVar_SetS32(const_cast("gNavi_NPC_Inner_Red"), Settings.cosmetic.navi_npc_inner_red); + CVar_SetS32("gNavi_NPC_Inner_Red", Settings.cosmetic.navi_npc_inner_red); Settings.cosmetic.navi_npc_inner_green = (Conf[CosmeticsSection]["navi_npc_inner_green"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_npc_inner_green"]) : Settings.cosmetic.navi_npc_inner_green; - CVar_SetS32(const_cast("gNavi_NPC_Inner_Green"), Settings.cosmetic.navi_npc_inner_green); + CVar_SetS32("gNavi_NPC_Inner_Green", Settings.cosmetic.navi_npc_inner_green); Settings.cosmetic.navi_npc_inner_blue = (Conf[CosmeticsSection]["navi_npc_inner_blue"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_npc_inner_blue"]) : Settings.cosmetic.navi_npc_inner_blue; - CVar_SetS32(const_cast("gNavi_NPC_Inner_Blue"), Settings.cosmetic.navi_npc_inner_blue); + CVar_SetS32("gNavi_NPC_Inner_Blue", Settings.cosmetic.navi_npc_inner_blue); Settings.cosmetic.navi_npc_outer_red = (Conf[CosmeticsSection]["navi_npc_outer_red"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_npc_outer_red"]) : Settings.cosmetic.navi_npc_outer_red; - CVar_SetS32(const_cast("gNavi_NPC_Outer_Red"), Settings.cosmetic.navi_npc_outer_red); + CVar_SetS32("gNavi_NPC_Outer_Red", Settings.cosmetic.navi_npc_outer_red); Settings.cosmetic.navi_npc_outer_green = (Conf[CosmeticsSection]["navi_npc_outer_green"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_npc_outer_green"]) : Settings.cosmetic.navi_npc_outer_green; - CVar_SetS32(const_cast("gNavi_NPC_Outer_Green"), Settings.cosmetic.navi_npc_outer_green); + CVar_SetS32("gNavi_NPC_Outer_Green", Settings.cosmetic.navi_npc_outer_green); Settings.cosmetic.navi_npc_outer_blue = (Conf[CosmeticsSection]["navi_npc_outer_blue"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_npc_outer_blue"]) : Settings.cosmetic.navi_npc_outer_blue; - CVar_SetS32(const_cast("gNavi_NPC_Outer_Blue"), Settings.cosmetic.navi_npc_outer_blue); + CVar_SetS32("gNavi_NPC_Outer_Blue", Settings.cosmetic.navi_npc_outer_blue); Settings.cosmetic.navi_enemy_inner_red = (Conf[CosmeticsSection]["navi_enemy_inner_red"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_enemy_inner_red"]) : Settings.cosmetic.navi_enemy_inner_red; - CVar_SetS32(const_cast("gNavi_Enemy_Inner_Red"), Settings.cosmetic.navi_enemy_inner_red); + CVar_SetS32("gNavi_Enemy_Inner_Red", Settings.cosmetic.navi_enemy_inner_red); Settings.cosmetic.navi_enemy_inner_green = (Conf[CosmeticsSection]["navi_enemy_inner_green"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_enemy_inner_green"]) : Settings.cosmetic.navi_enemy_inner_green; - CVar_SetS32(const_cast("gNavi_Enemy_Inner_Green"), Settings.cosmetic.navi_enemy_inner_green); + CVar_SetS32("gNavi_Enemy_Inner_Green", Settings.cosmetic.navi_enemy_inner_green); Settings.cosmetic.navi_enemy_inner_blue = (Conf[CosmeticsSection]["navi_enemy_inner_blue"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_enemy_inner_blue"]) : Settings.cosmetic.navi_enemy_inner_blue; - CVar_SetS32(const_cast("gNavi_Enemy_Inner_Blue"), Settings.cosmetic.navi_enemy_inner_blue); + CVar_SetS32("gNavi_Enemy_Inner_Blue", Settings.cosmetic.navi_enemy_inner_blue); Settings.cosmetic.navi_enemy_outer_red = (Conf[CosmeticsSection]["navi_enemy_outer_red"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_enemy_outer_red"]) : Settings.cosmetic.navi_enemy_outer_red; - CVar_SetS32(const_cast("gNavi_Enemy_Outer_Red"), Settings.cosmetic.navi_enemy_outer_red); + CVar_SetS32("gNavi_Enemy_Outer_Red", Settings.cosmetic.navi_enemy_outer_red); Settings.cosmetic.navi_enemy_outer_green = (Conf[CosmeticsSection]["navi_enemy_outer_green"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_enemy_outer_green"]) : Settings.cosmetic.navi_enemy_outer_green; - CVar_SetS32(const_cast("gNavi_Enemy_Outer_Green"), Settings.cosmetic.navi_enemy_outer_green); + CVar_SetS32("gNavi_Enemy_Outer_Green", Settings.cosmetic.navi_enemy_outer_green); Settings.cosmetic.navi_enemy_outer_blue = (Conf[CosmeticsSection]["navi_enemy_outer_blue"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_enemy_outer_blue"]) : Settings.cosmetic.navi_enemy_outer_blue; - CVar_SetS32(const_cast("gNavi_Enemy_Outer_Blue"), Settings.cosmetic.navi_enemy_outer_blue); + CVar_SetS32("gNavi_Enemy_Outer_Blue", Settings.cosmetic.navi_enemy_outer_blue); Settings.cosmetic.navi_prop_inner_red = (Conf[CosmeticsSection]["navi_prop_inner_red"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_prop_inner_red"]) : Settings.cosmetic.navi_prop_inner_red; - CVar_SetS32(const_cast("gNavi_Prop_Inner_Red"), Settings.cosmetic.navi_prop_inner_red); + CVar_SetS32("gNavi_Prop_Inner_Red", Settings.cosmetic.navi_prop_inner_red); Settings.cosmetic.navi_prop_inner_green = (Conf[CosmeticsSection]["navi_prop_inner_green"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_prop_inner_green"]) : Settings.cosmetic.navi_prop_inner_green; - CVar_SetS32(const_cast("gNavi_Prop_Inner_Green"), Settings.cosmetic.navi_prop_inner_green); + CVar_SetS32("gNavi_Prop_Inner_Green", Settings.cosmetic.navi_prop_inner_green); Settings.cosmetic.navi_prop_inner_blue = (Conf[CosmeticsSection]["navi_prop_inner_blue"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_prop_inner_blue"]) : Settings.cosmetic.navi_prop_inner_blue; - CVar_SetS32(const_cast("gNavi_Prop_Inner_Blue"), Settings.cosmetic.navi_prop_inner_blue); + CVar_SetS32("gNavi_Prop_Inner_Blue", Settings.cosmetic.navi_prop_inner_blue); Settings.cosmetic.navi_prop_outer_red = (Conf[CosmeticsSection]["navi_prop_outer_red"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_prop_outer_red"]) : Settings.cosmetic.navi_prop_outer_red; - CVar_SetS32(const_cast("gNavi_Prop_Outer_Red"), Settings.cosmetic.navi_prop_outer_red); + CVar_SetS32("gNavi_Prop_Outer_Red", Settings.cosmetic.navi_prop_outer_red); Settings.cosmetic.navi_prop_outer_green = (Conf[CosmeticsSection]["navi_prop_outer_green"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_prop_outer_green"]) : Settings.cosmetic.navi_prop_outer_green; - CVar_SetS32(const_cast("gNavi_Prop_Outer_Green"), Settings.cosmetic.navi_prop_outer_green); + CVar_SetS32("gNavi_Prop_Outer_Green", Settings.cosmetic.navi_prop_outer_green); Settings.cosmetic.navi_prop_outer_blue = (Conf[CosmeticsSection]["navi_prop_outer_blue"] != "") ? Ship::stoi(Conf[CosmeticsSection]["navi_prop_outer_blue"]) : Settings.cosmetic.navi_prop_outer_blue; - CVar_SetS32(const_cast("gNavi_Prop_Outer_Blue"), Settings.cosmetic.navi_prop_outer_blue); + CVar_SetS32("gNavi_Prop_Outer_Blue", Settings.cosmetic.navi_prop_outer_blue); @@ -238,9 +237,28 @@ namespace Game { Settings.cheats.freeze_time = stob(Conf[CheatSection]["freeze_time"]); CVar_SetS32("gFreezeTime", Settings.cheats.freeze_time); + // Per-Controller + LoadPadSettings(); + UpdateAudio(); } + void LoadPadSettings() { + const std::shared_ptr pConf = GlobalCtx2::GetInstance()->GetConfig(); + ConfigFile& Conf = *pConf; + + for (const auto& [i, controllers] : Ship::Window::Controllers) { + for (const auto& controller : controllers) { + if (auto padConfSection = controller->GetPadConfSection()) { + Settings.controller.extra[i].gyro_sensitivity = Ship::stof(Conf[*padConfSection]["gyro_sensitivity"]); + Settings.controller.extra[i].rumble_strength = Ship::stof(Conf[*padConfSection]["rumble_strength"]); + Settings.controller.extra[i].gyro_drift_x = Ship::stof(Conf[*padConfSection]["gyro_drift_x"], 0.0f); + Settings.controller.extra[i].gyro_drift_y = Ship::stof(Conf[*padConfSection]["gyro_drift_y"], 0.0f); + } + } + } + } + void SaveSettings() { const std::shared_ptr pConf = GlobalCtx2::GetInstance()->GetConfig(); ConfigFile& Conf = *pConf; @@ -272,8 +290,7 @@ namespace Game { // Controllers - Conf[ControllerSection]["gyro_sensitivity"] = std::to_string(Settings.controller.gyro_sensitivity); - Conf[ControllerSection]["rumble_strength"] = std::to_string(Settings.controller.rumble_strength); + Conf[ControllerSection]["rumble_enabled"] = std::to_string(Settings.controller.rumble_enabled); Conf[ControllerSection]["input_scale"] = std::to_string(Settings.controller.input_scale); Conf[ControllerSection]["input_enabled"] = std::to_string(Settings.controller.input_enabled); Conf[ControllerSection]["dpad_pause_name"] = std::to_string(Settings.controller.dpad_pause_name); @@ -333,6 +350,17 @@ namespace Game { Conf[CheatSection]["moon_jump_on_l"] = std::to_string(Settings.cheats.moon_jump_on_l); Conf[CheatSection]["super_tunic"] = std::to_string(Settings.cheats.super_tunic); + // Per-Controller + for (const auto& [i, controllers] : Ship::Window::Controllers) { + for (const auto& controller : controllers) { + if (auto padConfSection = controller->GetPadConfSection()) { + Conf[*padConfSection]["gyro_sensitivity"] = std::to_string(Settings.controller.extra[i].gyro_sensitivity); + Conf[*padConfSection]["rumble_strength"] = std::to_string(Settings.controller.extra[i].rumble_strength); + Conf[*padConfSection]["gyro_drift_x"] = std::to_string(Settings.controller.extra[i].gyro_drift_x); + Conf[*padConfSection]["gyro_drift_y"] = std::to_string(Settings.controller.extra[i].gyro_drift_y); + } + } + } Conf.Save(); } diff --git a/libultraship/libultraship/GameSettings.h b/libultraship/libultraship/GameSettings.h index 4f4eecb97..2feea8dcb 100644 --- a/libultraship/libultraship/GameSettings.h +++ b/libultraship/libultraship/GameSettings.h @@ -34,11 +34,14 @@ struct SoHConfigType { // Controller struct { - float gyro_sensitivity = 1.0f; - float rumble_strength = 1.0f; + struct { + float gyro_sensitivity = 1.0f; + float rumble_strength = 1.0f; + float gyro_drift_x = 0.0f; + float gyro_drift_y = 0.0f; + } extra[4]; + bool rumble_enabled = true; float input_scale = 1.0f; - float gyroDriftX = 0.0f; - float gyroDriftY = 0.0f; bool input_enabled = false; bool dpad_pause_name = false; bool dpad_ocarina_text = false; @@ -128,6 +131,7 @@ namespace Game { extern SoHConfigType Settings; void InitSettings(); void LoadSettings(); + void LoadPadSettings(); void SaveSettings(); void SetSeqPlayerVolume(SeqPlayers playerId, float volume); } diff --git a/libultraship/libultraship/KeyboardController.cpp b/libultraship/libultraship/KeyboardController.cpp index 6f78a1678..13014c6a7 100644 --- a/libultraship/libultraship/KeyboardController.cpp +++ b/libultraship/libultraship/KeyboardController.cpp @@ -53,4 +53,4 @@ namespace Ship { std::string KeyboardController::GetBindingConfSection() { return GetControllerType() + " CONTROLLER BINDING " + std::to_string(GetControllerNumber() + 1); } -} \ No newline at end of file +} diff --git a/libultraship/libultraship/KeyboardController.h b/libultraship/libultraship/KeyboardController.h index ab0f98e64..f6c109ca7 100644 --- a/libultraship/libultraship/KeyboardController.h +++ b/libultraship/libultraship/KeyboardController.h @@ -10,11 +10,16 @@ namespace Ship { void ReadFromSource(); void WriteToSource(ControllerCallback* controller); + bool Connected() const { return true; } + bool CanRumble() const { return false; } bool PressButton(int32_t dwScancode); bool ReleaseButton(int32_t dwScancode); void ReleaseAllButtons(); + bool HasPadConf() const { return false; } + std::optional GetPadConfSection() { return {}; } + protected: std::string GetControllerType(); std::string GetConfSection(); diff --git a/libultraship/libultraship/SDLController.cpp b/libultraship/libultraship/SDLController.cpp index 47fb57441..267607048 100644 --- a/libultraship/libultraship/SDLController.cpp +++ b/libultraship/libultraship/SDLController.cpp @@ -74,15 +74,21 @@ namespace Ship { Cont = NewCont; std::string BindingConfSection = GetBindingConfSection(); - std::shared_ptr pBindingConf = GlobalCtx2::GetInstance()->GetConfig(); - ConfigFile& BindingConf = *pBindingConf.get(); + std::string PadConfSection = *GetPadConfSection(); + std::shared_ptr config = GlobalCtx2::GetInstance()->GetConfig(); - if (!BindingConf.has(BindingConfSection)) { + if (!config->has(BindingConfSection)) { CreateDefaultBinding(); } + if (!config->has(PadConfSection)) { + CreateDefaultPadConf(); + } + LoadBinding(); LoadAxisThresholds(); + // Update per-controller settings in ImGui menu after opening controller. + Game::LoadPadSettings(); break; } @@ -93,6 +99,9 @@ namespace Ship { } bool SDLController::Close() { + if (SDL_GameControllerHasRumble(Cont)) { + SDL_GameControllerRumble(Cont, 0, 0, 0); + } if (Cont != nullptr) { SDL_GameControllerClose(Cont); } @@ -178,37 +187,41 @@ namespace Ship { if (SDL_GameControllerHasSensor(Cont, SDL_SENSOR_GYRO)) { + size_t contNumber = GetControllerNumber(); + float& gyro_drift_x = Game::Settings.controller.extra[contNumber].gyro_drift_x; + float& gyro_drift_y = Game::Settings.controller.extra[contNumber].gyro_drift_y; + const float gyro_sensitivity = Game::Settings.controller.extra[contNumber].gyro_sensitivity; + float gyroData[3]; SDL_GameControllerGetSensorData(Cont, SDL_SENSOR_GYRO, gyroData, 3); const char* contName = SDL_GameControllerName(Cont); const int isSpecialController = !strcmp("PS5 Controller", contName); - const float gyroSensitivity = Game::Settings.controller.gyro_sensitivity; - if (Game::Settings.controller.gyroDriftX == 0) { - Game::Settings.controller.gyroDriftX = gyroData[0]; + if (gyro_drift_x == 0) { + gyro_drift_x = gyroData[0]; } - if (Game::Settings.controller.gyroDriftY == 0) { + if (gyro_drift_y == 0) { if (isSpecialController == 1) { - Game::Settings.controller.gyroDriftY = gyroData[2]; + gyro_drift_y = gyroData[2]; } else { - Game::Settings.controller.gyroDriftY = gyroData[1]; + gyro_drift_y = gyroData[1]; } } if (isSpecialController == 1) { - wGyroX = gyroData[0] - Game::Settings.controller.gyroDriftX; - wGyroY = -gyroData[2] - Game::Settings.controller.gyroDriftY; + wGyroX = gyroData[0] - gyro_drift_x; + wGyroY = -gyroData[2] - gyro_drift_y; } else { - wGyroX = gyroData[0] - Game::Settings.controller.gyroDriftX; - wGyroY = gyroData[1] - Game::Settings.controller.gyroDriftY; + wGyroX = gyroData[0] - gyro_drift_x; + wGyroY = gyroData[1] - gyro_drift_y; } - wGyroX *= gyroSensitivity; - wGyroY *= gyroSensitivity; + wGyroX *= gyro_sensitivity; + wGyroY *= gyro_sensitivity; } for (int32_t i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) { @@ -331,7 +344,10 @@ namespace Ship { { if (SDL_GameControllerHasRumble(Cont)) { if (controller->rumble > 0) { - SDL_GameControllerRumble(Cont, 0xFFFF * Game::Settings.controller.rumble_strength, 0xFFFF * Game::Settings.controller.rumble_strength, 1); + float rumble_strength = Game::Settings.controller.extra[GetControllerNumber()].rumble_strength; + SDL_GameControllerRumble(Cont, 0xFFFF * rumble_strength, 0xFFFF * rumble_strength, 0); + } else { + SDL_GameControllerRumble(Cont, 0, 0, 0); } } @@ -391,6 +407,19 @@ namespace Ship { Conf.Save(); } + void SDLController::CreateDefaultPadConf() { + std::string ConfSection = *GetPadConfSection(); + std::shared_ptr pConf = GlobalCtx2::GetInstance()->GetConfig(); + ConfigFile& Conf = *pConf.get(); + + Conf[ConfSection]["gyro_sensitivity"] = std::to_string(1.0f); + Conf[ConfSection]["rumble_strength"] = std::to_string(1.0f); + Conf[ConfSection]["gyro_drift_x"] = std::to_string(0.0f); + Conf[ConfSection]["gyro_drift_y"] = std::to_string(0.0f); + + Conf.Save(); + } + void SDLController::SetButtonMapping(const std::string& szButtonName, int32_t dwScancode) { if (guid.compare(INVALID_SDL_CONTROLLER_GUID)) { return; @@ -410,4 +439,8 @@ namespace Ship { std::string SDLController::GetBindingConfSection() { return GetControllerType() + " CONTROLLER BINDING " + guid; } + + std::optional SDLController::GetPadConfSection() { + return GetControllerType() + " CONTROLLER PAD " + guid; + } } diff --git a/libultraship/libultraship/SDLController.h b/libultraship/libultraship/SDLController.h index 5c71c50a9..138466a89 100644 --- a/libultraship/libultraship/SDLController.h +++ b/libultraship/libultraship/SDLController.h @@ -12,15 +12,21 @@ namespace Ship { void ReadFromSource(); void WriteToSource(ControllerCallback* controller); + bool Connected() const { return Cont != nullptr; } + bool CanRumble() const { return SDL_GameControllerHasRumble(Cont); } std::string GetGuid() { return guid; }; + bool HasPadConf() const { return true; } + std::optional GetPadConfSection(); + protected: std::string GetControllerType(); void SetButtonMapping(const std::string& szButtonName, int32_t dwScancode); std::string GetConfSection(); std::string GetBindingConfSection(); void CreateDefaultBinding(); + void CreateDefaultPadConf(); static bool IsGuidInUse(const std::string& guid); private: diff --git a/libultraship/libultraship/SohImGuiImpl.cpp b/libultraship/libultraship/SohImGuiImpl.cpp index 96211fe20..5111a0d6d 100644 --- a/libultraship/libultraship/SohImGuiImpl.cpp +++ b/libultraship/libultraship/SohImGuiImpl.cpp @@ -3,6 +3,9 @@ #include #include #include +#include +#include +#include #include "Archive.h" #include "Environment.h" @@ -81,49 +84,49 @@ namespace SohImGui { ImGui_ImplWin32_Init(impl.dx11.window); break; } - kokiri_col[0] = std::clamp((float) CVar_GetS32((char*)"gTunic_Kokiri_Red", 30)/255, 0.0f, 1.0f); - kokiri_col[1] = std::clamp((float)CVar_GetS32((char*)"gTunic_Kokiri_Green", 105) / 255, 0.0f, 1.0f); - kokiri_col[2] = std::clamp((float)CVar_GetS32((char*)"gTunic_Kokiri_Blue", 27) / 255, 0.0f, 1.0f); + kokiri_col[0] = std::clamp((float) CVar_GetS32("gTunic_Kokiri_Red", 30)/255, 0.0f, 1.0f); + kokiri_col[1] = std::clamp((float)CVar_GetS32("gTunic_Kokiri_Green", 105) / 255, 0.0f, 1.0f); + kokiri_col[2] = std::clamp((float)CVar_GetS32("gTunic_Kokiri_Blue", 27) / 255, 0.0f, 1.0f); - goron_col[0] = std::clamp((float)CVar_GetS32((char*)"gTunic_Goron_Red", 100) / 255, 0.0f, 1.0f); - goron_col[1] = std::clamp((float)CVar_GetS32((char*)"gTunic_Goron_Green", 20) / 255, 0.0f, 1.0f); - goron_col[2] = std::clamp((float)CVar_GetS32((char*)"gTunic_Goron_Blue", 0) / 255, 0.0f, 1.0f); + goron_col[0] = std::clamp((float)CVar_GetS32("gTunic_Goron_Red", 100) / 255, 0.0f, 1.0f); + goron_col[1] = std::clamp((float)CVar_GetS32("gTunic_Goron_Green", 20) / 255, 0.0f, 1.0f); + goron_col[2] = std::clamp((float)CVar_GetS32("gTunic_Goron_Blue", 0) / 255, 0.0f, 1.0f); - zora_col[0] = std::clamp((float)CVar_GetS32((char*)"gTunic_Zora_Red", 0) / 255, 0.0f, 1.0f); - zora_col[1] = std::clamp((float)CVar_GetS32((char*)"gTunic_Zora_Green", 60) / 255, 0.0f, 1.0f); - zora_col[2] = std::clamp((float)CVar_GetS32((char*)"gTunic_Zora_Blue", 100) / 255, 0.0f, 1.0f); + zora_col[0] = std::clamp((float)CVar_GetS32("gTunic_Zora_Red", 0) / 255, 0.0f, 1.0f); + zora_col[1] = std::clamp((float)CVar_GetS32("gTunic_Zora_Green", 60) / 255, 0.0f, 1.0f); + zora_col[2] = std::clamp((float)CVar_GetS32("gTunic_Zora_Blue", 100) / 255, 0.0f, 1.0f); - navi_idle_i_col[0] = std::clamp((float)CVar_GetS32((char*)"gNavi_Idle_Inner_Red", 0) / 255, 0.0f, 1.0f); - navi_idle_i_col[1] = std::clamp((float)CVar_GetS32((char*)"gNavi_Idle_Inner_Green", 0) / 255, 0.0f, 1.0f); - navi_idle_i_col[2] = std::clamp((float)CVar_GetS32((char*)"gNavi_Idle_Inner_Blue", 0) / 255, 0.0f, 1.0f); + navi_idle_i_col[0] = std::clamp((float)CVar_GetS32("gNavi_Idle_Inner_Red", 0) / 255, 0.0f, 1.0f); + navi_idle_i_col[1] = std::clamp((float)CVar_GetS32("gNavi_Idle_Inner_Green", 0) / 255, 0.0f, 1.0f); + navi_idle_i_col[2] = std::clamp((float)CVar_GetS32("gNavi_Idle_Inner_Blue", 0) / 255, 0.0f, 1.0f); - navi_idle_o_col[0] = std::clamp((float)CVar_GetS32((char*)"gNavi_Idle_Outer_Red", 0) / 255, 0.0f, 1.0f); - navi_idle_o_col[1] = std::clamp((float)CVar_GetS32((char*)"gNavi_Idle_Outer_Green", 0) / 255, 0.0f, 1.0f); - navi_idle_o_col[2] = std::clamp((float)CVar_GetS32((char*)"gNavi_Idle_Outer_Blue", 0) / 255, 0.0f, 1.0f); + navi_idle_o_col[0] = std::clamp((float)CVar_GetS32("gNavi_Idle_Outer_Red", 0) / 255, 0.0f, 1.0f); + navi_idle_o_col[1] = std::clamp((float)CVar_GetS32("gNavi_Idle_Outer_Green", 0) / 255, 0.0f, 1.0f); + navi_idle_o_col[2] = std::clamp((float)CVar_GetS32("gNavi_Idle_Outer_Blue", 0) / 255, 0.0f, 1.0f); - navi_npc_i_col[0] = std::clamp((float)CVar_GetS32((char*)"gNavi_NPC_Inner_Red", 0) / 255, 0.0f, 1.0f); - navi_npc_i_col[1] = std::clamp((float)CVar_GetS32((char*)"gNavi_NPC_Inner_Green", 0) / 255, 0.0f, 1.0f); - navi_npc_i_col[2] = std::clamp((float)CVar_GetS32((char*)"gNavi_NPC_Inner_Blue", 0) / 255, 0.0f, 1.0f); + navi_npc_i_col[0] = std::clamp((float)CVar_GetS32("gNavi_NPC_Inner_Red", 0) / 255, 0.0f, 1.0f); + navi_npc_i_col[1] = std::clamp((float)CVar_GetS32("gNavi_NPC_Inner_Green", 0) / 255, 0.0f, 1.0f); + navi_npc_i_col[2] = std::clamp((float)CVar_GetS32("gNavi_NPC_Inner_Blue", 0) / 255, 0.0f, 1.0f); - navi_npc_o_col[0] = std::clamp((float)CVar_GetS32((char*)"gNavi_NPC_Outer_Red", 0) / 255, 0.0f, 1.0f); - navi_npc_o_col[1] = std::clamp((float)CVar_GetS32((char*)"gNavi_NPC_Outer_Green", 0) / 255, 0.0f, 1.0f); - navi_npc_o_col[2] = std::clamp((float)CVar_GetS32((char*)"gNavi_NPC_Outer_Blue", 0) / 255, 0.0f, 1.0f); + navi_npc_o_col[0] = std::clamp((float)CVar_GetS32("gNavi_NPC_Outer_Red", 0) / 255, 0.0f, 1.0f); + navi_npc_o_col[1] = std::clamp((float)CVar_GetS32("gNavi_NPC_Outer_Green", 0) / 255, 0.0f, 1.0f); + navi_npc_o_col[2] = std::clamp((float)CVar_GetS32("gNavi_NPC_Outer_Blue", 0) / 255, 0.0f, 1.0f); - navi_enemy_i_col[0] = std::clamp((float)CVar_GetS32((char*)"gNavi_Enemy_Inner_Red", 0) / 255, 0.0f, 1.0f); - navi_enemy_i_col[1] = std::clamp((float)CVar_GetS32((char*)"gNavi_Enemy_Inner_Green", 0) / 255, 0.0f, 1.0f); - navi_enemy_i_col[2] = std::clamp((float)CVar_GetS32((char*)"gNavi_Enemy_Inner_Blue", 0) / 255, 0.0f, 1.0f); + navi_enemy_i_col[0] = std::clamp((float)CVar_GetS32("gNavi_Enemy_Inner_Red", 0) / 255, 0.0f, 1.0f); + navi_enemy_i_col[1] = std::clamp((float)CVar_GetS32("gNavi_Enemy_Inner_Green", 0) / 255, 0.0f, 1.0f); + navi_enemy_i_col[2] = std::clamp((float)CVar_GetS32("gNavi_Enemy_Inner_Blue", 0) / 255, 0.0f, 1.0f); - navi_enemy_o_col[0] = std::clamp((float)CVar_GetS32((char*)"gNavi_Enemy_Outer_Red", 0) / 255, 0.0f, 1.0f); - navi_enemy_o_col[1] = std::clamp((float)CVar_GetS32((char*)"gNavi_Enemy_Outer_Green", 0) / 255, 0.0f, 1.0f); - navi_enemy_o_col[2] = std::clamp((float)CVar_GetS32((char*)"gNavi_Enemy_Outer_Blue", 0) / 255, 0.0f, 1.0f); + navi_enemy_o_col[0] = std::clamp((float)CVar_GetS32("gNavi_Enemy_Outer_Red", 0) / 255, 0.0f, 1.0f); + navi_enemy_o_col[1] = std::clamp((float)CVar_GetS32("gNavi_Enemy_Outer_Green", 0) / 255, 0.0f, 1.0f); + navi_enemy_o_col[2] = std::clamp((float)CVar_GetS32("gNavi_Enemy_Outer_Blue", 0) / 255, 0.0f, 1.0f); - navi_prop_i_col[0] = std::clamp((float)CVar_GetS32((char*)"gNavi_Prop_Inner_Red", 0) / 255, 0.0f, 1.0f); - navi_prop_i_col[1] = std::clamp((float)CVar_GetS32((char*)"gNavi_Prop_Inner_Green", 0) / 255, 0.0f, 1.0f); - navi_prop_i_col[2] = std::clamp((float)CVar_GetS32((char*)"gNavi_Prop_Inner_Blue", 0) / 255, 0.0f, 1.0f); + navi_prop_i_col[0] = std::clamp((float)CVar_GetS32("gNavi_Prop_Inner_Red", 0) / 255, 0.0f, 1.0f); + navi_prop_i_col[1] = std::clamp((float)CVar_GetS32("gNavi_Prop_Inner_Green", 0) / 255, 0.0f, 1.0f); + navi_prop_i_col[2] = std::clamp((float)CVar_GetS32("gNavi_Prop_Inner_Blue", 0) / 255, 0.0f, 1.0f); - navi_prop_o_col[0] = std::clamp((float)CVar_GetS32((char*)"gNavi_Prop_Outer_Red", 0) / 255, 0.0f, 1.0f); - navi_prop_o_col[1] = std::clamp((float)CVar_GetS32((char*)"gNavi_Prop_Outer_Green", 0) / 255, 0.0f, 1.0f); - navi_prop_o_col[2] = std::clamp((float)CVar_GetS32((char*)"gNavi_Prop_Outer_Blue", 0) / 255, 0.0f, 1.0f); + navi_prop_o_col[0] = std::clamp((float)CVar_GetS32("gNavi_Prop_Outer_Red", 0) / 255, 0.0f, 1.0f); + navi_prop_o_col[1] = std::clamp((float)CVar_GetS32("gNavi_Prop_Outer_Green", 0) / 255, 0.0f, 1.0f); + navi_prop_o_col[2] = std::clamp((float)CVar_GetS32("gNavi_Prop_Outer_Blue", 0) / 255, 0.0f, 1.0f); } void ImGuiBackendInit() { @@ -402,20 +405,41 @@ namespace SohImGui { } if (ImGui::BeginMenu("Controller")) { - ImGui::Text("Gyro Sensitivity: %d %%", static_cast(100 * Game::Settings.controller.gyro_sensitivity)); - if (ImGui::SliderFloat("##GYROSCOPE", &Game::Settings.controller.gyro_sensitivity, 0.0f, 1.0f, "")) { - needs_save = true; - } + for (const auto& [i, controllers] : Ship::Window::Controllers) { + bool hasPad = std::find_if(controllers.begin(), controllers.end(), [](const auto& c) { + return c->HasPadConf() && c->Connected(); + }) != controllers.end(); - if (ImGui::Button("Recalibrate Gyro")) { - Game::Settings.controller.gyroDriftX = 0; - Game::Settings.controller.gyroDriftY = 0; + if (!hasPad) continue; + + auto menuLabel = "Controller " + std::to_string(i + 1); + if (ImGui::BeginMenu(menuLabel.c_str())) { + ImGui::Text("Gyro Sensitivity: %d %%", static_cast(100 * Game::Settings.controller.extra[i].gyro_sensitivity)); + if (ImGui::SliderFloat("##GYROSCOPE", &Game::Settings.controller.extra[i].gyro_sensitivity, 0.0f, 1.0f, "")) { + needs_save = true; + } + + if (ImGui::Button("Recalibrate Gyro")) { + Game::Settings.controller.extra[i].gyro_drift_x = 0; + Game::Settings.controller.extra[i].gyro_drift_y = 0; + needs_save = true; + } + + ImGui::Separator(); + + ImGui::Text("Rumble Strength: %d %%", static_cast(100 * Game::Settings.controller.extra[i].rumble_strength)); + if (ImGui::SliderFloat("##RUMBLE", &Game::Settings.controller.extra[i].rumble_strength, 0.0f, 1.0f, "")) { + needs_save = true; + } + + ImGui::EndMenu(); + } } ImGui::Separator(); - ImGui::Text("Rumble Strength: %d %%", static_cast(100 * Game::Settings.controller.rumble_strength)); - if (ImGui::SliderFloat("##RUMBLE", &Game::Settings.controller.rumble_strength, 0.0f, 1.0f, "")) { + if (ImGui::Checkbox("Rumble Enabled", &Game::Settings.controller.rumble_enabled)) { + CVar_SetS32("gRumbleEnabled", Game::Settings.controller.rumble_enabled); needs_save = true; } @@ -505,7 +529,7 @@ namespace SohImGui { } if (ImGui::Checkbox("Dynamic Wallet Icon", &Game::Settings.enhancements.dynamic_wallet_icon)) { - CVar_SetS32(const_cast("gDynamicWalletIcon"), Game::Settings.enhancements.dynamic_wallet_icon); + CVar_SetS32("gDynamicWalletIcon", Game::Settings.enhancements.dynamic_wallet_icon); needs_save = true; } @@ -587,30 +611,30 @@ namespace SohImGui { ImGui::Text("Tunics"); ImGui::Separator(); if (ImGui::ColorEdit3("Kokiri Tunic", kokiri_col)) { - Game::Settings.cosmetic.tunic_kokiri_red = (int) (kokiri_col[0] * 255); - Game::Settings.cosmetic.tunic_kokiri_green = (int) (kokiri_col[1] * 255); - Game::Settings.cosmetic.tunic_kokiri_blue = (int) (kokiri_col[2] * 255); - CVar_SetS32(const_cast("gTunic_Kokiri_Red"), Game::Settings.cosmetic.tunic_kokiri_red); - CVar_SetS32(const_cast("gTunic_Kokiri_Green"), Game::Settings.cosmetic.tunic_kokiri_green); - CVar_SetS32(const_cast("gTunic_Kokiri_Blue"), Game::Settings.cosmetic.tunic_kokiri_blue); + Game::Settings.cosmetic.tunic_kokiri_red = (int)(kokiri_col[0] * 255); + Game::Settings.cosmetic.tunic_kokiri_green = (int)(kokiri_col[1] * 255); + Game::Settings.cosmetic.tunic_kokiri_blue = (int)(kokiri_col[2] * 255); + CVar_SetS32("gTunic_Kokiri_Red", Game::Settings.cosmetic.tunic_kokiri_red); + CVar_SetS32("gTunic_Kokiri_Green", Game::Settings.cosmetic.tunic_kokiri_green); + CVar_SetS32("gTunic_Kokiri_Blue", Game::Settings.cosmetic.tunic_kokiri_blue); needs_save = true; } if (ImGui::ColorEdit3("Goron Tunic", goron_col)) { Game::Settings.cosmetic.tunic_goron_red = (int)(goron_col[0] * 255); Game::Settings.cosmetic.tunic_goron_green = (int)(goron_col[1] * 255); Game::Settings.cosmetic.tunic_goron_blue = (int)(goron_col[2] * 255); - CVar_SetS32(const_cast("gTunic_Goron_Red"), Game::Settings.cosmetic.tunic_goron_red); - CVar_SetS32(const_cast("gTunic_Goron_Green"), Game::Settings.cosmetic.tunic_goron_green); - CVar_SetS32(const_cast("gTunic_Goron_Blue"), Game::Settings.cosmetic.tunic_goron_blue); + CVar_SetS32("gTunic_Goron_Red", Game::Settings.cosmetic.tunic_goron_red); + CVar_SetS32("gTunic_Goron_Green", Game::Settings.cosmetic.tunic_goron_green); + CVar_SetS32("gTunic_Goron_Blue", Game::Settings.cosmetic.tunic_goron_blue); needs_save = true; } if (ImGui::ColorEdit3("Zora Tunic", zora_col)) { Game::Settings.cosmetic.tunic_zora_red = (int)(zora_col[0] * 255); Game::Settings.cosmetic.tunic_zora_green = (int)(zora_col[1] * 255); Game::Settings.cosmetic.tunic_zora_blue = (int)(zora_col[2] * 255); - CVar_SetS32(const_cast("gTunic_Zora_Red"), Game::Settings.cosmetic.tunic_zora_red); - CVar_SetS32(const_cast("gTunic_Zora_Green"), Game::Settings.cosmetic.tunic_zora_green); - CVar_SetS32(const_cast("gTunic_Zora_Blue"), Game::Settings.cosmetic.tunic_zora_blue); + CVar_SetS32("gTunic_Zora_Red", Game::Settings.cosmetic.tunic_zora_red); + CVar_SetS32("gTunic_Zora_Green", Game::Settings.cosmetic.tunic_zora_green); + CVar_SetS32("gTunic_Zora_Blue", Game::Settings.cosmetic.tunic_zora_blue); needs_save = true; } ImGui::Text("Navi"); @@ -619,9 +643,9 @@ namespace SohImGui { Game::Settings.cosmetic.navi_idle_inner_red = (int)(navi_idle_i_col[0] * 255); Game::Settings.cosmetic.navi_idle_inner_green = (int)(navi_idle_i_col[1] * 255); Game::Settings.cosmetic.navi_idle_inner_blue = (int)(navi_idle_i_col[2] * 255); - CVar_SetS32(const_cast("gNavi_Idle_Inner_Red"), Game::Settings.cosmetic.navi_idle_inner_red); - CVar_SetS32(const_cast("gNavi_Idle_Inner_Green"), Game::Settings.cosmetic.navi_idle_inner_green); - CVar_SetS32(const_cast("gNavi_Idle_Inner_Blue"), Game::Settings.cosmetic.navi_idle_inner_blue); + CVar_SetS32("gNavi_Idle_Inner_Red", Game::Settings.cosmetic.navi_idle_inner_red); + CVar_SetS32("gNavi_Idle_Inner_Green", Game::Settings.cosmetic.navi_idle_inner_green); + CVar_SetS32("gNavi_Idle_Inner_Blue", Game::Settings.cosmetic.navi_idle_inner_blue); needs_save = true; } @@ -629,9 +653,9 @@ namespace SohImGui { Game::Settings.cosmetic.navi_idle_outer_red = (int)(navi_idle_o_col[0] * 255); Game::Settings.cosmetic.navi_idle_outer_green = (int)(navi_idle_o_col[1] * 255); Game::Settings.cosmetic.navi_idle_outer_blue = (int)(navi_idle_o_col[2] * 255); - CVar_SetS32(const_cast("gNavi_Idle_Outer_Red"), Game::Settings.cosmetic.navi_idle_outer_red); - CVar_SetS32(const_cast("gNavi_Idle_Outer_Green"), Game::Settings.cosmetic.navi_idle_outer_green); - CVar_SetS32(const_cast("gNavi_Idle_Outer_Blue"), Game::Settings.cosmetic.navi_idle_outer_blue); + CVar_SetS32("gNavi_Idle_Outer_Red", Game::Settings.cosmetic.navi_idle_outer_red); + CVar_SetS32("gNavi_Idle_Outer_Green", Game::Settings.cosmetic.navi_idle_outer_green); + CVar_SetS32("gNavi_Idle_Outer_Blue", Game::Settings.cosmetic.navi_idle_outer_blue); needs_save = true; } @@ -639,9 +663,9 @@ namespace SohImGui { Game::Settings.cosmetic.navi_npc_inner_red = (int)(navi_npc_i_col[0] * 255); Game::Settings.cosmetic.navi_npc_inner_green = (int)(navi_npc_i_col[1] * 255); Game::Settings.cosmetic.navi_npc_inner_blue = (int)(navi_npc_i_col[2] * 255); - CVar_SetS32(const_cast("gNavi_NPC_Inner_Red"), Game::Settings.cosmetic.navi_npc_inner_red); - CVar_SetS32(const_cast("gNavi_NPC_Inner_Green"), Game::Settings.cosmetic.navi_npc_inner_green); - CVar_SetS32(const_cast("gNavi_NPC_Inner_Blue"), Game::Settings.cosmetic.navi_npc_inner_blue); + CVar_SetS32("gNavi_NPC_Inner_Red", Game::Settings.cosmetic.navi_npc_inner_red); + CVar_SetS32("gNavi_NPC_Inner_Green", Game::Settings.cosmetic.navi_npc_inner_green); + CVar_SetS32("gNavi_NPC_Inner_Blue", Game::Settings.cosmetic.navi_npc_inner_blue); needs_save = true; } @@ -649,9 +673,9 @@ namespace SohImGui { Game::Settings.cosmetic.navi_npc_outer_red = (int)(navi_npc_o_col[0] * 255); Game::Settings.cosmetic.navi_npc_outer_green = (int)(navi_npc_o_col[1] * 255); Game::Settings.cosmetic.navi_npc_outer_blue = (int)(navi_npc_o_col[2] * 255); - CVar_SetS32(const_cast("gNavi_NPC_Outer_Red"), Game::Settings.cosmetic.navi_npc_outer_red); - CVar_SetS32(const_cast("gNavi_NPC_Outer_Green"), Game::Settings.cosmetic.navi_npc_outer_green); - CVar_SetS32(const_cast("gNavi_NPC_Outer_Blue"), Game::Settings.cosmetic.navi_npc_outer_blue); + CVar_SetS32("gNavi_NPC_Outer_Red", Game::Settings.cosmetic.navi_npc_outer_red); + CVar_SetS32("gNavi_NPC_Outer_Green", Game::Settings.cosmetic.navi_npc_outer_green); + CVar_SetS32("gNavi_NPC_Outer_Blue", Game::Settings.cosmetic.navi_npc_outer_blue); needs_save = true; } @@ -659,9 +683,9 @@ namespace SohImGui { Game::Settings.cosmetic.navi_enemy_inner_red = (int)(navi_enemy_i_col[0] * 255); Game::Settings.cosmetic.navi_enemy_inner_green = (int)(navi_enemy_i_col[1] * 255); Game::Settings.cosmetic.navi_enemy_inner_blue = (int)(navi_enemy_i_col[2] * 255); - CVar_SetS32(const_cast("gNavi_Enemy_Inner_Red"), Game::Settings.cosmetic.navi_enemy_inner_red); - CVar_SetS32(const_cast("gNavi_Enemy_Inner_Green"), Game::Settings.cosmetic.navi_enemy_inner_green); - CVar_SetS32(const_cast("gNavi_Enemy_Inner_Blue"), Game::Settings.cosmetic.navi_enemy_inner_blue); + CVar_SetS32("gNavi_Enemy_Inner_Red", Game::Settings.cosmetic.navi_enemy_inner_red); + CVar_SetS32("gNavi_Enemy_Inner_Green", Game::Settings.cosmetic.navi_enemy_inner_green); + CVar_SetS32("gNavi_Enemy_Inner_Blue", Game::Settings.cosmetic.navi_enemy_inner_blue); needs_save = true; } @@ -669,9 +693,9 @@ namespace SohImGui { Game::Settings.cosmetic.navi_enemy_outer_red = (int)(navi_enemy_o_col[0] * 255); Game::Settings.cosmetic.navi_enemy_outer_green = (int)(navi_enemy_o_col[1] * 255); Game::Settings.cosmetic.navi_enemy_outer_blue = (int)(navi_enemy_o_col[2] * 255); - CVar_SetS32(const_cast("gNavi_Enemy_Outer_Red"), Game::Settings.cosmetic.navi_enemy_outer_red); - CVar_SetS32(const_cast("gNavi_Enemy_Outer_Green"), Game::Settings.cosmetic.navi_enemy_outer_green); - CVar_SetS32(const_cast("gNavi_Enemy_Outer_Blue"), Game::Settings.cosmetic.navi_enemy_outer_blue); + CVar_SetS32("gNavi_Enemy_Outer_Red", Game::Settings.cosmetic.navi_enemy_outer_red); + CVar_SetS32("gNavi_Enemy_Outer_Green", Game::Settings.cosmetic.navi_enemy_outer_green); + CVar_SetS32("gNavi_Enemy_Outer_Blue", Game::Settings.cosmetic.navi_enemy_outer_blue); needs_save = true; } @@ -679,9 +703,9 @@ namespace SohImGui { Game::Settings.cosmetic.navi_prop_inner_red = (int)(navi_prop_i_col[0] * 255); Game::Settings.cosmetic.navi_prop_inner_green = (int)(navi_prop_i_col[1] * 255); Game::Settings.cosmetic.navi_prop_inner_blue = (int)(navi_prop_i_col[2] * 255); - CVar_SetS32(const_cast("gNavi_Prop_Inner_Red"), Game::Settings.cosmetic.navi_prop_inner_red); - CVar_SetS32(const_cast("gNavi_Prop_Inner_Green"), Game::Settings.cosmetic.navi_prop_inner_green); - CVar_SetS32(const_cast("gNavi_Prop_Inner_Blue"), Game::Settings.cosmetic.navi_prop_inner_blue); + CVar_SetS32("gNavi_Prop_Inner_Red", Game::Settings.cosmetic.navi_prop_inner_red); + CVar_SetS32("gNavi_Prop_Inner_Green", Game::Settings.cosmetic.navi_prop_inner_green); + CVar_SetS32("gNavi_Prop_Inner_Blue", Game::Settings.cosmetic.navi_prop_inner_blue); needs_save = true; } @@ -689,9 +713,9 @@ namespace SohImGui { Game::Settings.cosmetic.navi_prop_outer_red = (int)(navi_prop_o_col[0] * 255); Game::Settings.cosmetic.navi_prop_outer_green = (int)(navi_prop_o_col[1] * 255); Game::Settings.cosmetic.navi_prop_outer_blue = (int)(navi_prop_o_col[2] * 255); - CVar_SetS32(const_cast("gNavi_Prop_Outer_Red"), Game::Settings.cosmetic.navi_prop_outer_red); - CVar_SetS32(const_cast("gNavi_Prop_Outer_Green"), Game::Settings.cosmetic.navi_prop_outer_green); - CVar_SetS32(const_cast("gNavi_Prop_Outer_Blue"), Game::Settings.cosmetic.navi_prop_outer_blue); + CVar_SetS32("gNavi_Prop_Outer_Red", Game::Settings.cosmetic.navi_prop_outer_red); + CVar_SetS32("gNavi_Prop_Outer_Green", Game::Settings.cosmetic.navi_prop_outer_green); + CVar_SetS32("gNavi_Prop_Outer_Blue", Game::Settings.cosmetic.navi_prop_outer_blue); needs_save = true; } diff --git a/soh/soh/Enhancements/bootcommands.c b/soh/soh/Enhancements/bootcommands.c index 60143e295..da4276f77 100644 --- a/soh/soh/Enhancements/bootcommands.c +++ b/soh/soh/Enhancements/bootcommands.c @@ -25,6 +25,7 @@ void BootCommands_Init() CVar_RegisterS32("gDebugEnabled", 0); CVar_RegisterS32("gPauseLiveLink", 0); CVar_RegisterS32("gMinimalUI", 0); + CVar_RegisterS32("gRumbleEnabled", 0); CVar_RegisterS32("gUniformLR", 1); CVar_RegisterS32("gNewDrops", 0); CVar_RegisterS32("gVisualAgony", 0); diff --git a/soh/soh/Enhancements/debugconsole.cpp b/soh/soh/Enhancements/debugconsole.cpp index 06126281f..de8cab260 100644 --- a/soh/soh/Enhancements/debugconsole.cpp +++ b/soh/soh/Enhancements/debugconsole.cpp @@ -337,11 +337,11 @@ static bool SetCVarHandler(const std::vector& args) { int vType = CheckVarType(args[2]); if (vType == VARTYPE_STRING) - CVar_SetString((char*)args[1].c_str(), (char*)args[2].c_str()); + CVar_SetString(args[1].c_str(), (char*)args[2].c_str()); else if (vType == VARTYPE_FLOAT) - CVar_SetFloat((char*)args[1].c_str(), std::stof(args[2])); + CVar_SetFloat(args[1].c_str(), std::stof(args[2])); else - CVar_SetS32((char*)args[1].c_str(), std::stoi(args[2])); + CVar_SetS32(args[1].c_str(), std::stoi(args[2])); DebugConsole_SaveCVars(); @@ -354,7 +354,7 @@ static bool GetCVarHandler(const std::vector& args) { if (args.size() < 2) return CMD_FAILED; - CVar* cvar = CVar_GetVar((char*) args[1].c_str()); + CVar* cvar = CVar_GetVar(args[1].c_str()); if (cvar != nullptr) { @@ -446,4 +446,4 @@ void DebugConsole_SaveCVars() } File::WriteAllText("cvars.cfg", output); -} \ No newline at end of file +} diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index fca6d6b7d..f125437ab 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -3,6 +3,7 @@ #include #include #include "GlobalCtx2.h" +#include "GameSettings.h" #include "ResourceMgr.h" #include "DisplayList.h" #include "PlayerAnimation.h" @@ -885,3 +886,13 @@ extern "C" void AudioPlayer_Play(const uint8_t* buf, uint32_t len) { OTRGlobals::Instance->context->GetWindow()->GetAudioPlayer()->Play(buf, len); } } + +extern "C" int Controller_ShouldRumble(size_t i) { + for (const auto& controller : Ship::Window::Controllers.at(i)) { + if (controller->CanRumble() && Game::Settings.controller.extra[i].rumble_strength > 0.001f) { + return 1; + } + } + + return 0; +} diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 20080fcb1..dfb235712 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -64,4 +64,5 @@ int AudioPlayer_Buffered(void); int AudioPlayer_GetDesiredBuffered(void); void AudioPlayer_Play(const uint8_t* buf, uint32_t len); void AudioMgr_CreateNextAudioBuffer(s16* samples, u32 num_samples); +int Controller_ShouldRumble(size_t i); #endif diff --git a/soh/soh/stubs.c b/soh/soh/stubs.c index 871d5ca22..c47c1fa5d 100644 --- a/soh/soh/stubs.c +++ b/soh/soh/stubs.c @@ -102,7 +102,7 @@ void osCreateViManager(OSPri pri) s32 osMotorInit(OSMesgQueue* ctrlrqueue, OSPfs* pfs, s32 channel) { - + return 0; } u32 osAiGetLength(void) @@ -2099,4 +2099,4 @@ u8 gSequenceFontTable[0x1C0] = { 0x01, 0x12, 0x01, 0x24, 0x01, 0x18, 0x01, 0x19, 0x01, 0x13, 0x01, 0x20, 0x01, 0x1B, 0x01, 0x1C, 0x01, 0x1D, 0x01, 0x03, 0x01, 0x1F, 0x01, 0x20, 0x01, 0x20, 0x01, 0x09, 0x01, 0x21, 0x01, 0x22, 0x01, 0x21, 0x01, 0x09, 0x01, 0x20, 0x01, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; \ No newline at end of file +}; diff --git a/soh/src/code/padmgr.c b/soh/src/code/padmgr.c index 973c2b446..08c89869f 100644 --- a/soh/src/code/padmgr.c +++ b/soh/src/code/padmgr.c @@ -269,7 +269,7 @@ void PadMgr_ProcessInputs(PadMgr* padMgr) { input->press.stick_y += (s8)(input->cur.stick_y - input->prev.stick_y); } - controllerCallback.rumble = padMgr->rumbleEnable[0] > 0 ? 1 : 0; + controllerCallback.rumble = CVar_GetS32("gRumbleEnabled", 0) && (padMgr->rumbleEnable[0] > 0); if (HealthMeter_IsCritical()) { controllerCallback.ledColor = 0; @@ -303,6 +303,11 @@ void PadMgr_HandleRetraceMsg(PadMgr* padMgr) { } osRecvMesg(queue, NULL, OS_MESG_BLOCK); osContGetReadData(padMgr->pads); + + for (i = 0; i < __osMaxControllers; i++) { + padMgr->padStatus[i].status = CVar_GetS32("gRumbleEnabled", 0) && Controller_ShouldRumble(i); + } + if (padMgr->preNMIShutdown) { memset(padMgr->pads, 0, sizeof(padMgr->pads)); }