Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 27 additions & 9 deletions code/mission/missionparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ SCP_vector<SCP_string> Parse_names;

SCP_vector<SCP_string> Mission_parse_warnings;

// true while a mission is being parsed and post-processed
bool Parsing_mission = false;

// Routes a parse-time auto-correction notice to the right surface for the app:
// outside QtFRED, the existing Warning(LOCATION, ...) popup; inside QtFRED, the
// Mission_parse_warnings queue so the ErrorChecker can present it without a popup.
Expand Down Expand Up @@ -7534,6 +7537,8 @@ bool parse_main(const char *mission_name, int flags)

Assert(Ship_info.size() <= MAX_SHIP_CLASSES);

Parsing_mission = true;

do {
// don't do this for imports
if (!(flags & MPF_IMPORT_FSM)) {
Expand Down Expand Up @@ -7585,6 +7590,8 @@ bool parse_main(const char *mission_name, int flags)
}
} while (0);

Parsing_mission = false;

if (!Fred_running)
strcpy_s(Mission_filename, mission_name);

Expand Down Expand Up @@ -8026,6 +8033,17 @@ int mission_parse_get_multi_mission_info( const char *filename )
return The_mission.num_players;
}

static p_object *mission_parse_get_arrival_ship_sub(const char *name)
{
for (auto p_objp : list_range(&Ship_arrival_list))
{
if (!stricmp(p_objp->name, name))
return p_objp; // still on the arrival list
}

return nullptr;
}

/**
* @brief Returns the parse object on the ship arrival list associated with the given name.
* @param[in] name The name of the object
Expand All @@ -8036,18 +8054,18 @@ int mission_parse_get_multi_mission_info( const char *filename )
*/
p_object *mission_parse_get_arrival_ship(const char *name)
{
p_object *p_objp;

if (name == nullptr)
return nullptr;

for (p_objp = GET_FIRST(&Ship_arrival_list); p_objp != END_OF_LIST(&Ship_arrival_list); p_objp = GET_NEXT(p_objp))
{
if (!stricmp(p_objp->name, name))
{
return p_objp; // still on the arrival list
}
}
// try the normal lookup
auto p_objp = mission_parse_get_arrival_ship_sub(name);
if (p_objp)
return p_objp;

// also search for ship names hashed using the legacy format
SCP_string legacy_hashed;
if (wing_bash_legacy_hashed_ship_name(legacy_hashed, name))
return mission_parse_get_arrival_ship_sub(legacy_hashed.c_str());

return nullptr;
}
Expand Down
3 changes: 3 additions & 0 deletions code/mission/missionparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,9 @@ extern SCP_vector<SCP_string> Parse_names;
// silently buried. Outside of QtFRED these sites still call Warning(LOCATION, ...).
extern SCP_vector<SCP_string> Mission_parse_warnings;

// true while a mission is being parsed and post-processed
extern bool Parsing_mission;

extern char Player_start_shipname[NAME_LENGTH];
extern int Player_start_shipnum;
extern p_object *Player_start_pobject;
Expand Down
10 changes: 9 additions & 1 deletion code/parse/sexp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5846,7 +5846,15 @@ const ship_registry_entry *eval_ship(int node)
return eval_ship(arg_node);
}

auto ship_it = Ship_registry_map.find(CTEXT(node));
// look up the ship in the ship registry
auto ship_name = CTEXT(node);
auto ship_it = Ship_registry_map.find(ship_name);
if (ship_it == Ship_registry_map.end())
{
SCP_string legacy_hashed;
if (wing_bash_legacy_hashed_ship_name(legacy_hashed, ship_name))
ship_it = Ship_registry_map.find(legacy_hashed);
}
if (ship_it != Ship_registry_map.end())
{
// cache the value if it can't change later
Expand Down
94 changes: 89 additions & 5 deletions code/ship/ship.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,19 @@ ship_info* ship_registry_entry::sip() const
}
}

int ship_registry_entry::ship_class_index() const
{
if (shipnum >= 0)
return Ships[shipnum].ship_info_index;
else if (pobj_num >= 0)
return Parse_objects[pobj_num].ship_class;
else
{
Assertion(false, "A ship registry entry must have either a parse object or a ship!");
return -1;
}
}

SCP_vector<ship_registry_entry> Ship_registry;
SCP_unordered_map<SCP_string, int, SCP_string_lcase_hash, SCP_string_lcase_equal_to> Ship_registry_map;

Expand Down Expand Up @@ -268,6 +281,15 @@ bool ship_registry_exists(int index)
const ship_registry_entry *ship_registry_get(const char *name)
{
auto ship_it = Ship_registry_map.find(name);

// also search for ship names hashed using the legacy format
if (ship_it == Ship_registry_map.end())
{
SCP_string legacy_hashed;
if (wing_bash_legacy_hashed_ship_name(legacy_hashed, name))
ship_it = Ship_registry_map.find(legacy_hashed);
}

if (ship_it != Ship_registry_map.end())
return &Ship_registry[ship_it->second];

Expand All @@ -277,6 +299,15 @@ const ship_registry_entry *ship_registry_get(const char *name)
const ship_registry_entry *ship_registry_get(const SCP_string &name)
{
auto ship_it = Ship_registry_map.find(name);

// also search for ship names hashed using the legacy format
if (ship_it == Ship_registry_map.end())
{
SCP_string legacy_hashed;
if (wing_bash_legacy_hashed_ship_name(legacy_hashed, name.c_str()))
ship_it = Ship_registry_map.find(legacy_hashed);
}

if (ship_it != Ship_registry_map.end())
return &Ship_registry[ship_it->second];

Expand Down Expand Up @@ -8645,6 +8676,15 @@ void ship_delete( object * obj )
shipp->weapons.primary_bank_external_model_instance[i] = -1;
}
}

