diff --git a/code/iff_defs/iff_defs.cpp b/code/iff_defs/iff_defs.cpp index 88244e167b5..bf20649bccb 100644 --- a/code/iff_defs/iff_defs.cpp +++ b/code/iff_defs/iff_defs.cpp @@ -13,6 +13,7 @@ #include "mission/missionparse.h" #include "parse/parselo.h" #include "ship/ship.h" +#include "options/Option.h" extern int radar_target_id_flags; @@ -40,6 +41,21 @@ flag_def_list rti_flags[] = { int Num_rti_flags = sizeof(rti_flags)/sizeof(flag_def_list); +static bool AccessiblitySupported = false; + +// used by In-Game Options menu +static bool AccessibilityEnabled = false; + +static auto AccessibilityOption = options::OptionBuilder("Game.IffAccessibility", + std::pair{"Accessibility IFF Colors", 1855}, + std::pair{"Enables or disables IFF Accessibility color overrides", 1856}) + .category(std::make_pair("Game", 1824)) + .default_val(false) + .level(options::ExpertLevel::Advanced) + .bind_to_once(&AccessibilityEnabled) + .importance(60) + .finish(); + /** * Borrowed from ship.cpp, ship_iff_init_colors * @@ -113,6 +129,8 @@ struct observed_color_t { static SCP_vector> observed_color_table; +static SCP_vector> accessibility_observed_color_table; + void resolve_iff_data() { // first get the traitor @@ -157,13 +175,30 @@ void resolve_iff_data() int target_iff = iff_lookup(observed_color.iff_name); // valid? - if (target_iff >= 0) + if (target_iff >= 0) { iff->observed_color_map[target_iff] = observed_color.color_index; - else + } else{ + Warning(LOCATION, + "Observed color IFF %s not found for IFF %s in iff_defs.tbl!\n", + observed_color.iff_name, + iff->iff_name); + } + } + + // resolve the accessibility observed color list names + for (const auto& observed_color : accessibility_observed_color_table[cur_iff]) { + // find out who + int target_iff = iff_lookup(observed_color.iff_name); + + // valid? + if (target_iff >= 0) { + iff->accessibility_observed_color_map[target_iff] = observed_color.color_index; + } else { Warning(LOCATION, "Observed color IFF %s not found for IFF %s in iff_defs.tbl!\n", observed_color.iff_name, iff->iff_name); + } } // resolve the all teams at war relationships @@ -246,6 +281,10 @@ void parse_iff_table(const char* filename) stuff_string(traitor_name, F_NAME, NAME_LENGTH); } + if (optional_string("$Accessibility Supported:")) { + stuff_boolean(&AccessiblitySupported); + } + int rgb[3]; // check if alternate colours are wanted to be used for these @@ -435,9 +474,12 @@ void parse_iff_table(const char* filename) Iff_info.push_back(ifft); attack_names.emplace_back(); observed_color_table.emplace_back(); + accessibility_observed_color_table.emplace_back(); iffp = &Iff_info[Iff_info.size() - 1]; //Initialize this to white for new IFFs iffp->color_index = iff_init_color(255, 255, 255); + // Initialize this to white for new IFFs + iffp->accessibility_color_index = iff_init_color(255, 255, 255); //Make sure flags are reset for new IFFs iffp->default_parse_flags.reset(); } @@ -450,6 +492,12 @@ void parse_iff_table(const char* filename) iffp->color_index = iff_init_color(rgb[0], rgb[1], rgb[2]); } + // get the accessiblity iff color + if (optional_string_either("$Accessibility Colour:", "$Accessibility Color:") != -1) { + stuff_int_list(rgb, 3, RAW_INTEGER_TYPE); + iffp->accessibility_color_index = iff_init_color(rgb[0], rgb[1], rgb[2]); + } + // get relationships between IFFs ------------------------------------- @@ -470,6 +518,18 @@ void parse_iff_table(const char* filename) observed_color_table[cur_iff].back().color_index = iff_init_color(rgb[0], rgb[1], rgb[2]); } + // get the list of accessibility observed colors + while (optional_string("+Accessibility Sees")) { + accessibility_observed_color_table[cur_iff].emplace_back(); + // get iff observed + stuff_string_until(accessibility_observed_color_table[cur_iff].back().iff_name, "As:", NAME_LENGTH); + required_string("As:"); + + // get color observed + stuff_int_list(rgb, 3, RAW_INTEGER_TYPE); + accessibility_observed_color_table[cur_iff].back().color_index = iff_init_color(rgb[0], rgb[1], rgb[2]); + } + // get F3 override iffp->hotkey_team = IFF_hotkey_team::Default; if (optional_string("+Hotkey Team:")) @@ -551,6 +611,11 @@ void iff_init() // parse any modular tables parse_modular_table("*-iff.tbm", parse_iff_table); + if (!AccessiblitySupported) { + options::OptionsManager::instance()->removeOption(AccessibilityOption); + AccessibilityEnabled = false; + } + // now resolve the relationships resolve_iff_data(); } @@ -665,14 +730,29 @@ color *iff_get_color(int color_index, int is_bright) */ color *iff_get_color_by_team(int team, int seen_from_team, int is_bright) { - Assert(team >= 0 && team < (int)Iff_info.size()); - Assert(seen_from_team < (int)Iff_info.size()); - Assert(is_bright == 0 || is_bright == 1); + Assertion(SCP_vector_inbounds(Iff_info, team), "Cannot get color by team because team is invalid. Get a coder!"); + Assertion((is_bright == 0 || is_bright == 1), "Error with brightness selection when getting color. Get a coder!"); + + int color_index; + SCP_map color_map; + + if (AccessibilityEnabled) { + color_index = Iff_info[team].accessibility_color_index; + if (SCP_vector_inbounds(Iff_info, seen_from_team)) { + color_map = Iff_info[seen_from_team].accessibility_observed_color_map; + } + } else { + color_index = Iff_info[team].color_index; + if (SCP_vector_inbounds(Iff_info, seen_from_team)) { + color_map = Iff_info[seen_from_team].observed_color_map; + } + } // is this guy being seen by anyone? - if (seen_from_team < 0) - return is_bright == 0 ? &Iff_colors[Iff_info[team].color_index].first : &Iff_colors[Iff_info[team].color_index].second; + if (seen_from_team < 0) { + return is_bright == 0 ? &Iff_colors[color_index].first : &Iff_colors[color_index].second; + } // Goober5000 - base the following on "sees X as" from iff code // c.f. AL's comment: @@ -682,13 +762,17 @@ color *iff_get_color_by_team(int team, int seen_from_team, int is_bright) // drawn friendly. If the team is different than the player's, then draw the // appropriate IFF. + // This goes here because seen_from_team can validly be a negative number. In that case color_map is undefined + // but that doesn't matter because we return in the statement above here. Below here, color_map needs to be defined + // which will happen if seen_from_team is valid. + Assertion(SCP_vector_inbounds(Iff_info, seen_from_team), "Cannot get color because seen_from_team is invalid. Get a coder!"); // assume an observed color is defined; if not, use normal color - auto it = Iff_info[seen_from_team].observed_color_map.find(team); - int color_index = Iff_info[team].color_index; + auto it = color_map.find(team); - if (it != Iff_info[seen_from_team].observed_color_map.end()) + if (it != color_map.end()) { color_index = it->second; + } return is_bright == 0 ? &Iff_colors[color_index].first : &Iff_colors[color_index].second; } @@ -700,23 +784,43 @@ color *iff_get_color_by_team(int team, int seen_from_team, int is_bright) */ color *iff_get_color_by_team_and_object(int team, int seen_from_team, int is_bright, object *objp) { - Assert(team >= 0 && team < (int)Iff_info.size()); - Assert(seen_from_team < (int)Iff_info.size()); - Assert(is_bright == 0 || is_bright == 1); + Assertion(SCP_vector_inbounds(Iff_info, team), "Cannot get color by team because team is invalid. Get a coder!"); + Assertion((is_bright == 0 || is_bright == 1), "Error with brightness selection when getting color. Get a coder!"); - int alt_color_index = -1; + int color_index; + SCP_map color_map; + + if (AccessibilityEnabled) { + color_index = Iff_info[team].accessibility_color_index; + if (SCP_vector_inbounds(Iff_info, seen_from_team)) { + color_map = Iff_info[seen_from_team].accessibility_observed_color_map; + } + } else { + color_index = Iff_info[team].color_index; + if (SCP_vector_inbounds(Iff_info, seen_from_team)) { + color_map = Iff_info[seen_from_team].observed_color_map; + } + } // is this guy being seen by anyone? - if (seen_from_team < 0) - return is_bright == 0 ? &Iff_colors[Iff_info[team].color_index].first : &Iff_colors[Iff_info[team].color_index].second; + if (seen_from_team < 0) { + return is_bright == 0 ? &Iff_colors[color_index].first : &Iff_colors[color_index].second; + } + + // This goes here because seen_from_team can validly be a negative number. In that case color_map is undefined + // but that doesn't matter because we return in the statement above here. Below here, color_map needs to be defined + // which will happen if seen_from_team is valid. + Assertion(SCP_vector_inbounds(Iff_info, seen_from_team), "Cannot get color because seen_from_team is invalid. Get a coder!"); - int color_index = -1; + int this_color_index = -1; { - auto it = Iff_info[seen_from_team].observed_color_map.find(team); - if (it != Iff_info[seen_from_team].observed_color_map.end()) - color_index = it->second; + auto it = color_map.find(team); + if (it != color_map.end()) + this_color_index = it->second; } + int alt_color_index = -1; + // switch in case some sort of parent iff color inheritance for example for bombs is wanted... switch(objp->type) { @@ -740,11 +844,12 @@ color *iff_get_color_by_team_and_object(int team, int seen_from_team, int is_bri } // temporary solution.... - if (alt_color_index >= 0) - color_index = alt_color_index; - if (color_index < 0) - color_index = Iff_info[team].color_index; + if (alt_color_index >= 0) { + this_color_index = alt_color_index; + } else { + this_color_index = color_index; + } - return is_bright == 0 ? &Iff_colors[color_index].first : &Iff_colors[color_index].second; + return is_bright == 0 ? &Iff_colors[this_color_index].first : &Iff_colors[this_color_index].second; } diff --git a/code/iff_defs/iff_defs.h b/code/iff_defs/iff_defs.h index 9c1f9c196c3..6a4972339ef 100644 --- a/code/iff_defs/iff_defs.h +++ b/code/iff_defs/iff_defs.h @@ -38,11 +38,13 @@ typedef struct iff_info { // required stuff char iff_name[NAME_LENGTH]; int color_index; // treat this as private and use iff_get_color or iff_get_color_by_team + int accessibility_color_index; // relationships int attackee_bitmask; // treat this as private and use iff_get_attackee_mask or iff_x_attacks_y int attackee_bitmask_all_teams_at_war; // treat this as private and use iff_get_attackee_mask or iff_x_attacks_y SCP_map observed_color_map; // treat this as private and use iff_get_color or iff_get_color_by_team + SCP_map accessibility_observed_color_map; IFF_hotkey_team hotkey_team; // flags diff --git a/code/localization/localize.cpp b/code/localization/localize.cpp index 72215d55612..d12c9431420 100644 --- a/code/localization/localize.cpp +++ b/code/localization/localize.cpp @@ -64,7 +64,7 @@ bool *Lcl_unexpected_tstring_check = nullptr; // NOTE: with map storage of XSTR strings, the indexes no longer need to be contiguous, // but internal strings should still increment XSTR_SIZE to avoid collisions. // retail XSTR_SIZE = 1570 -// #define XSTR_SIZE 1855 // This is the next available ID +// #define XSTR_SIZE 1857 // This is the next available ID // struct to allow for strings.tbl-determined x offset