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
8 changes: 4 additions & 4 deletions code/mission/missionparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ flag_def_list_new<Mission::Mission_Flags> Parse_mission_flags[] = {
{"All Teams at War", Mission::Mission_Flags::All_attack, true, false},
{"Use Autopilot Cinematics", Mission::Mission_Flags::Use_ap_cinematics, true, false},
{"Deactivate Hardcoded Autopilot", Mission::Mission_Flags::Deactivate_ap, true, false},
{"Toggle Showing Goals In Briefing", Mission::Mission_Flags::Toggle_showing_goals, true, false},
{"Toggle Showing Objectives In Briefing", Mission::Mission_Flags::Toggle_showing_goals, true, false},
{"Mission End to Mainhall", Mission::Mission_Flags::End_to_mainhall, true, false},
{"Override #Command with Command Info", Mission::Mission_Flags::Override_hashcommand, true, true},
{"Toggle Starting in Chase View", Mission::Mission_Flags::Toggle_start_chase_view, true, false},
Expand Down Expand Up @@ -424,7 +424,7 @@ parse_object_flag_description<Mission::Mission_Flags> Parse_mission_flag_descrip
{Mission::Mission_Flags::All_attack, "All teams target each other"},
{Mission::Mission_Flags::Use_ap_cinematics, "Use autopilot cinematics"},
{Mission::Mission_Flags::Deactivate_ap, "Deactivate hardcoded autopilot"},
{Mission::Mission_Flags::Toggle_showing_goals, "Show mission goals for training missions, hide otherwise"},
{Mission::Mission_Flags::Toggle_showing_goals, "Show mission objectives for training missions, hide otherwise"},
{Mission::Mission_Flags::End_to_mainhall, "Return to the mainhall after debrief instead of starting the next mission"},
{Mission::Mission_Flags::Override_hashcommand, "Override #Command with the Command info in Mission Specs"},
{Mission::Mission_Flags::Toggle_start_chase_view, "Toggles whether the player starts the mission in chase view"},
Expand Down Expand Up @@ -506,7 +506,7 @@ flag_def_list_new<Mission::Parse_Object_Flags> Parse_object_flags[] = {

parse_object_flag_description<Mission::Parse_Object_Flags> Parse_object_flag_descriptions[] = {
{ Mission::Parse_Object_Flags::SF_Cargo_known, "If set, the ship's cargo can be seen without scanning the ship."},
{ Mission::Parse_Object_Flags::SF_Ignore_count, "Ignore this ship when counting ship types for goals."},
{ Mission::Parse_Object_Flags::SF_Ignore_count, "Ignore this ship when counting ship types for objectives."},
{ Mission::Parse_Object_Flags::OF_Protected, "Ship and Turret AI will ignore and not attack ship."},
{ Mission::Parse_Object_Flags::SF_Reinforcement, "This ship is a reinforcement ship."},
{ Mission::Parse_Object_Flags::OF_No_shields, "Ship will have no shields (ETS will be rebalanced if shields were off and are enabled)."},
Expand Down Expand Up @@ -589,7 +589,7 @@ flag_def_list_new<Ship::Wing_Flags> Parse_wing_flags[] = {
};

parse_object_flag_description<Ship::Wing_Flags> Parse_wing_flag_descriptions[] = {
{ Ship::Wing_Flags::Ignore_count, "Ignore this wing when counting ship types for goals." },
{ Ship::Wing_Flags::Ignore_count, "Ignore this wing when counting ship types for objectives." },
{ Ship::Wing_Flags::Reinforcement, "This wing is a reinforcement wing." },
{ Ship::Wing_Flags::No_arrival_music, "Don't play arrival music when wing arrives." },
{ Ship::Wing_Flags::No_arrival_message, "Don't play arrival message when wing arrives." },
Expand Down
20 changes: 10 additions & 10 deletions code/missioneditor/missionsave.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1202,7 +1202,7 @@ int Fred_mission_save::save_briefing()

required_string_fred("$Formula:");
parse_comments();
convert_sexp_to_string(sexp_out, bs->formula, SEXP_SAVE_MODE);
convert_sexp_to_string(sexp_out, bs->formula, sexp_save_mode());
fout(" %s", sexp_out.c_str());

for (j = 0; j < bs->num_icons; j++) {
Expand Down Expand Up @@ -1820,7 +1820,7 @@ int Fred_mission_save::save_cutscenes()

required_string_fred("+formula:");
parse_comments();
convert_sexp_to_string(sexp_out, The_mission.cutscenes[i].formula, SEXP_SAVE_MODE);
convert_sexp_to_string(sexp_out, The_mission.cutscenes[i].formula, sexp_save_mode());
fout(" %s\n", sexp_out.c_str());
}
}
Expand Down Expand Up @@ -1862,7 +1862,7 @@ int Fred_mission_save::save_debriefing()
for (i = 0; i < Debriefing->num_stages; i++) {
required_string_fred("$Formula:");
parse_comments(2);
convert_sexp_to_string(sexp_out, Debriefing->stages[i].formula, SEXP_SAVE_MODE);
convert_sexp_to_string(sexp_out, Debriefing->stages[i].formula, sexp_save_mode());
fout(" %s", sexp_out.c_str());

// XSTR
Expand Down Expand Up @@ -1912,7 +1912,7 @@ int Fred_mission_save::save_events()
required_string_either_fred("$Formula:", "#Goals");
required_string_fred("$Formula:");
parse_comments(i ? 2 : 1);
convert_sexp_to_string(sexp_out, Mission_events[i].formula, SEXP_SAVE_MODE);
convert_sexp_to_string(sexp_out, Mission_events[i].formula, sexp_save_mode());
fout(" %s", sexp_out.c_str());

if (!Mission_events[i].name.empty()) {
Expand Down Expand Up @@ -2188,7 +2188,7 @@ int Fred_mission_save::save_fiction()
// save sexp formula if we have one
if (stage.formula >= 0 && stage.formula != Locked_sexp_true) {
SCP_string sexp_out;
convert_sexp_to_string(sexp_out, stage.formula, SEXP_SAVE_MODE);
convert_sexp_to_string(sexp_out, stage.formula, sexp_save_mode());

if (optional_string_fred("$Formula:"))
parse_comments();
Expand Down Expand Up @@ -2248,7 +2248,7 @@ int Fred_mission_save::save_goals()

required_string_fred("$Formula:");
parse_comments();
convert_sexp_to_string(sexp_out, Mission_goals[i].formula, SEXP_SAVE_MODE);
convert_sexp_to_string(sexp_out, Mission_goals[i].formula, sexp_save_mode());
fout(" %s", sexp_out.c_str());

if (Mission_goals[i].type & INVALID_GOAL) {
Expand Down Expand Up @@ -3641,7 +3641,7 @@ int Fred_mission_save::save_objects()

required_string_fred("$Arrival Cue:");
parse_comments();
convert_sexp_to_string(sexp_out, shipp->arrival_cue, SEXP_SAVE_MODE);
convert_sexp_to_string(sexp_out, shipp->arrival_cue, sexp_save_mode());
fout(" %s", sexp_out.c_str());

if (shipp->wingnum >= 0) {
Expand Down Expand Up @@ -3690,7 +3690,7 @@ int Fred_mission_save::save_objects()

required_string_fred("$Departure Cue:");
parse_comments();
convert_sexp_to_string(sexp_out, shipp->departure_cue, SEXP_SAVE_MODE);
convert_sexp_to_string(sexp_out, shipp->departure_cue, sexp_save_mode());
fout(" %s", sexp_out.c_str());

save_warp_params(WarpDirection::WARP_IN, shipp);
Expand Down Expand Up @@ -5063,7 +5063,7 @@ int Fred_mission_save::save_wings()

required_string_fred("$Arrival Cue:");
parse_comments();
convert_sexp_to_string(sexp_out, w.arrival_cue, SEXP_SAVE_MODE);
convert_sexp_to_string(sexp_out, w.arrival_cue, sexp_save_mode());
fout(" %s", sexp_out.c_str());

required_string_fred("$Departure Location:");
Expand Down Expand Up @@ -5108,7 +5108,7 @@ int Fred_mission_save::save_wings()

required_string_fred("$Departure Cue:");
parse_comments();
convert_sexp_to_string(sexp_out, w.departure_cue, SEXP_SAVE_MODE);
convert_sexp_to_string(sexp_out, w.departure_cue, sexp_save_mode());
fout(" %s", sexp_out.c_str());

required_string_fred("$Ships:");
Expand Down
4 changes: 4 additions & 0 deletions code/missioneditor/missionsave.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ class Fred_mission_save {
Fred_mission_save() = default;

void set_save_format(MissionFormat fmt) { save_config.save_format = fmt; }

int sexp_save_mode() const {
return (save_config.save_format == MissionFormat::RETAIL) ? SEXP_SAVE_MODE_RETAIL : SEXP_SAVE_MODE;
}
void set_template_info(const MissionTemplateInfo& info) { save_config.template_info = info; }
void set_view_pos(const vec3d& pos) { save_config.view_pos = pos; }
void set_view_orient(const matrix& orient) { save_config.view_orient = orient; }
Expand Down
1 change: 1 addition & 0 deletions code/parse/parselo.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ enum class ParseLookupType

#define SEXP_SAVE_MODE 1
#define SEXP_ERROR_CHECK_MODE 2
#define SEXP_SAVE_MODE_RETAIL 3 // Save mode that substitutes retail-compatible operator names for their FSO replacements

// Goober5000 - this seems to be a pretty universal function
extern bool end_string_at_first_hash_symbol(char *src, bool ignore_doubled_hash = false);
Expand Down
91 changes: 65 additions & 26 deletions code/parse/sexp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,19 +194,19 @@ SCP_vector<sexp_oper> Operators = {
{ "is-true-for-duration", OP_IS_TRUE_FOR_DURATION, 2, INT_MAX, SEXP_BOOLEAN_OPERATOR, }, // Goober5000

//Event/Goals Category
{ "is-goal-true-delay", OP_GOAL_TRUE_DELAY, 2, 2, SEXP_BOOLEAN_OPERATOR, },
{ "is-goal-false-delay", OP_GOAL_FALSE_DELAY, 2, 2, SEXP_BOOLEAN_OPERATOR, },
{ "is-goal-incomplete", OP_GOAL_INCOMPLETE, 1, 1, SEXP_BOOLEAN_OPERATOR, },
{ "is-objective-true-delay", OP_GOAL_TRUE_DELAY, 2, 2, SEXP_BOOLEAN_OPERATOR, },
{ "is-objective-false-delay", OP_GOAL_FALSE_DELAY, 2, 2, SEXP_BOOLEAN_OPERATOR, },
{ "is-objective-incomplete", OP_GOAL_INCOMPLETE, 1, 1, SEXP_BOOLEAN_OPERATOR, },
{ "is-event-true", OP_EVENT_TRUE, 1, 1, SEXP_BOOLEAN_OPERATOR, },
{ "is-event-true-delay", OP_EVENT_TRUE_DELAY, 2, 3, SEXP_BOOLEAN_OPERATOR, },
{ "is-event-true-msecs-delay", OP_EVENT_TRUE_MSECS_DELAY, 2, 3, SEXP_BOOLEAN_OPERATOR, },
{ "is-event-false", OP_EVENT_FALSE, 1, 1, SEXP_BOOLEAN_OPERATOR, },
{ "is-event-false-delay", OP_EVENT_FALSE_DELAY, 2, 3, SEXP_BOOLEAN_OPERATOR, },
{ "is-event-false-msecs-delay", OP_EVENT_FALSE_MSECS_DELAY, 2, 3, SEXP_BOOLEAN_OPERATOR, },
{ "is-event-incomplete", OP_EVENT_INCOMPLETE, 1, 1, SEXP_BOOLEAN_OPERATOR, },
{ "is-previous-goal-true", OP_PREVIOUS_GOAL_TRUE, 2, 3, SEXP_BOOLEAN_OPERATOR, },
{ "is-previous-goal-false", OP_PREVIOUS_GOAL_FALSE, 2, 3, SEXP_BOOLEAN_OPERATOR, },
{ "is-previous-goal-incomplete", OP_PREVIOUS_GOAL_INCOMPLETE, 2, 3, SEXP_BOOLEAN_OPERATOR, },
{ "is-previous-objective-true", OP_PREVIOUS_GOAL_TRUE, 2, 3, SEXP_BOOLEAN_OPERATOR, },
{ "is-previous-objective-false", OP_PREVIOUS_GOAL_FALSE, 2, 3, SEXP_BOOLEAN_OPERATOR, },
{ "is-previous-objective-incomplete", OP_PREVIOUS_GOAL_INCOMPLETE, 2, 3, SEXP_BOOLEAN_OPERATOR, },
{ "is-previous-event-true", OP_PREVIOUS_EVENT_TRUE, 2, 3, SEXP_BOOLEAN_OPERATOR, },
{ "is-previous-event-false", OP_PREVIOUS_EVENT_FALSE, 2, 3, SEXP_BOOLEAN_OPERATOR, },
{ "is-previous-event-incomplete", OP_PREVIOUS_EVENT_INCOMPLETE, 2, 3, SEXP_BOOLEAN_OPERATOR, },
Expand Down Expand Up @@ -4767,6 +4767,18 @@ int get_sexp()
strcpy_s(token, "add-to-collision-group-new");
else if (!stricmp(token, "remove-from-collision-group2"))
strcpy_s(token, "remove-from-collision-group-new");
else if (!stricmp(token, "is-goal-true-delay"))
strcpy_s(token, "is-objective-true-delay");
else if (!stricmp(token, "is-goal-false-delay"))
strcpy_s(token, "is-objective-false-delay");
else if (!stricmp(token, "is-goal-incomplete"))
strcpy_s(token, "is-objective-incomplete");
else if (!stricmp(token, "is-previous-goal-true"))
strcpy_s(token, "is-previous-objective-true");
else if (!stricmp(token, "is-previous-goal-false"))
strcpy_s(token, "is-previous-objective-false");
else if (!stricmp(token, "is-previous-goal-incomplete"))
strcpy_s(token, "is-previous-objective-incomplete");

op = get_operator_index(token);
if (op >= 0) {
Expand Down Expand Up @@ -5213,6 +5225,26 @@ int num_block_variables()
return Num_special_expl_blocks * BLOCK_EXP_SIZE;
}

// Reverse aliases used when saving in retail-compatible format: map canonical FSO operator names
// back to the older names that the retail FS2 engine can recognize.
static const std::pair<const char*, const char*> Sexp_retail_operator_aliases[] = {
{ "is-objective-true-delay", "is-goal-true-delay" },
{ "is-objective-false-delay", "is-goal-false-delay" },
{ "is-objective-incomplete", "is-goal-incomplete" },
{ "is-previous-objective-true", "is-previous-goal-true" },
{ "is-previous-objective-false", "is-previous-goal-false" },
{ "is-previous-objective-incomplete","is-previous-goal-incomplete" },
};

static const char* lookup_retail_operator_alias(const char* text)
{
for (const auto& pair : Sexp_retail_operator_aliases) {
if (!stricmp(text, pair.first))
return pair.second;
}
return nullptr;
}

/**
* Stuff this particular SEXP node (just the node, not the tree) into a string representation
*/
Expand Down Expand Up @@ -5298,6 +5330,13 @@ void stuff_sexp_text_string(SCP_string &dest, int node, int mode)
ctext_string = "0";
}
}
// when saving in retail-compatible format, substitute the retail name for any
// canonical FSO operator name that has a registered retail alias
if (mode == SEXP_SAVE_MODE_RETAIL && Sexp_nodes[node].subtype == SEXP_ATOM_OPERATOR) {
const char* retail_name = lookup_retail_operator_alias(ctext_string);
if (retail_name != nullptr)
ctext_string = retail_name;
}
sprintf(dest, "%s ", ctext_string);
}
}
Expand Down Expand Up @@ -38387,30 +38426,30 @@ SCP_vector<sexp_help_struct> Sexp_help = {
"false becomes true).\r\n\r\n"
"Returns a boolean value. Takes 1 boolean argument." },

{ OP_PREVIOUS_GOAL_TRUE, "Previous Mission Goal True (Boolean operator)\r\n"
"\tReturns true if the specified goal in the specified mission is true "
{ OP_PREVIOUS_GOAL_TRUE, "Previous Mission Objective True (Boolean operator)\r\n"
"\tReturns true if the specified objective in the specified mission is true "
"(or succeeded). It returns false otherwise.\r\n\r\n"
"Returns a boolean value. Takes 2 required arguments and 1 optional argument...\r\n"
"\t1:\tName of the mission.\r\n"
"\t2:\tName of the goal in the mission.\r\n"
"\t2:\tName of the objective in the mission.\r\n"
"\t3:\t(Optional) True/False which signifies what this sexpression should return when "
"this mission is played as a single mission, or is played as a campaign mission and skipped." },

{ OP_PREVIOUS_GOAL_FALSE, "Previous Mission Goal False (Boolean operator)\r\n"
"\tReturns true if the specified goal in the specified mission "
{ OP_PREVIOUS_GOAL_FALSE, "Previous Mission Objective False (Boolean operator)\r\n"
"\tReturns true if the specified objective in the specified mission "
"is false (or failed). It returns false otherwise.\r\n\r\n"
"Returns a boolean value. Takes 2 required arguments and 1 optional argument...\r\n"
"\t1:\tName of the mission.\r\n"
"\t2:\tName of the goal in the mission.\r\n"
"\t2:\tName of the objective in the mission.\r\n"
"\t3:\t(Optional) True/False which signifies what this sexpression should return when "
"this mission is played as a single mission, or is played as a campaign mission and skipped." },

{ OP_PREVIOUS_GOAL_INCOMPLETE, "Previous Mission Goal Incomplete (Boolean operator)\r\n"
"\tReturns true if the specified goal in the specified mission "
{ OP_PREVIOUS_GOAL_INCOMPLETE, "Previous Mission Objective Incomplete (Boolean operator)\r\n"
"\tReturns true if the specified objective in the specified mission "
"is incomplete (not true or false). It returns false otherwise.\r\n\r\n"
"Returns a boolean value. Takes 2 required arguments and 1 optional argument...\r\n"
"\t1:\tName of the mission.\r\n"
"\t2:\tName of the goal in the mission.\r\n"
"\t2:\tName of the objective in the mission.\r\n"
"\t3:\t(Optional) True/False which signifies what this sexpression should return when "
"this mission is played as a single mission, or is played as a campaign mission and skipped." },

Expand Down Expand Up @@ -38441,26 +38480,26 @@ SCP_vector<sexp_help_struct> Sexp_help = {
"\t3:\t(Optional) True/False which signifies what this sexpression should return when "
"this mission is played as a single mission, or is played as a campaign mission and skipped." },

{ OP_GOAL_TRUE_DELAY, "Mission Goal True (Boolean operator)\r\n"
"\tReturns true N seconds after the specified goal in the this mission is true (or succeeded). It returns false otherwise.\r\n\r\n"
"\tThis operator works by checking the mission log. Since goal status is evaluated after event status, a delay of 0 will cause an event to become true on the frame after the goal becomes true.\r\n\r\n"
{ OP_GOAL_TRUE_DELAY, "Mission Objective True (Boolean operator)\r\n"
"\tReturns true N seconds after the specified objective in the this mission is true (or succeeded). It returns false otherwise.\r\n\r\n"
"\tThis operator works by checking the mission log. Since objective status is evaluated after event status, a delay of 0 will cause an event to become true on the frame after the objective becomes true.\r\n\r\n"
"Returns a boolean value. Takes 2 required arguments and 1 optional argument...\r\n"
"\t1:\tName of the event in the mission.\r\n"
"\t1:\tName of the mission objective.\r\n"
"\t2:\tNumber of seconds to delay before returning true."},

{ OP_GOAL_FALSE_DELAY, "Mission Goal False (Boolean operator)\r\n"
"\tReturns true N seconds after the specified goal in the this mission is false (or failed). It returns false otherwise.\r\n\r\n"
"\tThis operator works by checking the mission log. Since goal status is evaluated after event status, a delay of 0 will cause an event to become true on the frame after the goal becomes false.\r\n\r\n"
{ OP_GOAL_FALSE_DELAY, "Mission Objective False (Boolean operator)\r\n"
"\tReturns true N seconds after the specified objective in the this mission is false (or failed). It returns false otherwise.\r\n\r\n"
"\tThis operator works by checking the mission log. Since objective status is evaluated after event status, a delay of 0 will cause an event to become true on the frame after the objective becomes false.\r\n\r\n"
"Returns a boolean value. Takes 2 required arguments and 1 optional argument...\r\n"
"\t1:\tName of the event in the mission.\r\n"
"\t1:\tName of the mission objective.\r\n"
"\t2:\tNumber of seconds to delay before returning true."},

{ OP_GOAL_INCOMPLETE, "Mission Goal Incomplete (Boolean operator)\r\n"
"\tReturns true if the specified goal in the this mission is incomplete. This "
{ OP_GOAL_INCOMPLETE, "Mission Objective Incomplete (Boolean operator)\r\n"
"\tReturns true if the specified objective in the this mission is incomplete. This "
"sexpression will only be useful in conjunction with another sexpression like "
"has-time-elapsed. Used alone, it will return true upon mission startup.\r\n"
"Returns a boolean value. Takes 1 argument...\r\n"
"\t1:\tName of the event in the mission."},
"\t1:\tName of the mission objective."},

{ OP_EVENT_TRUE_DELAY, "Mission Event True (Boolean operator)\r\n"
"\tReturns true N seconds after the specified event in the this mission is true (or succeeded). It returns false otherwise.\r\n\r\n"
Expand Down
6 changes: 5 additions & 1 deletion code/scripting/ade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,9 @@ ade_indexer::ade_indexer(lua_CFunction func,
ade_overload_list overloads,
const char* desc,
const char* ret_type,
const char* ret_desc)
const char* ret_desc,
const gameversion::version& deprecation_version,
const char* deprecation_message)
{
// Add function for meta
ade_table_entry ate;
Expand All @@ -802,6 +804,8 @@ ade_indexer::ade_indexer(lua_CFunction func,
ate.Description = desc;
ate.ReturnType = ret_type;
ate.ReturnDescription = ret_desc;
ate.DeprecationVersion = deprecation_version;
ate.DeprecationMessage = deprecation_message;

LibIdx = ade_manager::getInstance()->getEntry(parent.GetIdx()).AddSubentry(ate);
}
Expand Down
Loading
Loading