diff --git a/src/gui/hotkeyConfig.cpp b/src/gui/hotkeyConfig.cpp index e0857f423b..0fb12e6a19 100644 --- a/src/gui/hotkeyConfig.cpp +++ b/src/gui/hotkeyConfig.cpp @@ -210,7 +210,9 @@ Keys::Keys() : {"WEAPONS_FIRE_TUBE16"}, }}, weapons_enemy_next_target("WEAPONS_TARGET_NEXT_ENEMY", "C"), + weapons_enemy_prev_target("WEAPONS_TARGET_PREV_ENEMY"), weapons_next_target("WEAPONS_TARGET_NEXT", "Z"), + weapons_prev_target("WEAPONS_TARGET_PREV"), weapons_toggle_shields("WEAPONS_SHIELDS_TOGGLE", "S"), weapons_enable_shields("WEAPONS_SHIELDS_ENABLE"), weapons_disable_shields("WEAPONS_SHIELDS_DISABLE"), @@ -231,6 +233,11 @@ Keys::Keys() : science_scan_object("SCIENCE_SCAN_OBJECT", "S"), science_scan_abort("SCIENCE_SCAN_ABORT", "D"), science_select_next_scannable("SCIENCE_SELECT_NEXT_SCANNABLE", "C"), + science_select_prev_scannable("SCIENCE_SELECT_PREV_SCANNABLE"), + science_next_target("SCIENCE_TARGET_NEXT"), + science_prev_target("SCIENCE_TARGET_PREV"), + science_enemy_next_target("SCIENCE_TARGET_NEXT_ENEMY"), + science_enemy_prev_target("SCIENCE_TARGET_PREV_ENEMY"), science_scan_param_increase{{ {"SCIENCE_SCAN_PARAM_INCREASE_1"}, {"SCIENCE_SCAN_PARAM_INCREASE_2"}, @@ -313,6 +320,14 @@ Keys::Keys() : relay_alert_level_none("RELAY_ALERT_NONE"), relay_alert_level_yellow("RELAY_ALERT_YELLOW"), relay_alert_level_red("RELAY_ALERT_RED"), + relay_next_target("RELAY_TARGET_NEXT"), + relay_prev_target("RELAY_TARGET_PREV"), + relay_enemy_next_target("RELAY_TARGET_NEXT_ENEMY"), + relay_enemy_prev_target("RELAY_TARGET_PREV_ENEMY"), + relay_next_hackable("RELAY_TARGET_NEXT_HACKABLE"), + relay_prev_hackable("RELAY_TARGET_PREV_HACKABLE"), + relay_next_probe("RELAY_TARGET_NEXT_PROBE"), + relay_prev_probe("RELAY_TARGET_PREV_PROBE"), // GM screen gm_delete("GM_DELETE", "Delete"), @@ -415,7 +430,9 @@ void Keys::init() weapons_fire_tube[n].setLabel(tr("hotkey_menu", "Weapons"), tr("hotkey_Weapons", "Fire tube {number}").format({{"number", string(n + 1)}})); } weapons_enemy_next_target.setLabel(tr("hotkey_menu", "Weapons"), tr("hotkey_Weapons", "Select next hostile target")); + weapons_enemy_prev_target.setLabel(tr("hotkey_menu", "Weapons"), tr("hotkey_Weapons", "Select previous hostile target")); weapons_next_target.setLabel(tr("hotkey_menu", "Weapons"), tr("hotkey_Weapons", "Select next target (any)")); + weapons_prev_target.setLabel(tr("hotkey_menu", "Weapons"), tr("hotkey_Weapons", "Select previous target (any)")); weapons_toggle_shields.setLabel(tr("hotkey_menu", "Weapons"), tr("hotkey_Weapons", "Toggle shields")); weapons_enable_shields.setLabel(tr("hotkey_menu", "Weapons"), tr("hotkey_Weapons", "Enable shields")); weapons_disable_shields.setLabel(tr("hotkey_menu", "Weapons"), tr("hotkey_Weapons", "Disable shields")); @@ -436,6 +453,11 @@ void Keys::init() science_scan_object.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Scan object")); science_scan_abort.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Abort scan")); science_select_next_scannable.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Select next scannable object")); + science_select_prev_scannable.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Select previous scannable object")); + science_next_target.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Select next target (any)")); + science_prev_target.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Select previous target (any)")); + science_enemy_next_target.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Select next hostile target")); + science_enemy_prev_target.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Select previous hostile target")); for (auto n = 0u; n < science_scan_param_increase.size(); n++) { science_scan_param_increase[n].setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Scanning parameter {number} increase").format({{"number", string(n + 1)}})); @@ -502,6 +524,14 @@ void Keys::init() relay_alert_level_none.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Alert level: Normal")); relay_alert_level_yellow.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Alert level: Yellow")); relay_alert_level_red.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Alert level: Red")); + relay_next_target.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Select next target (any)")); + relay_prev_target.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Select previous target (any)")); + relay_enemy_next_target.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Select next hostile target")); + relay_enemy_prev_target.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Select previous hostile target")); + relay_next_hackable.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Select next hackable target")); + relay_prev_hackable.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Select previous hackable target")); + relay_next_probe.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Select next probe")); + relay_prev_probe.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Select previous probe")); // Cinematic view cinematic.init(); diff --git a/src/gui/hotkeyConfig.h b/src/gui/hotkeyConfig.h index 67d2172338..142e2831d8 100644 --- a/src/gui/hotkeyConfig.h +++ b/src/gui/hotkeyConfig.h @@ -99,7 +99,9 @@ class Keys std::array weapons_unload_tube; std::array weapons_fire_tube; sp::io::Keybinding weapons_enemy_next_target; + sp::io::Keybinding weapons_enemy_prev_target; sp::io::Keybinding weapons_next_target; + sp::io::Keybinding weapons_prev_target; sp::io::Keybinding weapons_toggle_shields; sp::io::Keybinding weapons_enable_shields; sp::io::Keybinding weapons_disable_shields; @@ -120,6 +122,11 @@ class Keys sp::io::Keybinding science_scan_object; sp::io::Keybinding science_scan_abort; sp::io::Keybinding science_select_next_scannable; + sp::io::Keybinding science_select_prev_scannable; + sp::io::Keybinding science_next_target; + sp::io::Keybinding science_prev_target; + sp::io::Keybinding science_enemy_next_target; + sp::io::Keybinding science_enemy_prev_target; std::array science_scan_param_increase; std::array science_scan_param_decrease; std::array science_scan_param_set; @@ -158,6 +165,14 @@ class Keys sp::io::Keybinding relay_alert_level_none; sp::io::Keybinding relay_alert_level_yellow; sp::io::Keybinding relay_alert_level_red; + sp::io::Keybinding relay_next_target; + sp::io::Keybinding relay_prev_target; + sp::io::Keybinding relay_enemy_next_target; + sp::io::Keybinding relay_enemy_prev_target; + sp::io::Keybinding relay_next_hackable; + sp::io::Keybinding relay_prev_hackable; + sp::io::Keybinding relay_next_probe; + sp::io::Keybinding relay_prev_probe; // Cinematic view binds struct CinematicKeys { diff --git a/src/screenComponents/targetsContainer.cpp b/src/screenComponents/targetsContainer.cpp index 303a6aa822..b233067d40 100644 --- a/src/screenComponents/targetsContainer.cpp +++ b/src/screenComponents/targetsContainer.cpp @@ -7,7 +7,6 @@ #include "components/radar.h" #include "ecs/query.h" - TargetsContainer::TargetsContainer() { waypoint_selection_index = -1; @@ -22,24 +21,15 @@ void TargetsContainer::clear() void TargetsContainer::add(sp::ecs::Entity obj) { - if (!obj) - return; - for(auto e : entries) - if (e == obj) - return; + if (!obj) return; + for (auto e : entries) if (e == obj) return; entries.push_back(obj); } void TargetsContainer::set(sp::ecs::Entity obj) { - if (obj) - { - entries = {obj}; - } - else - { - clear(); - } + if (obj) entries = {obj}; + else clear(); waypoint_selection_index = -1; } @@ -56,150 +46,302 @@ std::vector TargetsContainer::getTargets() sp::ecs::Entity TargetsContainer::get() { - if (entries.empty()) - return {}; + if (entries.empty()) return {}; return entries[0]; } +std::vector TargetsContainer::populateEntities(glm::vec2 position, float max_range, ESelectionType selection_type, std::function filter) +{ + std::vector entities; + + for (auto [entity, transform] : sp::ecs::Query()) + { + if (isValidTarget(entity, selection_type) + && glm::distance(position, transform.getPosition()) <= max_range + && filter(entity)) + { + entities.push_back(entity); + } + } + + sortByDistance(position, entities); + return entities; +} + +std::vector TargetsContainer::populateEntities(glm::vec2 position, float max_range, ESelectionType selection_type, KnownFriendOrFoe known_fof) +{ + std::vector entities; + + for (auto [entity, transform] : sp::ecs::Query()) + { + if (isValidTarget(entity, selection_type) + && glm::distance(position, transform.getPosition()) <= max_range) + { + switch (known_fof) + { + // Target any entity regardless of FoF state. + case KnownFriendOrFoe::Any: + entities.push_back(entity); + break; + // Target only entities with a known FoF state (skip unknown). + case KnownFriendOrFoe::Known: + if (isFoFKnown(entity)) entities.push_back(entity); + break; + // Target only entities whose FoF state is unknown (skip known). + case KnownFriendOrFoe::Unknown: + if (!isFoFKnown(entity)) entities.push_back(entity); + break; + // Target only entities whose FoF state is known friendly. + case KnownFriendOrFoe::KnownFriendly: + if (isFoFKnown(entity) && Faction::getRelation(my_spaceship, entity) == FactionRelation::Friendly) + entities.push_back(entity); + break; + // Target only entities whose FoF state is known non-friendly + // (neutral, hostile). + case KnownFriendOrFoe::KnownNonFriendly: + if (isFoFKnown(entity) && Faction::getRelation(my_spaceship, entity) != FactionRelation::Friendly) + entities.push_back(entity); + break; + // Target only entities whose FoF state is not known friendly + // (neutral, hostile, unknown). + case KnownFriendOrFoe::NotKnownFriendly: + { + const bool is_known = isFoFKnown(entity); + if (!is_known + || (is_known && Faction::getRelation(my_spaceship, entity) != FactionRelation::Friendly)) + { + entities.push_back(entity); + } + break; + } + // Target only entities whose FoF state is known neutral. + case KnownFriendOrFoe::KnownNeutral: + if (isFoFKnown(entity) && Faction::getRelation(my_spaceship, entity) == FactionRelation::Neutral) + entities.push_back(entity); + break; + // Target only entities whose FoF state is known non-neutral + // (friendly, hostile). + case KnownFriendOrFoe::KnownNonNeutral: + if (isFoFKnown(entity) && Faction::getRelation(my_spaceship, entity) != FactionRelation::Neutral) + entities.push_back(entity); + break; + // Target only entities whose FoF state is not known neutral + // (friendly, hostile, unknown). + case KnownFriendOrFoe::NotKnownNeutral: + { + const bool is_known = isFoFKnown(entity); + if (!is_known + || (is_known && Faction::getRelation(my_spaceship, entity) != FactionRelation::Neutral)) + { + entities.push_back(entity); + } + break; + } + // Target only entities whose FoF state is known hostile. + case KnownFriendOrFoe::KnownHostile: + if (isFoFKnown(entity) && Faction::getRelation(my_spaceship, entity) == FactionRelation::Enemy) + entities.push_back(entity); + break; + // Target only entities whose FoF state is known non-hostile + // (neutral, friendly). + case KnownFriendOrFoe::KnownNonHostile: + if (isFoFKnown(entity) && Faction::getRelation(my_spaceship, entity) != FactionRelation::Enemy) + entities.push_back(entity); + break; + // Target only entities whose FoF state is not known hostile + // (neutral, friendly, unknown). + case KnownFriendOrFoe::NotKnownHostile: + { + const bool is_known = isFoFKnown(entity); + if (!is_known + || (is_known && Faction::getRelation(my_spaceship, entity) != FactionRelation::Enemy)) + { + entities.push_back(entity); + } + break; + } + } + } + } + + sortByDistance(position, entities); + return entities; +} + void TargetsContainer::setToClosestTo(glm::vec2 position, float max_range, ESelectionType selection_type) { sp::ecs::Entity target; glm::vec2 target_position; for(auto entity : sp::TransformQuery::queryArea(position - glm::vec2(max_range, max_range), position + glm::vec2(max_range, max_range))) { + if (!isValidTarget(entity, selection_type)) continue; auto transform = entity.getComponent(); if (!transform) continue; - if (!isValidTarget(entity, selection_type)) continue; - if (!target || glm::length2(position - transform->getPosition()) < glm::length2(position - target_position)) { + if (!target || glm::length2(position - transform->getPosition()) < glm::length2(position - target_position)) + { target = entity; target_position = transform->getPosition(); } } - if (allow_waypoint_selection) { - if (auto waypoints = my_spaceship.getComponent()) { - for(size_t n=0; nwaypoints.size(); n++) + if (auto waypoints = my_spaceship.getComponent()) + { + for (size_t n = 0; n < waypoints->waypoints.size(); n++) { - if (glm::length2(waypoints->waypoints[n].position - position) < max_range*max_range) + if (glm::length2(waypoints->waypoints[n].position - position) < max_range * max_range + && (!target || glm::length2(position - waypoints->waypoints[n].position) < glm::length2(position - target_position))) { - if (!target || glm::length2(position - waypoints->waypoints[n].position) < glm::length2(position - target_position)) - { - clear(); - waypoint_selection_index = waypoints->waypoints[n].id; - return; - } + clear(); + waypoint_selection_index = waypoints->waypoints[n].id; + return; } } } } + set(target); } int TargetsContainer::getWaypointIndex() { auto waypoints = my_spaceship.getComponent(); - if (!waypoints || waypoint_selection_index < 0 || !waypoints->get(waypoint_selection_index)) + if (!waypoints + || waypoint_selection_index < 0 + || !waypoints->get(waypoint_selection_index)) + { waypoint_selection_index = -1; + } + return waypoint_selection_index; } void TargetsContainer::setWaypointIndex(int index) { auto waypoints = my_spaceship.getComponent(); - if (waypoints && waypoints->get(index)) - waypoint_selection_index = index; + if (waypoints && waypoints->get(index)) waypoint_selection_index = index; } -void TargetsContainer::setNext(glm::vec2 position, float max_range, ESelectionType selection_type) +bool TargetsContainer::isFoFKnown(sp::ecs::Entity entity) { - std::vector entities; - - for(auto [entity, transform] : sp::ecs::Query()) { - if(isValidTarget(entity, selection_type) && glm::distance(position, transform.getPosition()) <= max_range) { - entities.push_back(entity); - } - } + auto ss = entity.getComponent(); + if (!ss) return true; + return ss->getStateFor(my_spaceship) >= ScanState::State::FriendOrFoeIdentified; +} - sortByDistance(position, entities); - setNext(position, max_range, entities); +void TargetsContainer::setNext(glm::vec2 position, float max_range, ESelectionType selection_type, KnownFriendOrFoe known_fof) +{ + setNext(position, populateEntities(position, max_range, selection_type, known_fof)); } -void TargetsContainer::setNext(glm::vec2 position, float max_range, ESelectionType selection_type, FactionRelation relation) +void TargetsContainer::setPrev(glm::vec2 position, float max_range, ESelectionType selection_type, KnownFriendOrFoe known_fof) { - std::vector entities; - for(auto [entity, transform] : sp::ecs::Query()) { - if(isValidTarget(entity, selection_type) && glm::distance(position, transform.getPosition()) <= max_range && Faction::getRelation(my_spaceship, entity) == relation) { - entities.push_back(entity); - } - } + setPrev(position, populateEntities(position, max_range, selection_type, known_fof)); +} - sortByDistance(position, entities); - setNext(position, max_range, entities); +void TargetsContainer::setNext(glm::vec2 position, float max_range, ESelectionType selection_type, std::function filter) +{ + setNext(position, populateEntities(position, max_range, selection_type, filter)); } -void TargetsContainer::setNext(glm::vec2 position, float max_range, std::vector &entities) +void TargetsContainer::setPrev(glm::vec2 position, float max_range, ESelectionType selection_type, std::function filter) { - sp::ecs::Entity default_target; - sp::ecs::Entity current_target; - glm::vec2 default_target_position; + setPrev(position, populateEntities(position, max_range, selection_type, filter)); +} - for (auto entity : entities) { - auto transform = entity.getComponent(); +void TargetsContainer::setNext(glm::vec2 position, const std::vector& entities) +{ + // Find the first valid entity (closest in the distance-sorted list) for + // wrap-around. + sp::ecs::Entity first_valid; + for (auto entity : entities) + { + if (!entity.hasComponent()) continue; + first_valid = entity; + break; + } - if (!transform) - continue; + if (!first_valid) return; - // Start collecting nearest relevant entities in case we never run into a previous target - if (!default_target || - glm::length2(position - transform->getPosition()) < - glm::length2(position - default_target_position)) { - default_target = entity; - default_target_position = transform->getPosition(); - } + bool found_current = false; + for (auto entity : entities) + { + if (!entity.hasComponent()) continue; - // if we set a current target in the last iteration (condition below) - // the set the entity to be this next entity in the list. - if (current_target) { + // Select the entity after this one, or wrap to the closest if there + // isn't one. + if (found_current) + { set(entity); my_player_info->commandSetTarget(get()); return; } - if (get() == entity) { - current_target = entity; - } + if (get() == entity) + found_current = true; } - // If we didn't short-circuit because of an existing target above, set the - // target to be the default_target (closest to `position`) - set(default_target); + // Current target not in list or at end: select the first/closest entity. + set(first_valid); my_player_info->commandSetTarget(get()); } -void TargetsContainer::sortByDistance(glm::vec2 position, std::vector& entities) +void TargetsContainer::setPrev(glm::vec2 position, const std::vector& entities) { - sort(entities.begin(), entities.end(), [position](sp::ecs::Entity a, sp::ecs::Entity b) { - auto transform_a = a.getComponent(); - auto transform_b = b.getComponent(); - if (!transform_a) - return bool(transform_b); + // Find the last valid entity (furthest in the distance-sorted list) for + // wrap-around. + sp::ecs::Entity last_valid; + for (auto entity : entities) + { + if (!entity.hasComponent()) continue; + last_valid = entity; + } + + if (!last_valid) return; + + sp::ecs::Entity prev_entity; + for (auto entity : entities) + { + if (!entity.hasComponent()) continue; - if (!transform_b) - return bool(transform_a); + // Select the entity before this one, or wrap to the furthest if there + // isn't one. + if (get() == entity) + { + set(prev_entity ? prev_entity : last_valid); + my_player_info->commandSetTarget(get()); + return; + } + prev_entity = entity; + } - return glm::distance(position, transform_a->getPosition()) < glm::distance(position, transform_b->getPosition()); - }); + // Current target not in list: select the furthest entity. + set(last_valid); + my_player_info->commandSetTarget(get()); +} +void TargetsContainer::sortByDistance(glm::vec2 position, std::vector& entities) +{ + sort (entities.begin(), entities.end(), + [position](sp::ecs::Entity a, sp::ecs::Entity b) + { + auto transform_a = a.getComponent(); + auto transform_b = b.getComponent(); + if (!transform_a) return bool(transform_b); + if (!transform_b) return bool(transform_a); + + return glm::distance(position, transform_a->getPosition()) < glm::distance(position, transform_b->getPosition()); + } + ); } bool TargetsContainer::isValidTarget(sp::ecs::Entity entity, ESelectionType selection_type) { if (entity == my_spaceship) return false; - switch(selection_type) + switch (selection_type) { case Selectable: if (entity.hasComponent()) return true; @@ -217,5 +359,6 @@ bool TargetsContainer::isValidTarget(sp::ecs::Entity entity, ESelectionType sele if (entity.getComponent()) return true; break; } + return false; } diff --git a/src/screenComponents/targetsContainer.h b/src/screenComponents/targetsContainer.h index 3e792e1037..f17f4cc0ed 100644 --- a/src/screenComponents/targetsContainer.h +++ b/src/screenComponents/targetsContainer.h @@ -1,8 +1,8 @@ -#ifndef TARGETS_CONTAINER_H -#define TARGETS_CONTAINER_H +#pragma once #include "ecs/entity.h" #include "components/faction.h" +#include class TargetsContainer { @@ -14,6 +14,22 @@ class TargetsContainer Scannable, }; + enum class KnownFriendOrFoe + { + Any, + Known, + Unknown, + KnownFriendly, + KnownNonFriendly, + NotKnownFriendly, + KnownNeutral, + KnownNonNeutral, + NotKnownNeutral, + KnownHostile, + KnownNonHostile, + NotKnownHostile + }; + TargetsContainer(); void setAllowWaypointSelection() { allow_waypoint_selection = true; } @@ -28,17 +44,27 @@ class TargetsContainer void setWaypointIndex(int index); void setToClosestTo(glm::vec2 position, float max_range, ESelectionType selection_type); - void setNext(glm::vec2 position, float max_range, ESelectionType selection_type); - void setNext(glm::vec2 position, float max_range, ESelectionType selection_type, FactionRelation relation); + + // Select next/previous target by selection type, and optionally also by + // friend-or-foe state. + void setNext(glm::vec2 position, float max_range, ESelectionType selection_type, KnownFriendOrFoe known_fof = KnownFriendOrFoe::Any); + void setPrev(glm::vec2 position, float max_range, ESelectionType selection_type, KnownFriendOrFoe known_fof = KnownFriendOrFoe::Any); + // Select next/previous target by selection type and a function-defined + // filter. + void setNext(glm::vec2 position, float max_range, ESelectionType selection_type, std::function filter); + void setPrev(glm::vec2 position, float max_range, ESelectionType selection_type, std::function filter); private: std::vector entries; bool allow_waypoint_selection; int waypoint_selection_index; - void setNext(glm::vec2 position, float max_range, std::vector& entities); + bool isFoFKnown(sp::ecs::Entity entity); void sortByDistance(glm::vec2 position, std::vector& entities); bool isValidTarget(sp::ecs::Entity entity, ESelectionType selection_type); + // Return a vector of entities that match the given condition. + std::vector populateEntities(glm::vec2 position, float max_range, ESelectionType selection_type, KnownFriendOrFoe known_fof); + std::vector populateEntities(glm::vec2 position, float max_range, ESelectionType selection_type, std::function filter); + void setNext(glm::vec2 position, const std::vector& entities); + void setPrev(glm::vec2 position, const std::vector& entities); }; - -#endif//TARGETS_CONTAINER_H diff --git a/src/screens/crew1/singlePilotScreen.cpp b/src/screens/crew1/singlePilotScreen.cpp index 5aa90eac9e..8d46354b38 100644 --- a/src/screens/crew1/singlePilotScreen.cpp +++ b/src/screens/crew1/singlePilotScreen.cpp @@ -164,37 +164,83 @@ void SinglePilotScreen::onDraw(sp::RenderTarget& renderer) void SinglePilotScreen::onUpdate() { - if (my_spaceship && isVisible()) + if (!my_spaceship || !isVisible()) return; + + // Copied and pasted from Helms screen. + auto angle = (keys.helms_turn_right.getValue() - keys.helms_turn_left.getValue()) * 5.0f; + if (angle != 0.0f) { - auto angle = (keys.helms_turn_right.getValue() - keys.helms_turn_left.getValue()) * 5.0f; - if (angle != 0.0f) - { - if (auto transform = my_spaceship.getComponent()) - my_player_info->commandTargetRotation(transform->getRotation() + angle); - } + if (auto transform = my_spaceship.getComponent()) + my_player_info->commandTargetRotation(transform->getRotation() + angle); + } - if (keys.weapons_enemy_next_target.getDown()) + // Copied and pasted from Weapons screen. + // Target selection cycle keybinds. + // Select hostile targets. + if (keys.weapons_enemy_next_target.getDown()) + { + if (auto transform = my_spaceship.getComponent()) { - if (auto transform = my_spaceship.getComponent()) { - auto lrr = my_spaceship.getComponent(); - targets.setNext(transform->getPosition(), lrr ? lrr->short_range : 5000.0f, TargetsContainer::Targetable, FactionRelation::Enemy); - my_player_info->commandSetTarget(targets.get()); - } + auto lrr = my_spaceship.getComponent(); + targets.setNext( + transform->getPosition(), + lrr ? lrr->short_range : 5000.0f, + TargetsContainer::ESelectionType::Targetable, + TargetsContainer::KnownFriendOrFoe::KnownHostile + ); + my_player_info->commandSetTarget(targets.get()); } - if (keys.weapons_next_target.getDown()) + } + if (keys.weapons_enemy_prev_target.getDown()) + { + if (auto transform = my_spaceship.getComponent()) { - if (auto transform = my_spaceship.getComponent()) { - auto lrr = my_spaceship.getComponent(); - targets.setNext(transform->getPosition(), lrr ? lrr->short_range : 5000.0f, TargetsContainer::Targetable); - my_player_info->commandSetTarget(targets.get()); - } + auto lrr = my_spaceship.getComponent(); + targets.setPrev( + transform->getPosition(), + lrr ? lrr->short_range : 5000.0f, + TargetsContainer::ESelectionType::Targetable, + TargetsContainer::KnownFriendOrFoe::KnownHostile + ); + my_player_info->commandSetTarget(targets.get()); } + } - auto aim_adjust = keys.weapons_aim_left.getValue() - keys.weapons_aim_right.getValue(); - if (aim_adjust != 0.0f) + // Select any non-friendly target. + if (keys.weapons_next_target.getDown()) + { + if (auto transform = my_spaceship.getComponent()) + { + auto lrr = my_spaceship.getComponent(); + targets.setNext( + transform->getPosition(), + lrr ? lrr->short_range : 5000.0f, + TargetsContainer::ESelectionType::Targetable, + TargetsContainer::KnownFriendOrFoe::NotKnownFriendly + ); + my_player_info->commandSetTarget(targets.get()); + } + } + if (keys.weapons_prev_target.getDown()) + { + if (auto transform = my_spaceship.getComponent()) { - missile_aim->setValue(missile_aim->getValue() - 5.0f * aim_adjust); - tube_controls->setMissileTargetAngle(missile_aim->getValue()); + auto lrr = my_spaceship.getComponent(); + targets.setPrev( + transform->getPosition(), + lrr ? lrr->short_range : 5000.0f, + TargetsContainer::ESelectionType::Targetable, + TargetsContainer::KnownFriendOrFoe::NotKnownFriendly + ); + my_player_info->commandSetTarget(targets.get()); } } + + // Manual missile aiming keybinds. + auto aim_adjust = keys.weapons_aim_left.getValue() - keys.weapons_aim_right.getValue(); + if (aim_adjust != 0.0f) + { + missile_aim->setValue(missile_aim->getValue() - 5.0f * aim_adjust); + tube_controls->setMissileTargetAngle(missile_aim->getValue()); + } } diff --git a/src/screens/crew4/tacticalScreen.cpp b/src/screens/crew4/tacticalScreen.cpp index dd2280c1e2..6e36f14fc5 100644 --- a/src/screens/crew4/tacticalScreen.cpp +++ b/src/screens/crew4/tacticalScreen.cpp @@ -152,37 +152,83 @@ void TacticalScreen::onDraw(sp::RenderTarget& renderer) void TacticalScreen::onUpdate() { - if (my_spaceship && isVisible()) + if (!my_spaceship || !isVisible()) return; + + // Copied and pasted from Helms screen. + auto angle = (keys.helms_turn_right.getValue() - keys.helms_turn_left.getValue()) * 5.0f; + if (angle != 0.0f) { - auto angle = (keys.helms_turn_right.getValue() - keys.helms_turn_left.getValue()) * 5.0f; - if (angle != 0.0f) - { - if (auto transform = my_spaceship.getComponent()) - my_player_info->commandTargetRotation(transform->getRotation() + angle); - } + if (auto transform = my_spaceship.getComponent()) + my_player_info->commandTargetRotation(transform->getRotation() + angle); + } - if (keys.weapons_enemy_next_target.getDown()) + // Copied and pasted from Weapons screen. + // Target selection cycle keybinds. + // Select hostile targets. + if (keys.weapons_enemy_next_target.getDown()) + { + if (auto transform = my_spaceship.getComponent()) { - if (auto transform = my_spaceship.getComponent()) { - auto lrr = my_spaceship.getComponent(); - targets.setNext(transform->getPosition(), lrr ? lrr->short_range : 5000.0f, TargetsContainer::Targetable, FactionRelation::Enemy); - my_player_info->commandSetTarget(targets.get()); - } + auto lrr = my_spaceship.getComponent(); + targets.setNext( + transform->getPosition(), + lrr ? lrr->short_range : 5000.0f, + TargetsContainer::ESelectionType::Targetable, + TargetsContainer::KnownFriendOrFoe::KnownHostile + ); + my_player_info->commandSetTarget(targets.get()); } - if (keys.weapons_next_target.getDown()) + } + if (keys.weapons_enemy_prev_target.getDown()) + { + if (auto transform = my_spaceship.getComponent()) { - if (auto transform = my_spaceship.getComponent()) { - auto lrr = my_spaceship.getComponent(); - targets.setNext(transform->getPosition(), lrr ? lrr->short_range : 5000.0f, TargetsContainer::Targetable); - my_player_info->commandSetTarget(targets.get()); - } + auto lrr = my_spaceship.getComponent(); + targets.setPrev( + transform->getPosition(), + lrr ? lrr->short_range : 5000.0f, + TargetsContainer::ESelectionType::Targetable, + TargetsContainer::KnownFriendOrFoe::KnownHostile + ); + my_player_info->commandSetTarget(targets.get()); } + } - auto aim_adjust = keys.weapons_aim_left.getValue() - keys.weapons_aim_right.getValue(); - if (aim_adjust != 0.0f) + // Select any non-friendly target. + if (keys.weapons_next_target.getDown()) + { + if (auto transform = my_spaceship.getComponent()) + { + auto lrr = my_spaceship.getComponent(); + targets.setNext( + transform->getPosition(), + lrr ? lrr->short_range : 5000.0f, + TargetsContainer::ESelectionType::Targetable, + TargetsContainer::KnownFriendOrFoe::NotKnownFriendly + ); + my_player_info->commandSetTarget(targets.get()); + } + } + if (keys.weapons_prev_target.getDown()) + { + if (auto transform = my_spaceship.getComponent()) { - missile_aim->setValue(missile_aim->getValue() - 5.0f * aim_adjust); - tube_controls->setMissileTargetAngle(missile_aim->getValue()); + auto lrr = my_spaceship.getComponent(); + targets.setPrev( + transform->getPosition(), + lrr ? lrr->short_range : 5000.0f, + TargetsContainer::ESelectionType::Targetable, + TargetsContainer::KnownFriendOrFoe::NotKnownFriendly + ); + my_player_info->commandSetTarget(targets.get()); } } + + // Manual missile aiming keybinds. + auto aim_adjust = keys.weapons_aim_left.getValue() - keys.weapons_aim_right.getValue(); + if (aim_adjust != 0.0f) + { + missile_aim->setValue(missile_aim->getValue() - 5.0f * aim_adjust); + tube_controls->setMissileTargetAngle(missile_aim->getValue()); + } } diff --git a/src/screens/crew6/relayScreen.cpp b/src/screens/crew6/relayScreen.cpp index d7bd665eac..89a9447a61 100644 --- a/src/screens/crew6/relayScreen.cpp +++ b/src/screens/crew6/relayScreen.cpp @@ -38,6 +38,22 @@ static bool canHack(sp::ecs::Entity entity) return Faction::getRelation(entity, my_spaceship) != FactionRelation::Friendly; } +static bool isVisibleOnRelay(sp::ecs::Entity entity) +{ + auto target_transform = entity.getComponent(); + if (!target_transform) return false; + for (auto [e, ssrr, transform] : sp::ecs::Query()) + { + if (Faction::getRelation(my_spaceship, e) != FactionRelation::Friendly) + continue; + float r = 5000.0f; + if (auto lrr = e.getComponent()) r = lrr->short_range; + if (glm::length2(transform.getPosition() - target_transform->getPosition()) < r * r) + return true; + } + return false; +} + RelayScreen::RelayScreen(GuiContainer* owner, bool allow_comms) : GuiOverlay(owner, "RELAY_SCREEN", GuiTheme::getColor("background")), mode(TargetSelection) { @@ -342,3 +358,87 @@ void RelayScreen::onDraw(sp::RenderTarget& renderer) delete_waypoint_button->setEnable(targets.getWaypointIndex() >= 0); } + +void RelayScreen::onUpdate() +{ + if (!my_spaceship || !isVisible()) return; + + if (auto transform = my_spaceship.getComponent()) + { + const float view_range = radar->getDistance() * 1.42f; + + // Select visible targetable entities. + if (keys.relay_next_target.getDown()) + targets.setNext(transform->getPosition(), view_range, TargetsContainer::Targetable, isVisibleOnRelay); + if (keys.relay_prev_target.getDown()) + targets.setPrev(transform->getPosition(), view_range, TargetsContainer::Targetable, isVisibleOnRelay); + + // Select visible hostile entities. + if (keys.relay_enemy_next_target.getDown()) + { + targets.setNext(transform->getPosition(), view_range, TargetsContainer::Targetable, + [](sp::ecs::Entity entity) + { + if (!isVisibleOnRelay(entity)) return false; + auto ss = entity.getComponent(); + bool fof_known = !ss || ss->getStateFor(my_spaceship) >= ScanState::State::FriendOrFoeIdentified; + return fof_known && Faction::getRelation(my_spaceship, entity) == FactionRelation::Enemy; + } + ); + } + if (keys.relay_enemy_prev_target.getDown()) + { + targets.setPrev(transform->getPosition(), view_range, TargetsContainer::Targetable, + [](sp::ecs::Entity entity) + { + if (!isVisibleOnRelay(entity)) return false; + auto ss = entity.getComponent(); + bool fof_known = !ss || ss->getStateFor(my_spaceship) >= ScanState::State::FriendOrFoeIdentified; + return fof_known && Faction::getRelation(my_spaceship, entity) == FactionRelation::Enemy; + } + ); + } + + // Select visible hackable entities. + if (keys.relay_next_hackable.getDown()) + { + targets.setNext(transform->getPosition(), view_range, TargetsContainer::Targetable, + [](sp::ecs::Entity entity) + { + return isVisibleOnRelay(entity) && canHack(entity); + } + ); + } + if (keys.relay_prev_hackable.getDown()) + { + targets.setPrev(transform->getPosition(), view_range, TargetsContainer::Targetable, + [](sp::ecs::Entity entity) + { + return isVisibleOnRelay(entity) && canHack(entity); + } + ); + } + + // Select player-launched probes. + if (keys.relay_next_probe.getDown()) + { + targets.setNext(transform->getPosition(), view_range, TargetsContainer::Selectable, + [](sp::ecs::Entity entity) + { + auto arl = entity.getComponent(); + return arl && arl->owner == my_spaceship; + } + ); + } + if (keys.relay_prev_probe.getDown()) + { + targets.setPrev(transform->getPosition(), view_range, TargetsContainer::Selectable, + [](sp::ecs::Entity entity) + { + auto arl = entity.getComponent(); + return arl && arl->owner == my_spaceship; + } + ); + } + } +} diff --git a/src/screens/crew6/relayScreen.h b/src/screens/crew6/relayScreen.h index 8de707344b..37d4d4f0fa 100644 --- a/src/screens/crew6/relayScreen.h +++ b/src/screens/crew6/relayScreen.h @@ -52,4 +52,5 @@ class RelayScreen : public GuiOverlay RelayScreen(GuiContainer* owner, bool allow_comms); virtual void onDraw(sp::RenderTarget& target) override; + virtual void onUpdate() override; }; diff --git a/src/screens/crew6/scienceScreen.cpp b/src/screens/crew6/scienceScreen.cpp index 22e05bc8fc..7a849c2f26 100644 --- a/src/screens/crew6/scienceScreen.cpp +++ b/src/screens/crew6/scienceScreen.cpp @@ -547,39 +547,68 @@ void ScienceScreen::onDraw(sp::RenderTarget& renderer) void ScienceScreen::onUpdate() { - if (my_spaceship) + if (!my_spaceship || !isVisible()) return; + + // Initiate a scan on scannable objects. + if (keys.science_scan_object.getDown() && + my_spaceship.hasComponent() && + my_spaceship.getComponent()->delay == 0.0f) { - // Initiate a scan on scannable objects. - if (keys.science_scan_object.getDown() && - my_spaceship.hasComponent() && - my_spaceship.getComponent()->delay == 0.0f) + auto obj = targets.get(); + + // Allow scanning only if the object is scannable, and if the player + // isn't already scanning something. + auto scanstate = obj.getComponent(); + if (scanstate && scanstate->getStateFor(my_spaceship) != ScanState::State::FullScan) { - auto obj = targets.get(); + // Check for active radar link and validate the linked entity. + auto rl = my_spaceship.getComponent(); + if (rl && rl->linked_entity && rl->linked_entity.hasComponent() && probe_radar->isVisible()) + my_player_info->commandScan(obj, rl->linked_entity); + else + my_player_info->commandScan(obj); + return; + } + } + + // Cycle selectable entities. + if (auto transform = my_spaceship.getComponent()) + { + auto scanner = my_spaceship.getComponent(); + glm::vec2 scanner_position = transform->getPosition(); + float scanner_range = science_radar->getDistance(); - // Allow scanning only if the object is scannable, and if the player - // isn't already scanning something. - auto scanstate = obj.getComponent(); - if (scanstate && scanstate->getStateFor(my_spaceship) != ScanState::State::FullScan) + if (auto rl = my_spaceship.getComponent()) + { + if (probe_view_button->getValue() && rl && rl->linked_entity) { - // Check for active radar link and validate the linked entity - auto rl = my_spaceship.getComponent(); - if (rl && rl->linked_entity && rl->linked_entity.hasComponent() && probe_radar->isVisible()) - my_player_info->commandScan(obj, rl->linked_entity); - else - my_player_info->commandScan(obj); - return; + if (auto probe_transform = rl->linked_entity.getComponent()) + { + scanner_position = probe_transform->getPosition(); + scanner_range = PROBE_ZOOM_DISTANCE; + } } } - // Cycle selection through scannable objects. - if (keys.science_select_next_scannable.getDown() && - my_spaceship.hasComponent() && - my_spaceship.getComponent()->delay == 0.0f) + // Select previous/next scannable entity. + if (scanner && scanner->delay == 0.0f) { - if (auto transform = my_spaceship.getComponent()) { - auto lrr = my_spaceship.getComponent(); - targets.setNext(transform->getPosition(), lrr ? lrr->long_range : DEFAULT_MAX_ZOOM_DISTANCE, TargetsContainer::ESelectionType::Scannable); - } + if (keys.science_select_next_scannable.getDown()) + targets.setNext(scanner_position, scanner_range, TargetsContainer::ESelectionType::Scannable); + if (keys.science_select_prev_scannable.getDown()) + targets.setPrev(scanner_position, scanner_range, TargetsContainer::ESelectionType::Scannable); } + + // Select previous/next hostile entity. + if (keys.science_enemy_next_target.getDown()) + targets.setNext(scanner_position, scanner_range, TargetsContainer::ESelectionType::Selectable, TargetsContainer::KnownFriendOrFoe::KnownHostile); + if (keys.science_enemy_prev_target.getDown()) + targets.setPrev(scanner_position, scanner_range, TargetsContainer::ESelectionType::Selectable, TargetsContainer::KnownFriendOrFoe::KnownHostile); + + // Select previous/next selectable entity. + if (keys.science_next_target.getDown()) + targets.setNext(scanner_position, scanner_range, TargetsContainer::ESelectionType::Selectable); + if (keys.science_prev_target.getDown()) + targets.setPrev(scanner_position, scanner_range, TargetsContainer::ESelectionType::Selectable); } } diff --git a/src/screens/crew6/weaponsScreen.cpp b/src/screens/crew6/weaponsScreen.cpp index 998801605f..fa6e737264 100644 --- a/src/screens/crew6/weaponsScreen.cpp +++ b/src/screens/crew6/weaponsScreen.cpp @@ -142,29 +142,74 @@ void WeaponsScreen::onDraw(sp::RenderTarget& renderer) void WeaponsScreen::onUpdate() { - if (my_spaceship && isVisible()) + if (!my_spaceship || !isVisible()) return; + + // Target selection cycle keybinds. + // Select hostile targets. + if (keys.weapons_enemy_next_target.getDown()) { - if (keys.weapons_enemy_next_target.getDown()) + if (auto transform = my_spaceship.getComponent()) { - if (auto transform = my_spaceship.getComponent()) { - auto lrr = my_spaceship.getComponent(); - targets.setNext(transform->getPosition(), lrr ? lrr->short_range : 5000.0f, TargetsContainer::Targetable, FactionRelation::Enemy); - my_player_info->commandSetTarget(targets.get()); - } + auto lrr = my_spaceship.getComponent(); + targets.setNext( + transform->getPosition(), + lrr ? lrr->short_range : 5000.0f, + TargetsContainer::ESelectionType::Targetable, + TargetsContainer::KnownFriendOrFoe::KnownHostile + ); + my_player_info->commandSetTarget(targets.get()); } - if (keys.weapons_next_target.getDown()) + } + if (keys.weapons_enemy_prev_target.getDown()) + { + if (auto transform = my_spaceship.getComponent()) { - if (auto transform = my_spaceship.getComponent()) { - auto lrr = my_spaceship.getComponent(); - targets.setNext(transform->getPosition(), lrr ? lrr->short_range : 5000.0f, TargetsContainer::Targetable); - my_player_info->commandSetTarget(targets.get()); - } + auto lrr = my_spaceship.getComponent(); + targets.setPrev( + transform->getPosition(), + lrr ? lrr->short_range : 5000.0f, + TargetsContainer::ESelectionType::Targetable, + TargetsContainer::KnownFriendOrFoe::KnownHostile + ); + my_player_info->commandSetTarget(targets.get()); } - auto aim_adjust = keys.weapons_aim_left.getValue() - keys.weapons_aim_right.getValue(); - if (aim_adjust != 0.0f) + } + + // Select any non-friendly target. + if (keys.weapons_next_target.getDown()) + { + if (auto transform = my_spaceship.getComponent()) { - missile_aim->setValue(missile_aim->getValue() - 5.0f * aim_adjust); - tube_controls->setMissileTargetAngle(missile_aim->getValue()); + auto lrr = my_spaceship.getComponent(); + targets.setNext( + transform->getPosition(), + lrr ? lrr->short_range : 5000.0f, + TargetsContainer::ESelectionType::Targetable, + TargetsContainer::KnownFriendOrFoe::NotKnownFriendly + ); + my_player_info->commandSetTarget(targets.get()); } } + if (keys.weapons_prev_target.getDown()) + { + if (auto transform = my_spaceship.getComponent()) + { + auto lrr = my_spaceship.getComponent(); + targets.setPrev( + transform->getPosition(), + lrr ? lrr->short_range : 5000.0f, + TargetsContainer::ESelectionType::Targetable, + TargetsContainer::KnownFriendOrFoe::NotKnownFriendly + ); + my_player_info->commandSetTarget(targets.get()); + } + } + + // Manual missile aiming keybinds. + auto aim_adjust = keys.weapons_aim_left.getValue() - keys.weapons_aim_right.getValue(); + if (aim_adjust != 0.0f) + { + missile_aim->setValue(missile_aim->getValue() - 5.0f * aim_adjust); + tube_controls->setMissileTargetAngle(missile_aim->getValue()); + } }