// In FRED, clean up the registry so that stale references don't stick around. Conversely,
// in FSO, we need to keep the registry entry so that ships will still be known in the debriefing.
if (Fred_running)
{
auto ship_it = Ship_registry_map.find(shipp->ship_name);
if (ship_it != Ship_registry_map.end())
Ship_registry_map.erase(ship_it); // don't erase the vector entry to avoid clobbering other indexes
}
}

/**
Expand Down Expand Up @@ -15028,6 +15068,34 @@ void wing_bash_ship_name(ship *shipp, const wing *wingp, int ordinal, bool reset
}
}

bool wing_bash_legacy_hashed_ship_name(SCP_string &dest, const char *src)
{
// missions might have ships within wings that were saved using the legacy hash format, with the hash suffix at the end
auto hash = get_pointer_to_first_hash_symbol(src);
if (hash && *(hash + 1) != '\0')
{
// find the run of digits immediately preceding the hash
auto digits = hash;
while (digits > src && isdigit(static_cast<unsigned char>(*(digits - 1))))
digits--;

// the ordinal must be at least one digit, preceded by a space, preceded by the wing name
if (digits < hash && digits > (src + 1) && *(digits - 1) == ' ')
{
// move the ordinal from before the hash to the end of the name
dest.assign(src, digits - 1);
dest += hash;
dest += ' ';
dest.append(digits, hash);

// we changed it
return true;
}
}

return false;
}

/**
* Return the object index of the ship with name *name.
*/
Expand Down Expand Up @@ -15251,10 +15319,7 @@ int ship_info_lookup(const char *token)
return ship_info_lookup_sub(name);
}

/**
* Return the ship index of the ship with name *name.
*/
int ship_name_lookup(const char *name, int inc_players)
static int ship_name_lookup_sub(const char *name, int inc_players)
{
Assertion(name != nullptr, "NULL name passed to ship_name_lookup");

Expand All @@ -15272,7 +15337,26 @@ int ship_name_lookup(const char *name, int inc_players)
return -1;
}

int ship_type_name_lookup_sub(const char *name)
/**
* Return the ship index of the ship with name *name.
*/
int ship_name_lookup(const char *name, int inc_players)
{
// try the normal lookup
auto idx = ship_name_lookup_sub(name, inc_players);
if (idx >= 0)
return idx;

// also search for ship names hashed using the legacy format
SCP_string legacy_hashed;
if (wing_bash_legacy_hashed_ship_name(legacy_hashed, name))
return ship_name_lookup_sub(legacy_hashed.c_str(), inc_players);

// couldn't find it
return -1;
}

static int ship_type_name_lookup_sub(const char *name)
{
Assertion(name != nullptr, "NULL name passed to ship_type_name_lookup");

Expand Down
3 changes: 3 additions & 0 deletions code/ship/ship.h
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,7 @@ struct ship_registry_entry
ship* shipp_or_null() const;

ship_info* sip() const;
int ship_class_index() const;
};

extern SCP_vector<ship_registry_entry> Ship_registry;
Expand Down Expand Up @@ -1876,6 +1877,8 @@ extern void wing_bash_ship_name(SCP_string &ship_name, const char *wing_name, in
extern void wing_bash_ship_name(char *ship_name, const char *wing_name, int ordinal);
extern void wing_bash_ship_name(p_object *p_objp, const wing *wingp, int ordinal, bool reset_display_name_if_normal = false);
extern void wing_bash_ship_name(ship *shipp, const wing *wingp, int ordinal, bool reset_display_name_if_normal = false);
extern bool wing_bash_legacy_hashed_ship_name(SCP_string &dest, const char *src);

extern int Player_ship_class;

// Do the special effect for energy dissipating into the shield for a hit.
Expand Down
10 changes: 1 addition & 9 deletions fred2/freddoc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,15 +331,7 @@ bool CFREDDoc::load_mission(const char *pathname, int flags) {
wing_bash_ship_name(name, Wings[i].name, j + 1);
old_name = Ships[Wings[i].ship_index[j]].ship_name;
if (stricmp(name, old_name) != 0) { // need to fix name
update_sexp_references(old_name, name);
ai_update_goal_references(sexp_ref_type::SHIP, old_name, name);
update_texture_replacements(old_name, name);
int k = find_item_with_string(Reinforcements, &reinforcements::name, old_name);
if (k >= 0) {
Assert(strlen(name) < NAME_LENGTH);
strcpy_s(Reinforcements[k].name, name);
}

rename_ship(Wings[i].ship_index[j], name);
// bash it again so that we handle display names if needed
wing_bash_ship_name(&Ships[Wings[i].ship_index[j]], &Wings[i], j + 1, true);
}
Expand Down
10 changes: 1 addition & 9 deletions qtfred/src/mission/Editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,15 +337,7 @@ bool Editor::loadMission(const std::string& mission_name, int flags) {
wing_bash_ship_name(name, Wings[i].name, j + 1);
old_name = Ships[Wings[i].ship_index[j]].ship_name;
if (stricmp(name, old_name) != 0) { // need to fix name
update_sexp_references(old_name, name);
ai_update_goal_references(sexp_ref_type::SHIP, old_name, name);
update_texture_replacements(old_name, name);
int k = find_item_with_string(Reinforcements, &reinforcements::name, old_name);
if (k >= 0) {
Assert(strlen(name) < NAME_LENGTH);
strcpy_s(Reinforcements[k].name, name);
}

rename_ship(Wings[i].ship_index[j], name);
// bash it again so that we handle display names if needed
wing_bash_ship_name(&Ships[Wings[i].ship_index[j]], &Wings[i], j + 1, true);
}
Expand Down
Loading