mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 08:15:59 -10:00
* always use exact match * custom gauges should use the type for colors with old preset files
486 lines
16 KiB
C++
486 lines
16 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _HUDCONFIG_H
|
|
#define _HUDCONFIG_H
|
|
|
|
#include "hud/hud.h"
|
|
#include "hud/hudshield.h"
|
|
#include "ui/ui.h"
|
|
|
|
class player;
|
|
class ship;
|
|
struct ai_info;
|
|
|
|
#define HUD_COLOR_PRESET_1 0
|
|
#define HUD_COLOR_PRESET_2 1
|
|
#define HUD_COLOR_PRESET_3 2
|
|
#define NUM_HUD_COLOR_PRESETS 3 // Number of default colors. Keep this up to date.
|
|
|
|
// specify the max distance that the radar should detect objects
|
|
// Index in Radar_ranges[] array to get values
|
|
|
|
#define RR_MAX_RANGES 3 // keep up to date
|
|
#define RR_SHORT 0
|
|
#define RR_LONG 1
|
|
#define RR_INFINITY 2
|
|
extern float Radar_ranges[RR_MAX_RANGES];
|
|
extern const char *Radar_range_text(int range_num);
|
|
|
|
class HC_gauge_mappings {
|
|
public:
|
|
static HC_gauge_mappings& get_instance()
|
|
{
|
|
static HC_gauge_mappings instance;
|
|
return instance;
|
|
}
|
|
|
|
// Prevent copying
|
|
HC_gauge_mappings(const HC_gauge_mappings&) = delete;
|
|
HC_gauge_mappings& operator=(const HC_gauge_mappings&) = delete;
|
|
|
|
// Numeric ID -> New String ID
|
|
SCP_string get_string_id_from_numeric_id(int numeric_id) const
|
|
{
|
|
auto it = gauge_map.find(numeric_id);
|
|
return (it != gauge_map.end()) ? it->second.second : "";
|
|
}
|
|
|
|
// HCF String Name -> New String ID
|
|
SCP_string get_string_id_from_hcf_id(const SCP_string& hcf_name) const
|
|
{
|
|
for (const auto& [id, mapping] : gauge_map) {
|
|
if (XSTR(mapping.first.first.c_str(), mapping.first.second) == hcf_name) {
|
|
return mapping.second;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
// New String ID -> Numeric ID (for saving to player file)
|
|
int get_numeric_id_from_string_id(const SCP_string& string_id) const
|
|
{
|
|
for (const auto& [id, mapping] : gauge_map) {
|
|
if (mapping.second == string_id) {
|
|
return id;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// New String ID -> HCF String Name (for saving HCF files)
|
|
SCP_string get_hcf_name_from_string_id(const SCP_string& string_id) const
|
|
{
|
|
for (const auto& [id, mapping] : gauge_map) {
|
|
if (mapping.second == string_id) {
|
|
return XSTR(mapping.first.first.c_str(), mapping.first.second);
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
private:
|
|
HC_gauge_mappings()
|
|
{
|
|
// Map the old gauge_config numeric IDs, the HCF file IDs (which, yes, were translated...), and the newer string
|
|
// IDs for the retail built-in gauges. Custom gauges will only have a string ID and do not need to be mapped.
|
|
gauge_map = {{0, {{"lead indicator", 249}, "Builtin::LeadIndicator"}},
|
|
{1, {{"target orientation", 250}, "Builtin::TargetOrientation"}},
|
|
{2, {{"closest attacking hostile", 251}, "Builtin::ClosestAttackingHostile"}},
|
|
{3, {{"current target direction", 252}, "Builtin::CurrentTargetDirection"}},
|
|
{4, {{"mission time", 253}, "Builtin::MissionTime"}},
|
|
{5, {{"reticle", 254}, "Builtin::Reticle"}},
|
|
{6, {{"throttle", 255}, "Builtin::Throttle"}},
|
|
{7, {{"radar", 256}, "Builtin::Radar"}},
|
|
{8, {{"target monitor", 257}, "Builtin::TargetMonitor"}},
|
|
{9, {{"center of reticle", 258}, "Builtin::CenterOfReticle"}},
|
|
{10, {{"extra target info", 259}, "Builtin::ExtraTargetInfo"}},
|
|
{11, {{"target shield", 260}, "Builtin::TargetShield"}},
|
|
{12, {{"player shield", 261}, "Builtin::PlayerShield"}},
|
|
{13, {{"power management", 262}, "Builtin::PowerManagement"}},
|
|
{14, {{"auto-target icon", 263}, "Builtin::AutoTargetIcon"}},
|
|
{15, {{"auto-speed-match icon", 264}, "Builtin::AutoSpeedMatchIcon"}},
|
|
{16, {{"weapons display", 265}, "Builtin::WeaponsDisplay"}},
|
|
{17, {{"monitoring view", 266}, "Builtin::MonitoringView"}},
|
|
{18, {{"directives view", 267}, "Builtin::DirectivesView"}},
|
|
{19, {{"threat gauge", 268}, "Builtin::ThreatGauge"}},
|
|
{20, {{"afterburner energy", 269}, "Builtin::AfterburnerEnergy"}},
|
|
{21, {{"weapons energy", 270}, "Builtin::WeaponsEnergy"}},
|
|
{22, {{"weapon linking", 271}, "Builtin::WeaponLinking"}},
|
|
{23, {{"target hull/shield icon", 272}, "Builtin::TargetHullShieldIcon"}},
|
|
{24, {{"offscreen indicator", 273}, "Builtin::OffscreenIndicator"}},
|
|
{25, {{"comm video", 274}, "Builtin::CommVideo"}},
|
|
{26, {{"damage display", 275}, "Builtin::DamageDisplay"}},
|
|
{27, {{"message output", 276}, "Builtin::MessageOutput"}},
|
|
{28, {{"locked missile direction", 277}, "Builtin::LockedMissileDirection"}},
|
|
{29, {{"countermeasures", 278}, "Builtin::Countermeasures"}},
|
|
{30, {{"objective notify", 279}, "Builtin::ObjectiveNotify"}},
|
|
{31, {{"wingmen status", 280}, "Builtin::WingmenStatus"}},
|
|
{32, {{"offscreen range", 281}, "Builtin::OffscreenRange"}},
|
|
{33, {{"kills gauge", 282}, "Builtin::KillsGauge"}},
|
|
{34, {{"attacking target count", 283}, "Builtin::AttackingTargetCount"}},
|
|
{35, {{"warning flash", 1459}, "Builtin::WarningFlash"}},
|
|
{36, {{"comm menu", 1460}, "Builtin::CommMenu"}},
|
|
{37, {{"support gauge", 1461}, "Builtin::SupportGauge"}},
|
|
{38, {{"lag gauge", 1462}, "Builtin::LagGauge"}}};
|
|
}
|
|
|
|
SCP_unordered_map<int, std::pair<std::pair<SCP_string, int>, SCP_string>> gauge_map;
|
|
};
|
|
|
|
/*!
|
|
* @brief Vector for storing the filenames of hud preset files
|
|
* @note main definition in hudconfig.cpp
|
|
*/
|
|
extern SCP_vector<SCP_string> HC_preset_filenames;
|
|
|
|
extern SCP_vector<SCP_string> observer_visible_gauges;
|
|
|
|
extern const int HC_gauge_config_coords[GR_NUM_RESOLUTIONS][4];
|
|
extern int HC_resize_mode;
|
|
|
|
/*!
|
|
* @brief get the gauge pointer for the given gauge index
|
|
*/
|
|
HudGauge* hud_config_get_gauge_pointer(const SCP_string& gauge_id);
|
|
|
|
/**
|
|
* @brief Contains core HUD configuration data
|
|
* @note Is not default init'd. Assumes new player, PLR, or CSG reads will correctly set data.
|
|
*/
|
|
typedef struct HUD_CONFIG_TYPE {
|
|
int rp_dist; // one of RR_ #defines above; Is the maxium radar view distance setting
|
|
bool is_observer; // 1 or 0, observer mode or not, respectively
|
|
int main_color; // the default HUD_COLOR selection for all gauges; each gauge may override this with a custom RGB
|
|
|
|
// Maps for HUD gauge configuration
|
|
SCP_unordered_map<SCP_string, color> gauge_colors; // Gauge-specific colors
|
|
SCP_unordered_map<SCP_string, bool> show_flags_map; // Show/hide state for gauges
|
|
SCP_unordered_map<SCP_string, bool> popup_flags_map; // Popup state for gauges
|
|
SCP_unordered_map<SCP_string, int> gauge_types; // Gauge types used for backup colors for custom gauges to preseve old behavior
|
|
|
|
static color default_white_color()
|
|
{
|
|
color white;
|
|
gr_init_alphacolor(&white, 255, 255, 255, 255);
|
|
return white;
|
|
}
|
|
|
|
// Methods for setting and getting gauge properties where getting will return a default value
|
|
|
|
void set_gauge_color(const SCP_string& gauge_id, const color& col)
|
|
{
|
|
gauge_colors[gauge_id] = col;
|
|
}
|
|
|
|
// Get the gauge color, the color based on its type, or white if the gauge is not found
|
|
color get_gauge_color(const SCP_string& gauge_id) const
|
|
{
|
|
auto it = gauge_colors.find(gauge_id);
|
|
|
|
// Got a match? Return it
|
|
if (it != gauge_colors.end()) {
|
|
return it->second;
|
|
}
|
|
|
|
// No match yet.. try using the gauge type
|
|
auto type_it = gauge_types.find(gauge_id);
|
|
if (type_it != gauge_types.end()) {
|
|
const HC_gauge_mappings& gauge_map = HC_gauge_mappings::get_instance();
|
|
|
|
it = gauge_colors.find(gauge_map.get_string_id_from_numeric_id(type_it->second));
|
|
if (it != gauge_colors.end()) {
|
|
return it->second;
|
|
}
|
|
}
|
|
|
|
// Still nothing.. return white
|
|
return default_white_color();
|
|
}
|
|
|
|
void set_gauge_type(const SCP_string& gauge_id, int type) {
|
|
gauge_types[gauge_id] = type;
|
|
}
|
|
|
|
void set_gauge_visibility(const SCP_string& gauge_id, bool visible)
|
|
{
|
|
show_flags_map[gauge_id] = visible;
|
|
}
|
|
|
|
// Get the gauge config visibility setting or false (invisible) if not found
|
|
bool is_gauge_visible(const SCP_string& gauge_id) const
|
|
{
|
|
auto it = show_flags_map.find(gauge_id);
|
|
return (it != show_flags_map.end()) ? it->second : false; // Default to invisible
|
|
}
|
|
|
|
void set_gauge_popup(const SCP_string& gauge_id, bool popup)
|
|
{
|
|
popup_flags_map[gauge_id] = popup;
|
|
}
|
|
|
|
// Get the gauge config popup setting or false if not found
|
|
bool is_gauge_popup(const SCP_string& gauge_id) const
|
|
{
|
|
auto it = popup_flags_map.find(gauge_id);
|
|
return (it != popup_flags_map.end()) ? it->second : false; // Default to not a popup
|
|
}
|
|
|
|
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
|
bool is_gauge_shown_in_config(const SCP_string& gauge_id) const
|
|
{
|
|
HudGauge* gauge = hud_config_get_gauge_pointer(gauge_id);
|
|
return gauge && gauge->getVisibleInConfig();
|
|
}
|
|
} HUD_CONFIG_TYPE;
|
|
|
|
extern HUD_CONFIG_TYPE HUD_config;
|
|
|
|
// HUD Color presets
|
|
typedef struct hc_col {
|
|
int r, g, b;
|
|
SCP_string name;
|
|
int xstr = -1;
|
|
} hc_col;
|
|
|
|
extern hc_col HC_colors[NUM_HUD_COLOR_PRESETS];
|
|
|
|
extern int HC_default_color;
|
|
extern SCP_string HC_default_preset_file;
|
|
|
|
|
|
/**
|
|
* @struct HC_gauge_setting
|
|
* @brief Contains core HUD configuration data
|
|
*/
|
|
struct HC_gauge_setting
|
|
{
|
|
bool use_iff_color; // if the gauge uses target IFF color for its color
|
|
bool can_popup; // if the gauge can use the popup method
|
|
bool use_tag_color; // If the gauge color respects target tagging?
|
|
|
|
HC_gauge_setting(bool iff, bool cp, bool cl) : use_iff_color(iff), can_popup(cp), use_tag_color(cl){}
|
|
};
|
|
|
|
class BoundingBox {
|
|
public:
|
|
int x1, x2, y1, y2;
|
|
|
|
// Default constructor (initializes to invalid state)
|
|
constexpr BoundingBox() : x1(-1), x2(-1), y1(-1), y2(-1) {}
|
|
|
|
// Constructor
|
|
constexpr BoundingBox(int nx1, int nx2, int ny1, int ny2) : x1(nx1), x2(nx2), y1(ny1), y2(ny2) {}
|
|
|
|
// Equality operator
|
|
bool operator==(const BoundingBox& other) const
|
|
{
|
|
return x1 == other.x1 && x2 == other.x2 && y1 == other.y1 && y2 == other.y2;
|
|
}
|
|
|
|
bool isOverlapping(const BoundingBox& other) const
|
|
{
|
|
return (x2 >= other.x1 && // Not completely to the left
|
|
x1 <= other.x2 && // Not completely to the right
|
|
y2 >= other.y1 && // Not completely above
|
|
y1 <= other.y2); // Not completely below
|
|
}
|
|
|
|
// Check if the bounding box is valid (no negative coordinates)
|
|
bool isValid() const
|
|
{
|
|
return x1 >= 0 && x2 >= 0 && y1 >= 0 && y2 >= 0;
|
|
}
|
|
|
|
// Static function to check if any bounding box in an array overlaps with a new one
|
|
static bool isOverlappingAny(const SCP_vector<std::pair<SCP_string, BoundingBox>>& mouse_coords, const BoundingBox& newBox, SCP_string self_id)
|
|
{
|
|
return std::any_of(mouse_coords.begin(), mouse_coords.end(), [&](const std::pair<SCP_string, BoundingBox>& item) {
|
|
const auto& [gauge_id, bbox] = item;
|
|
if (gauge_id == self_id) {
|
|
return false; // Skip checking against itself
|
|
}
|
|
return bbox.isValid() && bbox.isOverlapping(newBox);
|
|
});
|
|
}
|
|
};
|
|
|
|
extern char HC_wingam_gauge_status_names[MAX_SQUADRON_WINGS][32];
|
|
|
|
extern SCP_vector<std::pair<SCP_string, HudGauge*>> HC_gauge_map;
|
|
extern SCP_string HC_gauge_hot;
|
|
extern SCP_string HC_gauge_selected;
|
|
extern SCP_vector<std::pair<size_t, SCP_string>> HC_available_huds;
|
|
extern int HC_chosen_hud;
|
|
extern bool HC_select_all;
|
|
extern int HC_gauge_coordinates[6]; // x1, x2, y1, y2, w, h for gauge rendering
|
|
extern SCP_vector<std::pair<SCP_string, BoundingBox>> HC_gauge_mouse_coords;
|
|
|
|
extern int HC_talking_head_frame;
|
|
extern SCP_string HC_head_anim_filename;
|
|
extern bool HC_show_default_hud;
|
|
extern std::unordered_set<SCP_string> HC_ignored_huds;
|
|
extern SCP_map<SCP_string, std::array<SCP_string, num_shield_gauge_types>> HC_hud_shield_ships;
|
|
extern SCP_map<SCP_string, SCP_vector<SCP_string>> HC_hud_primary_weapons;
|
|
extern SCP_map<SCP_string, SCP_vector<SCP_string>> HC_hud_secondary_weapons;
|
|
|
|
|
|
/*!
|
|
* @brief init hud config screen, setting up the hud preview display
|
|
*
|
|
* param[in] API_Access whether or not this method has been called from the lua api
|
|
* param[in] x the x coord to render the preview display
|
|
* param[in] y the y coord to render the preview display
|
|
* param[in] w the width to render the preview display
|
|
* param[in] h the height to render the preview display
|
|
*/
|
|
void hud_config_init(bool API_Access = false, int x = 0, int y = 0, int w = -1, int h = -1);
|
|
|
|
/*!
|
|
* @brief do a hud config frame, including rendering the preview display and checking for button presses
|
|
*
|
|
* param[in] frametime unused
|
|
* param[in] API_Access whether or not this method has been called from the lua api
|
|
* param[in] mx mouse x coordinate
|
|
* param[in] my mouse y coordinate
|
|
*/
|
|
void hud_config_do_frame(float frametime, bool API_Access = false, int mx = 0, int my = 0);
|
|
|
|
/*!
|
|
* @brief close hud config and release all the bitmaps
|
|
*
|
|
* param[in] API_Access whether or not this method has been called from the lua api
|
|
*/
|
|
void hud_config_close(bool API_Access = false);
|
|
|
|
/*!
|
|
* @brief toggles selecting of all gauges for color modification
|
|
*
|
|
* param[bool] toggle true to toggle on, false for off
|
|
* param[in] API_Access whether or not this method has been called from the lua api
|
|
*/
|
|
void hud_config_select_all_toggle(bool toggle, bool API_Access = false);
|
|
|
|
/*!
|
|
* @brief sets no gauges as selected
|
|
*/
|
|
void hud_config_select_none();
|
|
|
|
/*!
|
|
* @brief sets no gauges as selected
|
|
*/
|
|
void hud_config_select_hud(bool next);
|
|
|
|
/*!
|
|
* @brief init the list of preset files found by cfile
|
|
*/
|
|
void hud_config_preset_init();
|
|
|
|
/*!
|
|
* @brief set the entire hud to the default setting or the filename provided
|
|
*
|
|
* param[in] filename the preset filename to use as the default
|
|
*/
|
|
void hud_set_default_hud_config(player* p, const SCP_string& filename);
|
|
|
|
/*!
|
|
* @brief delete a preset file and remove it from the preset vector
|
|
*/
|
|
void hud_config_delete_preset(SCP_string filename);
|
|
|
|
/*!
|
|
* @brief set gauge flags
|
|
*
|
|
* param[in] gauge_index the gauge to modify
|
|
* param[in] on_flag if the gauge is on or off, 1 for on, 0 for off
|
|
* param[in] popup_flag if the gauge is set to popup, 1 for popup, 0 otherwise
|
|
*/
|
|
void hud_config_set_gauge_flags(const SCP_string& gauge, bool on_flag, bool popup_flag);
|
|
|
|
void hud_config_restore();
|
|
void hud_config_backup();
|
|
void hud_config_as_observer(ship *shipp,ai_info *aif);
|
|
|
|
void hud_config_as_player();
|
|
|
|
/*!
|
|
* @brief leave hud config without accepting the player's changes
|
|
*/
|
|
void hud_config_cancel(bool change_state = true);
|
|
|
|
/*!
|
|
* @brief leave hud config and save the player's changes
|
|
*/
|
|
void hud_config_commit();
|
|
|
|
void hud_config_record_color(int color);
|
|
void hud_config_set_color(int color);
|
|
|
|
/*!
|
|
* @brief load a preset file to the hud gauges
|
|
*/
|
|
void hud_config_color_load(const char *name);
|
|
|
|
/*!
|
|
* @brief save the current hud gauges settings to a preset file
|
|
*/
|
|
void hud_config_color_save(const char* name, int version = 2);
|
|
|
|
/*!
|
|
* @brief same as hud_config_covert_coords but only returns the scale and doesn't convert any coords
|
|
*/
|
|
float hud_config_get_scale(int baseW, int baseH);
|
|
|
|
/*!
|
|
* @brief converts a set of coordinates to HUD Config's rendering coordinates
|
|
*/
|
|
std::pair<int, int> hud_config_convert_coords(int x, int y, float scale);
|
|
|
|
/*!
|
|
* @brief converts a set of coordinates to HUD Config's rendering coordinates
|
|
*/
|
|
std::pair<float, float> hud_config_convert_coords(float x, float y, float scale);
|
|
|
|
/*!
|
|
* @brief convert the given HUD gauge position coordinates to a set more appropriate for the HUD Config UI and return the smaller scale value used
|
|
* so that other offsets and positions can be multiplied in turn
|
|
*/
|
|
std::tuple<int, int, float> hud_config_convert_coord_sys(int x, int y, int baseW, int baseH);
|
|
|
|
/*!
|
|
* @brief convert the given HUD gauge position coordinates to a set more appropriate for the HUD Config UI and return
|
|
* the smaller scale value used so that other offsets and positions can be multiplied in turn
|
|
*/
|
|
std::tuple<float, float, float> hud_config_convert_coord_sys(float x, float y, int baseW, int baseH);
|
|
|
|
/*!
|
|
* @brief save gauge coords during rendering time so hud config can check if the mouse is hovering over the gauge
|
|
*/
|
|
void hud_config_set_mouse_coords(const SCP_string& gauge_id, int x1, int x2, int y1, int y2);
|
|
|
|
/*!
|
|
* @brief Function to calculate screen coordinates based on angle. Used for radial positioning gauges
|
|
*/
|
|
std::pair<float, float> hud_config_calc_coords_from_angle(float angle_degrees, int centerX, int centerY, float radius);
|
|
|
|
/*!
|
|
* @brief try to find an angle with no overlapping mouse coordinates for target-related gauges
|
|
*/
|
|
float hud_config_find_valid_angle(const SCP_string& gauge, float initial_angle, int centerX, int centerY, float radius);
|
|
|
|
/*!
|
|
* @brief generage a custom gauge id
|
|
*/
|
|
SCP_string create_custom_gauge_id(const SCP_string& gauge_name);
|
|
|
|
#endif
|
|
|