Files
fs2open.github.com/code/missioneditor/common.h
T
Goober5000andClaude Opus 5 a159e67a10 share the loadout usage-list code between the two editors
Add generate_ship_usage_list_team alongside the weaponry twin that already existed in missioneditor/common, so both loadout editors can drop their TVT/non-TVT branches and simply iterate Num_teams.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-25 03:22:23 -04:00

167 lines
8.3 KiB
C++

#pragma once
#include "globalincs/globals.h"
#include "mission/missionmessage.h"
#include "ship/anchor_t.h"
// Default AWACS range applied when the nebula intensity is unset or invalid
constexpr float DEFAULT_NEBULA_RANGE = 3000.0f;
// Smallest meaningful change in an orientation input field (degrees)
constexpr float ORIENT_INPUT_THRESHOLD = 0.01f;
// Normalize a degree value into the range [-180, 180]
float normalize_degrees(float deg);
// Voice acting manager
#define INVALID_MESSAGE ((MMessage*)SIZE_MAX) // was originally SIZE_T_MAX but that wasn't available outside fred. May need more research.
enum class PersonaSyncIndex : int {
Wingman = 0, // <Wingman Personas>
NonWingman = 1, // <Non-Wingman Personas>
PersonasStart = 2 // indices >= 2 map to specific persona
};
extern char Voice_abbrev_briefing[NAME_LENGTH];
extern char Voice_abbrev_campaign[NAME_LENGTH];
extern char Voice_abbrev_command_briefing[NAME_LENGTH];
extern char Voice_abbrev_debriefing[NAME_LENGTH];
extern char Voice_abbrev_message[NAME_LENGTH];
extern char Voice_abbrev_mission[NAME_LENGTH];
extern bool Voice_no_replace_filenames;
extern char Voice_script_entry_format[NOTES_LENGTH];
extern int Voice_export_selection;
extern bool Voice_group_messages;
extern SCP_string Voice_script_default_string;
extern SCP_string Voice_script_instructions_string;
void time_to_mission_info_string(const std::tm* src, char* dest, size_t dest_max_len);
void stuff_special_arrival_anchor_name(char* buf, int iff_index, int restrict_to_players, bool retail_format);
void stuff_special_arrival_anchor_name(char* buf, int anchor_num, bool retail_format);
int anchor_to_target(anchor_t anchor);
anchor_t target_to_anchor(int target);
// Rebuild Starting_wings[], Squadron_wings[], TVT_wings[] from their parallel
// name arrays via wing_name_lookup.
void update_custom_wing_indexes();
// The _team variants clear the map first; the _wing variants accumulate into it
// (so callers that build a total across several wings must clear the map themselves).
void generate_ship_usage_list_team(int team, SCP_map<int, int>& usage);
void generate_ship_usage_list_wing(int wing_num, SCP_map<int, int>& usage);
void generate_weaponry_usage_list_team(int team, SCP_map<int, int>& usage);
void generate_weaponry_usage_list_wing(int wing_num, SCP_map<int, int>& usage);
// If Player_start_shipnum no longer refers to a valid player start ship, repoint it to the
// first remaining player start in the mission (or -1 if there are none). Call this after
// changing a ship to or from an OBJ_START via demotion, deletion, etc.
void ensure_valid_player_start_shipnum();
// Make the given object the sole player start, per single-player semantics: promote it to
// OBJ_START, demote every other player start to OBJ_SHIP, adjust Player_starts to match,
// and repoint Player_start_shipnum. Returns true if anything changed.
bool set_single_player_start(int objnum);
// Check whether the given name is empty, starts with '<', or conflicts with an existing ship,
// wing, waypoint path, jump node, or target priority group.
// Returns an empty string if the name is valid, otherwise a self-contained reason string
// (e.g. "The name is already being used by a wing"). The exclude parameters prevent matching
// against the entity currently being renamed.
SCP_string check_name_conflict(const char *entity_type, const char *name, int exclude_ship = -1, int exclude_wing = -1, int exclude_waypoint_list = -1, int exclude_jump_node = -1);
// Free the engine data that the editors keep for their whole session. Call at shutdown, while the graphics
// system is still up, since models own GPU buffers and cursors own bitmaps.
void editor_free_engine_data();
// Resolve a mission filename to its index in Campaign.missions[], lazy-loading the mission's goal/event name lists from disk if the
// FRED_LOAD_PENDING flag is still set. Returns -1 if the mission isn't in the campaign.
int load_and_find_campaign_mission(const char *mission_filename);
struct FredShipSlotConfig
{
char (*fred_alt_names)[NAME_LENGTH + 1] = nullptr;
char (*fred_callsigns)[NAME_LENGTH + 1] = nullptr;
int *cur_ship = nullptr;
};
// Move the ship currently in Ships[from] into Ships[to], updating every
// back-reference (Objects, Ai_info, Wings, Player_start_shipnum, Ship_registry,
// and editor-side fields supplied via cfg). Leaves Ships[from] empty.
// Preconditions: from != to, Ships[from].objnum >= 0, Ships[to].objnum < 0.
// No caller may hold a ship* to either slot across this call.
// Fields in cfg whose pointers are nullptr are skipped.
void reassign_ship_slot(int from, int to, const FredShipSlotConfig& cfg, bool resort_obj_list = true);
// Swap the contents of two slots. Both must be valid (Ships[a].objnum >= 0
// and Ships[b].objnum >= 0). Implemented as three calls to reassign_ship_slot
// via a temporary empty slot.
void swap_ship_slots(int a, int b, const FredShipSlotConfig& cfg);
// Move the item at position from_pos in slots to position to_pos, shifting the
// items in between by one position.
void rotate_ship_slots(const SCP_vector<int>& slots, int from_pos, int to_pos, const FredShipSlotConfig& cfg);
struct FredWingSlotConfig
{
int (*wing_objects)[MAX_SHIPS_PER_WING] = nullptr;
int *cur_wing = nullptr;
};
// Move the wing currently in Wings[from] into Wings[to], updating every
// back-reference (Ships[i].wingnum, Starting/Squadron/TVT_wings caches, and
// editor-side fields supplied via cfg). Leaves Wings[from] empty.
// Preconditions: from != to, Wings[from].wave_count > 0, Wings[to].wave_count == 0.
// No caller may hold a wing* to either slot across this call.
// Fields in cfg whose pointers are nullptr are skipped.
void reassign_wing_slot(int from, int to, const FredWingSlotConfig& cfg, bool update_wing_indexes = true);
// Swap the contents of two slots. Both must be valid (Wings[a].wave_count > 0
// and Wings[b].wave_count > 0). Implemented as three calls to
// reassign_wing_slot via a temporary empty slot.
void swap_wing_slots(int a, int b, const FredWingSlotConfig& cfg);
// Move the item at position from_pos in slots to position to_pos, shifting the
// items in between by one position.
void rotate_wing_slots(const SCP_vector<int>& slots, int from_pos, int to_pos, const FredWingSlotConfig& cfg);
// Restore the obj_used_list invariant for the OBJ_SHIP/OBJ_START subset:
// among ship-type entries, list order matches Ships[] index order.
void resort_ships_in_obj_used_list();
// Same, for the OBJ_PROP subset: among prop entries, obj_used_list order matches
// Props[] index order. UI lists that walk obj_used_list, like the Scene Browser,
// depend on this to show props in their reordered Props[] order.
void resort_props_in_obj_used_list();
// Props and waypoint paths live in SCP_vectors rather than the fixed
// Ships[]/Wings[] arrays, and their only index-based back-reference is the
// owning object's instance (everything else refers to them by name). So unlike
// the ship/wing slot helpers above, these reorder the elements directly and just
// re-point the OBJ_PROP / OBJ_WAYPOINT object instances.
// Move the prop at display position from_pos to to_pos within `slots` (the
// occupied Props[] indices, in display order), shifting the props in between by
// one and preserving their relative order. Props[] may contain empty nullopt
// holes; those stay put while the occupants are permuted among their slots.
// Also resorts obj_used_list so Scene Browser matches.
void rotate_prop_slots(const SCP_vector<int>& slots, int from_pos, int to_pos);
// Move the waypoint list at index from_pos to to_pos within Waypoint_lists,
// shifting the lists in between by one and preserving their relative order.
// Waypoint_lists is kept compact, so positions are plain indices.
void rotate_waypoint_lists(int from_pos, int to_pos);
// Move the jump node at display position from_pos to to_pos within `slots` (the
// live Jump_nodes[] indices, in display order), shifting the nodes in between by
// one and preserving their relative order. Unlike ships/props there is no
// object-instance back-reference to re-point: a jump node links to its object via
// CJumpNode::m_objnum, which travels with the node, and is looked up by
// objnum/name, and the Scene Browser and mission save both iterate Jump_nodes
// directly so permuting the occupants among their slots is all that is needed.
void rotate_jump_nodes(const SCP_vector<int>& slots, int from_pos, int to_pos);