Skip to content

Commit

Permalink
Merge pull request scp-fs2open#6492 from Goober5000/immobile_flag_mig…
Browse files Browse the repository at this point in the history
…ration_checks

add safeguards to the "immobile" flag migration
  • Loading branch information
Goober5000 authored Dec 29, 2024
2 parents f1271cd + 2f18741 commit c3e9099
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 4 deletions.
5 changes: 5 additions & 0 deletions code/mission/missionparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ SCP_vector<SCP_string> Parse_names;

SCP_vector<texture_replace> Fred_texture_replacements;

SCP_unordered_set<int> Fred_migrated_immobile_ships;

int Num_path_restrictions;
path_restriction_t Path_restrictions[MAX_PATH_RESTRICTIONS];

Expand Down Expand Up @@ -2863,6 +2865,9 @@ void resolve_parse_flags(object *objp, flagset<Mission::Parse_Object_Flags> &par
{
objp->flags.set(Object::Object_Flags::Dont_change_position);
objp->flags.set(Object::Object_Flags::Dont_change_orientation);

// keep track of migrated ships
Fred_migrated_immobile_ships.insert(objp->instance);
}
else
objp->flags.set(Object::Object_Flags::Immobile);
Expand Down
3 changes: 3 additions & 0 deletions code/mission/missionparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,9 @@ typedef struct texture_replace {

extern SCP_vector<texture_replace> Fred_texture_replacements;

// which ships have had the "immobile" flag migrated to "don't-change-position" and "don't-change-orientation"
extern SCP_unordered_set<int> Fred_migrated_immobile_ships;

typedef struct alt_class {
int ship_class;
int variable_index; // if set allows the class to be set by a variable
Expand Down
53 changes: 53 additions & 0 deletions code/parse/sexp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4241,6 +4241,59 @@ int check_sexp_potential_issues(int node, int *bad_node, SCP_string &issue_msg)
break;
}

// examine uses of alter-ship-flag and are-ship-flags-set with "immobile"
case OP_ALTER_SHIP_FLAG:
case OP_ARE_SHIP_FLAGS_SET:
{
Object::Object_Flags object_flag = Object::Object_Flags::NUM_VALUES;
Ship::Ship_Flags ship_flag = Ship::Ship_Flags::NUM_VALUES;
Mission::Parse_Object_Flags parse_obj_flag = Mission::Parse_Object_Flags::NUM_VALUES;
AI::AI_Flags ai_flag = AI::AI_Flags::NUM_VALUES;
bool immobile_used = false;

// check to see the flag is specified by the sexp (don't check to see what the flag may be applied to)
if (op_num == OP_ALTER_SHIP_FLAG)
{
auto flag_name = CTEXT(first_arg_node);
sexp_check_flag_arrays(flag_name, object_flag, ship_flag, parse_obj_flag, ai_flag);
if (object_flag == Object::Object_Flags::Immobile || parse_obj_flag == Mission::Parse_Object_Flags::OF_Immobile)
immobile_used = true;
}
else
{
for (int n = CDR(first_arg_node); n >= 0; n = CDR(n))
{
auto flag_name = CTEXT(n);
sexp_check_flag_arrays(flag_name, object_flag, ship_flag, parse_obj_flag, ai_flag);
if (object_flag == Object::Object_Flags::Immobile || parse_obj_flag == Mission::Parse_Object_Flags::OF_Immobile)
{
immobile_used = true;
break;
}
}
}

// now check if any ships are created with any of the flags
if (immobile_used)
{
for (const auto so : list_range(&Ship_obj_list))
{
const auto &obj = Objects[so->objnum];
if (obj.flags[Object::Object_Flags::Immobile, Object::Object_Flags::Dont_change_position, Object::Object_Flags::Dont_change_orientation])
{
issue_msg = "At least one ship (";
issue_msg += Ships[obj.instance].ship_name;
issue_msg += ") has \"Does Not Change Position\" and/or \"Does Not Change Orientation\" checked, while this ";
issue_msg += Sexp_nodes[node].text;
issue_msg += " operator uses the \"immobile\" flag. Be aware that all three flags are independent and setting/checking one flag will not "
"set/check another. For convenience, the set-mobile and set-immobile operators will clear conflicting flags, but alter-ship-flag will not.";
return SEXP_CHECK_POTENTIAL_ISSUE;
}
}
}
break;
}

default:
break;
}
Expand Down
17 changes: 17 additions & 0 deletions fred2/freddoc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,23 @@ bool CFREDDoc::load_mission(const char *pathname, int flags) {
Fred_view_wnd->MessageBox(msg.c_str());
}

// message 4: check for "immobile" flag migration
if (!Fred_migrated_immobile_ships.empty()) {
SCP_string msg = "The \"immobile\" ship flag has been superseded by the \"don't-change-position\", and \"don't-change-orientation\" flags. "
"All ships which previously had \"Does Not Move\" checked in the ship flags editor will now have both \"Does Not Change Position\" and "
"\"Does Not Change Orientation\" checked. After you close this dialog, the error checker will check for any potential issues, including "
"issues involving these flags.\n\nThe following ships have been migrated:";

for (int shipnum : Fred_migrated_immobile_ships) {
msg += "\n\t";
msg += Ships[shipnum].ship_name;
}

truncate_message_lines(msg, 30);
Fred_view_wnd->MessageBox(msg.c_str());
Error_checker_checks_potential_issues_once = true;
}

obj_merge_created_list();
objp = GET_FIRST(&obj_used_list);
while (objp != END_OF_LIST(&obj_used_list)) {
Expand Down
1 change: 1 addition & 0 deletions fred2/fredrender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ int Show_outlines = 0;
bool Draw_outlines_on_selected_ships = true;
bool Draw_outline_at_warpin_position = false;
bool Error_checker_checks_potential_issues = true;
bool Error_checker_checks_potential_issues_once = false;
int Show_stars = 1;
int Single_axis_constraint = 0;
int True_rw, True_rh;
Expand Down
1 change: 1 addition & 0 deletions fred2/fredrender.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ extern int Show_outlines; //!< Bool. If nonzero, draw each object's me
extern bool Draw_outlines_on_selected_ships; // If a ship is selected, draw mesh lines
extern bool Draw_outline_at_warpin_position; // Project an outline at the place where the ship will arrive after warping in
extern bool Error_checker_checks_potential_issues; // Error checker checks not only outright errors but also potential issues
extern bool Error_checker_checks_potential_issues_once; // Same as above, but only once, and independent of the selected option
extern int Show_stars; //!< Bool. If nonzero, draw the starfield, nebulas, and suns. Might also handle skyboxes
extern int Single_axis_constraint; //!< Bool. If nonzero, constrain movement to one axis
extern int Show_distances; //!< Bool. If nonzero, draw lines between each object and display their distance on the middle of each line
Expand Down
5 changes: 3 additions & 2 deletions fred2/fredview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3406,7 +3406,7 @@ int CFREDView::fred_check_sexp(int sexp, int type, const char *location, ...)
return 1;
}

if (Error_checker_checks_potential_issues)
if (Error_checker_checks_potential_issues || Error_checker_checks_potential_issues_once)
z = check_sexp_potential_issues(sexp, &faulty_node, issue_msg);
if (z)
{
Expand All @@ -3417,11 +3417,12 @@ int CFREDView::fred_check_sexp(int sexp, int type, const char *location, ...)
if (!bad_node_str.empty()) // the previous function adds a space at the end
bad_node_str.pop_back();

sprintf(error_buf, "Potential issue detected in %s:\n%s\n\n%s\n\n(Suspect node appears to be: %s)", location_buf.c_str(), issue_msg.c_str(), sexp_buf.c_str(), bad_node_str.c_str());
sprintf(error_buf, "Potential issue detected in %s:\n\n%s\n\n%s\n\n(Suspect node appears to be: %s)", location_buf.c_str(), issue_msg.c_str(), sexp_buf.c_str(), bad_node_str.c_str());

if (Fred_main_wnd->MessageBox(error_buf.c_str(), "Warning", MB_OKCANCEL | MB_ICONINFORMATION) != IDOK)
return 1;
}
Error_checker_checks_potential_issues_once = false;

return 0;
}
Expand Down
1 change: 1 addition & 0 deletions fred2/management.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,7 @@ void clear_mission(bool fast_reload)
set_physics_controls();

