diff --git a/example_community_patch_settings_en.toml b/example_community_patch_settings_en.toml index a889dac8..9ca49701 100644 --- a/example_community_patch_settings_en.toml +++ b/example_community_patch_settings_en.toml @@ -100,6 +100,10 @@ hotkeys_enabled = true # If you prefer to disable the extended hotkeys set this to false hotkeys_extended = true +# Require a visible target popup or Set Course control for the primary-action shortcut. +# false preserves sending commands to the last target after its popup is dismissed. +primary_requires_visible_target = false + # If you have the Kir'Shara artifact, should the queue be enabled by default? queue_enabled = true diff --git a/mods/src/config.cc b/mods/src/config.cc index 41d7fd5b..52587287 100644 --- a/mods/src/config.cc +++ b/mods/src/config.cc @@ -1033,6 +1033,8 @@ void Config::Load() get_config_or_default(config, parsed, "control", "hotkeys_enabled", DCC::hotkeys_enabled, write_config); this->hotkeys_extended = get_config_or_default(config, parsed, "control", "hotkeys_extended", DCC::hotkeys_extended, write_config); + this->primary_requires_visible_target = get_config_or_default( + config, parsed, "control", "primary_requires_visible_target", DCC::primary_requires_visible_target, write_config); this->use_scopely_hotkeys = get_config_or_default(config, parsed, "control", "use_scopely_hotkeys", DCC::use_scopely_hotkeys, write_config); this->select_timer = diff --git a/mods/src/config.h b/mods/src/config.h index 31760de2..6404ff8c 100644 --- a/mods/src/config.h +++ b/mods/src/config.h @@ -192,6 +192,7 @@ class Config final bool kirshara_fixes; bool hotkeys_enabled; bool hotkeys_extended; + bool primary_requires_visible_target; bool use_scopely_hotkeys; bool use_presets_as_default; bool enable_experimental; diff --git a/mods/src/defaultconfig.h b/mods/src/defaultconfig.h index 3ef3dff7..4edc09c5 100644 --- a/mods/src/defaultconfig.h +++ b/mods/src/defaultconfig.h @@ -26,13 +26,14 @@ namespace SystemConfig namespace Control { - constexpr bool enable_experimental = false; - constexpr bool hotkeys_enabled = true; - constexpr bool hotkeys_extended = true; - constexpr bool use_scopely_hotkeys = false; - constexpr bool queue_enabled = true; - constexpr bool kirshara_fixes = true; - constexpr auto select_timer = 500; + constexpr bool enable_experimental = false; + constexpr bool hotkeys_enabled = true; + constexpr bool hotkeys_extended = true; + constexpr bool primary_requires_visible_target = false; + constexpr bool use_scopely_hotkeys = false; + constexpr bool queue_enabled = true; + constexpr bool kirshara_fixes = true; + constexpr auto select_timer = 500; } // namespace Control namespace Graphics diff --git a/mods/src/patches/parts/hotkeys.cc b/mods/src/patches/parts/hotkeys.cc index 4436cd29..c9392f5b 100644 --- a/mods/src/patches/parts/hotkeys.cc +++ b/mods/src/patches/parts/hotkeys.cc @@ -1162,8 +1162,13 @@ void ScreenManager_Update_Hook(auto original, ScreenManager* _this) if (!Key::IsInputFocused()) { // Lets try to remove the pre-scan because we hit escape and it's visible - if (Key::Pressed(KeyCode::Escape) && DidHideViewers()) { - return; + if (Key::Pressed(KeyCode::Escape)) { + if (config->primary_requires_visible_target) { + force_space_action_next_frame = false; + } + if (DidHideViewers()) { + return; + } } // Dismiss the golden rewards screen when escape or space is pressed. @@ -1264,14 +1269,23 @@ void ScreenManager_Update_Hook(auto original, ScreenManager* _this) return original(_this); } -// NOTE: If you change this loop functionality, also change DoHideViewersOfType template +template inline bool CanHideViewer(T* widget, bool require_parent = false) +{ + auto* visibility = widget ? widget->_visibilityController : nullptr; + if (!visibility || (visibility->_state != VisibilityState::Visible && visibility->_state != VisibilityState::Show)) { + return false; + } + if (!require_parent) { + return true; + } + auto* parent = widget->Parent; + return parent && parent->IsShowing; +} + template inline bool CanHideViewersOfType() { for (auto widget : ObjectFinder::GetAll()) { - const auto visible = widget && widget->_visibilityController != NULL - && (widget->_visibilityController->_state == VisibilityState::Visible - || widget->_visibilityController->_state == VisibilityState::Show); - if (visible) { + if (CanHideViewer(widget)) { return true; } } @@ -1288,22 +1302,12 @@ bool CanHideViewers() || CanHideViewersOfType()); } -// NOTE: If you change this loop functionality, also change CanideViewersOfType template template inline bool DidHideViewersOfType() { const auto objects = ObjectFinder::GetAll(); auto didHide = false; for (auto widget : objects) { - if (!widget) { - continue; - } - auto visbility_controller = widget->_visibilityController; - if (!visbility_controller) { - continue; - } - const auto visible = (visbility_controller->_state == VisibilityState::Visible - || visbility_controller->_state == VisibilityState::Show); - if (visible) { + if (CanHideViewer(widget)) { widget->HideAllViewers(); didHide = true; } @@ -1429,6 +1433,7 @@ void ExecuteSpaceAction(FleetBarViewController* fleet_bar) auto has_queue_clear = MapKey::IsDown(GameFunction::ActionQueueClear); auto has_recall = MapKey::IsDown(GameFunction::ActionRecall) && (!Config::Get().disable_preview_recall || !CanHideViewers()); + const bool require_visible_target = has_primary && Config::Get().primary_requires_visible_target; if (has_queue_clear) { action_queue->ClearQueue(fleet); @@ -1438,15 +1443,10 @@ void ExecuteSpaceAction(FleetBarViewController* fleet_bar) } else { auto all_pre_scan_widgets = ObjectFinder::GetAll(); for (auto pre_scan_widget : all_pre_scan_widgets) { - auto visibility_controller = pre_scan_widget ? pre_scan_widget->_visibilityController : nullptr; - if (visibility_controller - && (visibility_controller->_state == VisibilityState::Visible - || visibility_controller->_state == VisibilityState::Show)) { + if (CanHideViewer(pre_scan_widget, require_visible_target)) { if (auto mine_object_viewer_widget = ObjectFinder::Get(); - mine_object_viewer_widget && mine_object_viewer_widget->_visibilityController - && (mine_object_viewer_widget->_visibilityController->_state == VisibilityState::Visible - || mine_object_viewer_widget->_visibilityController->_state == VisibilityState::Show)) { + CanHideViewer(mine_object_viewer_widget, require_visible_target)) { if (has_secondary && pre_scan_widget->_scanEngageButtonsWidget) { return pre_scan_widget->_scanEngageButtonsWidget->OnScanButtonClicked(); } else if (has_primary) { @@ -1538,9 +1538,7 @@ void ExecuteSpaceAction(FleetBarViewController* fleet_bar) } if (auto mine_object_viewer_widget = ObjectFinder::Get(); - mine_object_viewer_widget && mine_object_viewer_widget->_visibilityController - && (mine_object_viewer_widget->_visibilityController->_state == VisibilityState::Visible - || mine_object_viewer_widget->_visibilityController->_state == VisibilityState::Show)) { + CanHideViewer(mine_object_viewer_widget, require_visible_target)) { if (has_secondary && mine_object_viewer_widget->_scanEngageButtonsWidget) { if (mine_object_viewer_widget->_scanEngageButtonsWidget->Context) { return mine_object_viewer_widget->_scanEngageButtonsWidget->OnScanButtonClicked(); @@ -1549,7 +1547,8 @@ void ExecuteSpaceAction(FleetBarViewController* fleet_bar) return mine_object_viewer_widget->MineClicked(); } } else if (auto star_node_object_viewer_widget = ObjectFinder::Get(); - star_node_object_viewer_widget && star_node_object_viewer_widget->Context) { + star_node_object_viewer_widget && star_node_object_viewer_widget->Context + && (!require_visible_target || CanHideViewer(star_node_object_viewer_widget, true))) { if (has_secondary) { star_node_object_viewer_widget->OnViewButtonActivation(); return; @@ -1579,7 +1578,10 @@ void ExecuteSpaceAction(FleetBarViewController* fleet_bar) return; } } else { - navigation_ui_controller->OnSetCourseButtonClick(); + // Dismissal keeps the native context's last position/path. Preserve that legacy shortcut unless opted out. + if (!require_visible_target || navigation_ui_controller->IsSetCourseVisible()) { + navigation_ui_controller->OnSetCourseButtonClick(); + } return; } } diff --git a/mods/src/prime/NavigationInteractionUIViewController.h b/mods/src/prime/NavigationInteractionUIViewController.h index 405170ed..2551295d 100644 --- a/mods/src/prime/NavigationInteractionUIViewController.h +++ b/mods/src/prime/NavigationInteractionUIViewController.h @@ -1,9 +1,37 @@ #pragma once #include +#include "VisibilityController.h" struct NavigationInteractionUIViewController { public: + bool IsSetCourseVisible() + { + static auto widget_class = il2cpp_get_class_helper("Assembly-CSharp", "Digit.Prime.Navigation", "SetCourseWidget"); + if (!get_class_helper().get_cls() || !widget_class.get_cls()) { + return false; + } + static auto widget_field = get_class_helper().GetField("_setCourseWidget"); + static auto visibility_field = widget_class.GetField("_visibilityController"); + static auto active_property = widget_class.GetProperty("isActiveAndEnabled"); + if (!widget_field.get_info() || !visibility_field.get_info()) { + return false; + } + + auto* widget = *reinterpret_cast(reinterpret_cast(this) + widget_field.offset()); + if (!widget) { + return false; + } + auto* visibility = + *reinterpret_cast(reinterpret_cast(widget) + visibility_field.offset()); + if (!visibility + || (visibility->_state != VisibilityState::Visible && visibility->_state != VisibilityState::Show)) { + return false; + } + const auto* active = active_property.Get(widget); + return active && *active; + } + void OnSetCourseButtonClick() { static auto OnSetCourseButtonClick = diff --git a/mods/src/prime/ParentObjectViewerViewController.h b/mods/src/prime/ParentObjectViewerViewController.h index 11ae6a13..030985b0 100644 --- a/mods/src/prime/ParentObjectViewerViewController.h +++ b/mods/src/prime/ParentObjectViewerViewController.h @@ -54,6 +54,7 @@ class ParentObjectViewerViewController : public ViewController(this); + const auto* showing = field.Get(this); + return showing && *showing; } -}; \ No newline at end of file +}; diff --git a/mods/src/prime/StarNodeObjectViewerWidget.h b/mods/src/prime/StarNodeObjectViewerWidget.h index 88938543..43f2ea50 100644 --- a/mods/src/prime/StarNodeObjectViewerWidget.h +++ b/mods/src/prime/StarNodeObjectViewerWidget.h @@ -2,9 +2,9 @@ #include -#include "Widget.h" +#include "ObjectViewerBaseWidget.h" -struct StarNodeObjectViewerWidget : public Widget { +struct StarNodeObjectViewerWidget : public ObjectViewerBaseWidget { public: void OnViewButtonActivation() { @@ -27,5 +27,5 @@ struct StarNodeObjectViewerWidget : public Widget; - friend struct Widget; + friend class ObjectViewerBaseWidget; };