Event_annotations.clear();
Fred_migrated_immobile_ships.clear();

// free memory from all parsing so far -- see also the stop_parse() in player_select_close() which frees all tbls found during game_init()
stop_parse();
Expand Down
33 changes: 31 additions & 2 deletions qtfred/src/mission/Editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <starfield/nebula.h>
#include <object/objectdock.h>
#include <localization/fhash.h>
#include <scripting/global_hooks.h>

#include "iff_defs/iff_defs.h" // iff_init
#include "object/object.h" // obj_init
Expand Down Expand Up @@ -271,6 +272,26 @@ bool Editor::loadMission(const std::string& mission_name, int flags) {
{ DialogButton::Ok });
}

// message 4: check for "immobile" flag migration
if (!Fred_migrated_immobile_ships.empty()) {
SCP_string msg = "The \"immobile\" ship flag has been superseded by the \"don't-change-position\", and \"don't-change-orientation\" flags. "
"All ships which previously had \"Does Not Move\" checked in the ship flags editor will now have both \"Does Not Change Position\" and "
"\"Does Not Change Orientation\" checked. After you close this dialog, the error checker will check for any potential issues, including "
"issues involving these flags.\n\nThe following ships have been migrated:";

for (int shipnum : Fred_migrated_immobile_ships) {
msg += "\n\t";
msg += Ships[shipnum].ship_name;
}

truncate_message_lines(msg, 30);
_lastActiveViewport->dialogProvider->showButtonDialog(DialogType::Information,
"Ship Flag Migration",
msg,
{ DialogButton::Ok });
_lastActiveViewport->Error_checker_checks_potential_issues_once = true;
}

obj_merge_created_list();
objp = GET_FIRST(&obj_used_list);
while (objp != END_OF_LIST(&obj_used_list)) {
Expand Down Expand Up @@ -381,6 +402,12 @@ bool Editor::loadMission(const std::string& mission_name, int flags) {

missionLoaded(filepath);

// This hook will allow for scripts to know when a mission has been loaded
// which will then allow them to update any LuaEnums that may be related to sexps
if (scripting::hooks::FredOnMissionLoad->isActive()) {
scripting::hooks::FredOnMissionLoad->run();
}

return true;
}
void Editor::unmark_all() {
Expand Down Expand Up @@ -530,6 +557,7 @@ void Editor::clearMission(bool fast_reload) {
}

Event_annotations.clear();
Fred_migrated_immobile_ships.clear();

// free memory from all parsing so far -- see also the stop_parse() in player_select_close() which frees all tbls found during game_init()
stop_parse();
Expand Down Expand Up @@ -2644,7 +2672,7 @@ int Editor::fred_check_sexp(int sexp, int type, const char* location, ...) {
return 1;
}

if (_lastActiveViewport->Error_checker_checks_potential_issues)
if (_lastActiveViewport->Error_checker_checks_potential_issues || _lastActiveViewport->Error_checker_checks_potential_issues_once)
z = check_sexp_potential_issues(sexp, &faulty_node, issue_msg);
if (z)
{
Expand All @@ -2655,11 +2683,12 @@ int Editor::fred_check_sexp(int sexp, int type, const char* location, ...) {
if (!bad_node_str.empty()) // the previous function adds a space at the end
bad_node_str.pop_back();

sprintf(error_buf, "Potential issue detected in %s:\n%s\n\n%s\n\n(Suspect node appears to be: %s)", location_buf.c_str(), issue_msg.c_str(), sexp_buf.c_str(), bad_node_str.c_str());
sprintf(error_buf, "Potential issue detected in %s:\n\n%s\n\n%s\n\n(Suspect node appears to be: %s)", location_buf.c_str(), issue_msg.c_str(), sexp_buf.c_str(), bad_node_str.c_str());

if (_lastActiveViewport->dialogProvider->showButtonDialog(DialogType::Warning, "Warning", error_buf.c_str(), { DialogButton::Ok, DialogButton::Cancel }) != DialogButton::Ok)
return 1;
}
_lastActiveViewport->Error_checker_checks_potential_issues_once = false;

return 0;
}
Expand Down
1 change: 1 addition & 0 deletions qtfred/src/mission/EditorViewport.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ class EditorViewport {
bool Lookat_mode = false;
bool Move_ships_when_undocking = true;
bool Error_checker_checks_potential_issues = true;
bool Error_checker_checks_potential_issues_once = false;

Editor* editor = nullptr;
FredRenderer* renderer = nullptr;
Expand Down

0 comments on commit c3e9099

Please sign in to comment.