diff --git a/code/mission/missionparse.cpp b/code/mission/missionparse.cpp
index 057a62afe4f..add8e66db9e 100644
--- a/code/mission/missionparse.cpp
+++ b/code/mission/missionparse.cpp
@@ -391,7 +391,7 @@ flag_def_list_new 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},
@@ -424,7 +424,7 @@ parse_object_flag_description 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"},
@@ -506,7 +506,7 @@ flag_def_list_new Parse_object_flags[] = {
parse_object_flag_description 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)."},
@@ -589,7 +589,7 @@ flag_def_list_new Parse_wing_flags[] = {
};
parse_object_flag_description 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." },
diff --git a/code/missioneditor/missionsave.cpp b/code/missioneditor/missionsave.cpp
index e46fb6b590c..b2b60a786fc 100644
--- a/code/missioneditor/missionsave.cpp
+++ b/code/missioneditor/missionsave.cpp
@@ -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++) {
@@ -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());
}
}
@@ -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
@@ -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()) {
@@ -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();
@@ -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) {
@@ -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) {
@@ -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);
@@ -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:");
@@ -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:");
diff --git a/code/missioneditor/missionsave.h b/code/missioneditor/missionsave.h
index b3e183c53d0..58d58112526 100644
--- a/code/missioneditor/missionsave.h
+++ b/code/missioneditor/missionsave.h
@@ -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; }
diff --git a/code/parse/parselo.h b/code/parse/parselo.h
index 8640962302d..5d5fc5e4f5a 100644
--- a/code/parse/parselo.h
+++ b/code/parse/parselo.h
@@ -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);
diff --git a/code/parse/sexp.cpp b/code/parse/sexp.cpp
index 2a8dc37e90a..04141654e67 100644
--- a/code/parse/sexp.cpp
+++ b/code/parse/sexp.cpp
@@ -194,9 +194,9 @@ SCP_vector 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, },
@@ -204,9 +204,9 @@ SCP_vector Operators = {
{ "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, },
@@ -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) {
@@ -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 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
*/
@@ -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);
}
}
@@ -38387,30 +38426,30 @@ SCP_vector 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." },
@@ -38441,26 +38480,26 @@ SCP_vector 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"
diff --git a/code/scripting/ade.cpp b/code/scripting/ade.cpp
index b4adbca0e13..34e084511ac 100644
--- a/code/scripting/ade.cpp
+++ b/code/scripting/ade.cpp
@@ -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;
@@ -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);
}
diff --git a/code/scripting/ade_api.h b/code/scripting/ade_api.h
index b538a006ba5..0a846306351 100644
--- a/code/scripting/ade_api.h
+++ b/code/scripting/ade_api.h
@@ -436,7 +436,9 @@ class ade_indexer : public ade_lib_handle {
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);
};
/**
@@ -455,7 +457,30 @@ class ade_indexer : public ade_lib_handle {
*/
#define ADE_INDEXER(parent, args, desc, ret_type, ret_desc) \
static int parent##___indexer_f(lua_State* L); \
- ::scripting::ade_indexer parent##___indexer(parent##___indexer_f, parent, args, desc, ret_type, ret_desc); \
+ ::scripting::ade_indexer parent##___indexer(parent##___indexer_f, parent, args, desc, ret_type, ret_desc, \
+ ::gameversion::version(), nullptr); \
+ static int parent##___indexer_f(lua_State* L)
+
+/**
+ * @brief Declare a deprecated indexer of an object
+ *
+ * Use this with objects to deal with forms such as vec.x, vec['x'], vec[0]. Format string should be "o*%", where * is
+ * indexing value, and % is the value to set to when LUA_SETTTING_VAR is set
+ *
+ * @param parent The library or object containing the indexer
+ * @param args Documentation for the type of the value that may be assigned
+ * @param desc Description of what the variable does
+ * @param ret_type The type of the returned value
+ * @param ret_desc Documentation for the returned value
+ * @param deprecate_version Version starting from which this function is deprecated.
+ * @param deprecated_msg Message for the deprecation notice. May be nullptr.
+ *
+ * @ingroup ade_api
+ */
+#define ADE_INDEXER_DEPRECATED(parent, args, desc, ret_type, ret_desc, deprecate_version, deprecated_msg) \
+ static int parent##___indexer_f(lua_State* L); \
+ ::scripting::ade_indexer parent##___indexer(parent##___indexer_f, parent, args, desc, ret_type, ret_desc, \
+ deprecate_version, deprecated_msg); \
static int parent##___indexer_f(lua_State* L)
//*************************Lua return values*************************
diff --git a/code/scripting/api/libs/mission.cpp b/code/scripting/api/libs/mission.cpp
index 395c254fda6..007f577eb49 100644
--- a/code/scripting/api/libs/mission.cpp
+++ b/code/scripting/api/libs/mission.cpp
@@ -23,6 +23,7 @@
#include "mission/missionlog.h"
#include "mission/missionmessage.h"
#include "mission/missiontraining.h"
+#include "mod_table/mod_table.h"
#include "missionui/missionbrief.h"
#include "missionui/missioncmdbrief.h"
#include "missionui/redalert.h"
@@ -410,9 +411,15 @@ ADE_FUNC(__len, l_Mission_Events, nullptr, "Number of events in mission", "numbe
}
//****SUBLIBRARY: Mission/Goals
-ADE_LIB_DERIV(l_Mission_Goals, "Goals", nullptr, "Goals", l_Mission);
+ADE_LIB_DERIV(l_Mission_Goals, "Goals", nullptr, "Goals (deprecated in favor of Objectives)", l_Mission);
-ADE_INDEXER(l_Mission_Goals, "number/string IndexOrName", "Indexes mission goals list", "mission_goal", "Goal handle, or invalid goal handle if index was invalid")
+ADE_INDEXER_DEPRECATED(l_Mission_Goals,
+ "number/string IndexOrName",
+ "Indexes mission goals list",
+ "mission_goal",
+ "Goal handle, or invalid goal handle if index was invalid",
+ gameversion::version(26, 0, 0),
+ "mn.Goals is deprecated in favor of mn.Objectives.")
{
const char* s;
if(!ade_get_args(L, "*s", &s))
@@ -434,7 +441,44 @@ ADE_INDEXER(l_Mission_Goals, "number/string IndexOrName", "Indexes mission goals
return ade_set_args(L, "o", l_Goal.Set(i));
}
-ADE_FUNC(__len, l_Mission_Goals, nullptr, "Number of goals in mission", "number", "Number of goals in mission")
+ADE_FUNC_DEPRECATED(__len,
+ l_Mission_Goals,
+ nullptr,
+ "Number of goals in mission",
+ "number",
+ "Number of goals in mission",
+ gameversion::version(26, 0, 0),
+ "mn.Goals is deprecated in favor of mn.Objectives.")
+{
+ return ade_set_args(L, "i", static_cast(Mission_goals.size()));
+}
+
+//****SUBLIBRARY: Mission/Mission_Objectives
+ADE_LIB_DERIV(l_Mission_Objectives, "Mission_Objectives", "Objectives", "Mission objectives", l_Mission);
+
+ADE_INDEXER(l_Mission_Objectives, "number/string IndexOrName", "Indexes mission objectives list", "mission_goal", "Objective handle, or invalid objective handle if index was invalid")
+{
+ const char* s;
+ if(!ade_get_args(L, "*s", &s))
+ return ade_set_error(L, "o", l_Goal.Set(-1));
+
+ int i = mission_goal_lookup(s);
+ if (i >= 0)
+ return ade_set_args(L, "o", l_Goal.Set(i));
+
+ //Now try as a number
+ i = atoi(s);
+ //Lua-->FS2
+ i--;
+
+ if(!SCP_vector_inbounds(Mission_goals, i))
+ return ade_set_error(L, "o", l_Goal.Set(-1));
+
+
+ return ade_set_args(L, "o", l_Goal.Set(i));
+}
+
+ADE_FUNC(__len, l_Mission_Objectives, nullptr, "Number of objectives in mission", "number", "Number of objectives in mission")
{
return ade_set_args(L, "i", static_cast(Mission_goals.size()));
}
diff --git a/code/scripting/api/objs/goal.cpp b/code/scripting/api/objs/goal.cpp
index 59b9d02af8e..df6a90a33c4 100644
--- a/code/scripting/api/objs/goal.cpp
+++ b/code/scripting/api/objs/goal.cpp
@@ -87,7 +87,21 @@ ADE_VIRTVAR(Team, l_Goal, nullptr, "The goal team", "team", "The goal team")
return ade_set_args(L, "o", l_Team.Set(Mission_goals[current].team));
}
-ADE_VIRTVAR(isGoalSatisfied, l_Goal, nullptr, "The status of the goal", "number", "0 if failed, 1 if complete, 2 if incomplete")
+ADE_VIRTVAR_DEPRECATED(isGoalSatisfied, l_Goal, nullptr, "The status of the goal", "number", "0 if failed, 1 if complete, 2 if incomplete", gameversion::version(26, 0, 0), "Deprecated in favor of isObjectiveSatisfied")
+{
+ int current;
+ if (!ade_get_args(L, "o", l_Goal.Get(¤t))) {
+ return ADE_RETURN_NIL;
+ }
+
+ if (ADE_SETTING_VAR) {
+ LuaError(L, "This property is read only.");
+ }
+
+ return ade_set_args(L, "i", Mission_goals[current].satisfied);
+}
+
+ADE_VIRTVAR(isObjectiveSatisfied, l_Goal, nullptr, "The status of the objective", "number", "0 if failed, 1 if complete, 2 if incomplete")
{
int current;
if (!ade_get_args(L, "o", l_Goal.Get(¤t))) {
@@ -115,7 +129,21 @@ ADE_VIRTVAR(Score, l_Goal, nullptr, "The score of the goal", "number", "the scor
return ade_set_args(L, "i", Mission_goals[current].score);
}
-ADE_VIRTVAR(isGoalValid, l_Goal, nullptr, "The goal validity", "boolean", "true if valid, false otherwise")
+ADE_VIRTVAR_DEPRECATED(isGoalValid, l_Goal, nullptr, "The goal validity", "boolean", "true if valid, false otherwise", gameversion::version(26, 0, 0), "Deprecated in favor of isObjectiveValid")
+{
+ int current;
+ if (!ade_get_args(L, "o", l_Goal.Get(¤t))) {
+ return ADE_RETURN_NIL;
+ }
+
+ if (ADE_SETTING_VAR) {
+ LuaError(L, "This property is read only.");
+ }
+
+ return ade_set_args(L, "b", !(Mission_goals[current].type & INVALID_GOAL));
+}
+
+ADE_VIRTVAR(isObjectiveValid, l_Goal, nullptr, "The objective validity", "boolean", "true if valid, false otherwise")
{
int current;
if (!ade_get_args(L, "o", l_Goal.Get(¤t))) {
diff --git a/fred2/dumpstats.cpp b/fred2/dumpstats.cpp
index 3959c9901ea..a7e12de15d2 100644
--- a/fred2/dumpstats.cpp
+++ b/fred2/dumpstats.cpp
@@ -463,7 +463,7 @@ void DumpStats::get_objectives_and_goals(CString &buffer)
CString temp;
int i;
- buffer += "\r\nOBJECTIVES AND GOALS\r\n";
+ buffer += "\r\nEVENT DIRECTIVES AND MISSION OBJECTIVES\r\n";
// objectives
for (i=0; i<(int)Mission_events.size(); i++) {
@@ -479,7 +479,7 @@ void DumpStats::get_objectives_and_goals(CString &buffer)
// goals
for (i=0; i<(int)Mission_goals.size(); i++) {
- temp.Format("\tGoal: %s, text: %s", Mission_goals[i].name.c_str(), Mission_goals[i].message.c_str());
+ temp.Format("\tObjective: %s, text: %s", Mission_goals[i].name.c_str(), Mission_goals[i].message.c_str());
buffer += temp;
switch(Mission_goals[i].type & GOAL_TYPE_MASK) {
diff --git a/fred2/fred.rc b/fred2/fred.rc
index bbfefe7442b..5d053c4100f 100644
--- a/fred2/fred.rc
+++ b/fred2/fred.rc
@@ -375,7 +375,7 @@ BEGIN
POPUP "Mission"
BEGIN
MENUITEM "&Mission Specs\tShift+N", 32771
- MENUITEM "Mission &Goals\tShift+G", 32800
+ MENUITEM "Mission &Objectives\tShift+G", 32800
MENUITEM "Mission &Events\tShift+E", 32974
MENUITEM "Mission Cutscenes", ID_EDITORS_CUTSCENES
MENUITEM SEPARATOR
@@ -982,7 +982,7 @@ BEGIN
CONTROL "Toggle Starting in Chase View",IDC_TOGGLE_START_CHASE,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,326,161,146,10
CONTROL "2D Mission",IDC_2D_MISSION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,326,171,123,10
- CONTROL "Toggle Showing Goals In Briefing",IDC_TOGGLE_SHOWING_GOALS,
+ CONTROL "Toggle Showing Objectives In Briefing",IDC_TOGGLE_SHOWING_GOALS,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,326,181,142,10
CONTROL "Mission End to Mainhall",IDC_END_TO_MAINHALL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,326,191,142,10
CONTROL "Preload Subspace Tunnel",IDC_PRELOAD_SUBSPACE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,326,201,142,10
@@ -1181,7 +1181,7 @@ BEGIN
COMBOBOX IDC_OBJ_TEAM,293,98,73,71,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
CONTROL "Objective Invalid",IDC_GOAL_INVALID,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,239,117,69,10
CONTROL "Don't Play Completion Music",IDC_NO_MUSIC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,239,127,107,10
- PUSHBUTTON "New Obj.",IDC_BUTTON_NEW_GOAL,233,146,44,14,0,WS_EX_STATICEDGE,HIDC_BUTTON_NEW_GOAL
+ PUSHBUTTON "New Objective",IDC_BUTTON_NEW_GOAL,233,146,44,14,0,WS_EX_STATICEDGE,HIDC_BUTTON_NEW_GOAL
PUSHBUTTON "OK",ID_OK,281,146,44,14
PUSHBUTTON "Cancel",IDCANCEL,329,146,44,14
EDITTEXT IDC_HELP_BOX,6,167,367,95,ES_MULTILINE | ES_READONLY | WS_VSCROLL,WS_EX_TRANSPARENT
@@ -1250,7 +1250,7 @@ BEGIN
PUSHBUTTON "Squad Logo",IDC_WING_SQUAD_LOGO_BUTTON,7,89,55,14
EDITTEXT IDC_WING_SQUAD_LOGO,65,90,80,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "Reinforcement Unit",IDC_REINFORCEMENT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,143,10,77,10
- CONTROL "Ignore for Counting Goals",IDC_IGNORE_COUNT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,143,21,96,10
+ CONTROL "Ignore for Counting Objectives",IDC_IGNORE_COUNT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,143,21,96,10
CONTROL "No Arrival Music",IDC_NO_ARRIVAL_MUSIC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,143,32,67,10
CONTROL "No Arrival Message",IDC_NO_ARRIVAL_MESSAGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,143,43,77,10
CONTROL "No First Wave Message",IDC_NO_FIRST_WAVE_MESSAGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,143,54,77,10
@@ -2058,7 +2058,7 @@ BEGIN
CONTROL "Reinforcement Unit",IDC_REINFORCEMENT,"Button",BS_3STATE | WS_TABSTOP,7,62,75,10
CONTROL "Protect Ship",IDC_PROTECT_SHIP,"Button",BS_3STATE | WS_TABSTOP,7,72,59,10
CONTROL "Beam Protect Ship",IDC_BEAM_PROTECT_SHIP,"Button",BS_3STATE | WS_TABSTOP,12,93,80,8
- CONTROL "Ignore for Counting Goals",IDC_IGNORE_COUNT,"Button",BS_3STATE | WS_TABSTOP,7,136,93,10
+ CONTROL "Ignore for Counting Objectives",IDC_IGNORE_COUNT,"Button",BS_3STATE | WS_TABSTOP,7,136,93,10
CONTROL "Escort Ship",IDC_ESCORT,"Button",BS_3STATE | WS_TABSTOP,7,146,52,10
EDITTEXT IDC_ESCORT_PRIORITY,43,157,26,12,ES_AUTOHSCROLL
LTEXT "Priority",IDC_STATIC,19,159,22,8
@@ -3151,18 +3151,18 @@ END
IDD_MISSION_GOALS DLGINIT
BEGIN
- IDC_DISPLAY_GOAL_TYPES_DROP, 0x403, 14, 0
-0x7250, 0x6d69, 0x7261, 0x2079, 0x6f47, 0x6c61, 0x0073,
- IDC_DISPLAY_GOAL_TYPES_DROP, 0x403, 16, 0
-0x6553, 0x6f63, 0x646e, 0x7261, 0x2079, 0x6f47, 0x6c61, 0x0073,
- IDC_DISPLAY_GOAL_TYPES_DROP, 0x403, 12, 0
-0x6f42, 0x756e, 0x2073, 0x6f47, 0x6c61, 0x0073,
- IDC_GOAL_TYPE_DROP, 0x403, 13, 0
-0x7250, 0x6d69, 0x7261, 0x2079, 0x6f47, 0x6c61, "\000"
- IDC_GOAL_TYPE_DROP, 0x403, 15, 0
-0x6553, 0x6f63, 0x646e, 0x7261, 0x2079, 0x6f47, 0x6c61, "\000"
- IDC_GOAL_TYPE_DROP, 0x403, 11, 0
-0x6f42, 0x756e, 0x2073, 0x6f47, 0x6c61, "\000"
+ IDC_DISPLAY_GOAL_TYPES_DROP, 0x403, 19, 0
+0x7250, 0x6d69, 0x7261, 0x2079, 0x624f, 0x656a, 0x7463, 0x7669, 0x7365, "\000"
+ IDC_DISPLAY_GOAL_TYPES_DROP, 0x403, 21, 0
+0x6553, 0x6f63, 0x646e, 0x7261, 0x2079, 0x624f, 0x656a, 0x7463, 0x7669, 0x7365, "\000"
+ IDC_DISPLAY_GOAL_TYPES_DROP, 0x403, 17, 0
+0x6f42, 0x756e, 0x2073, 0x624f, 0x656a, 0x7463, 0x7669, 0x7365, "\000"
+ IDC_GOAL_TYPE_DROP, 0x403, 18, 0
+0x7250, 0x6d69, 0x7261, 0x2079, 0x624f, 0x656a, 0x7463, 0x7669, 0x0065,
+ IDC_GOAL_TYPE_DROP, 0x403, 20, 0
+0x6553, 0x6f63, 0x646e, 0x7261, 0x2079, 0x624f, 0x656a, 0x7463, 0x7669, 0x0065,
+ IDC_GOAL_TYPE_DROP, 0x403, 16, 0
+0x6f42, 0x756e, 0x2073, 0x624f, 0x656a, 0x7463, 0x7669, 0x0065,
IDC_OBJ_TEAM, 0x403, 7, 0
0x6554, 0x6d61, 0x3120, "\000"
IDC_OBJ_TEAM, 0x403, 7, 0
@@ -3623,7 +3623,7 @@ END
STRINGTABLE
BEGIN
- ID_EDITORS_GOALS "Activates Mission Goal Editor\nMission Goal Editor"
+ ID_EDITORS_GOALS "Activates Mission Objective Editor\nMission Objective Editor"
ID_EDITORS_WAYPOINTS "Activates Waypoint Editor\nWaypoint Editor"
ID_EDITORS_SOUND "Activates Sound Editor\nSound Editor"
ID_EDITORS_TERRAIN "Activates Terrain Editor Screen\nTerrain Editor"
diff --git a/fred2/fredview.cpp b/fred2/fredview.cpp
index 62a135fd166..c8966b3642b 100644
--- a/fred2/fredview.cpp
+++ b/fred2/fredview.cpp
@@ -3008,7 +3008,7 @@ int CFREDView::global_error_check()
}
for (i=0; i<(int)Mission_goals.size(); i++){
- if (fred_check_sexp(Mission_goals[i].formula, OPR_BOOL, "mission goal \"%s\"", Mission_goals[i].name.c_str())){
+ if (fred_check_sexp(Mission_goals[i].formula, OPR_BOOL, "mission objective \"%s\"", Mission_goals[i].name.c_str())){
return -1;
}
}
diff --git a/fred2/management.cpp b/fred2/management.cpp
index 5021609a630..b09427b1703 100644
--- a/fred2/management.cpp
+++ b/fred2/management.cpp
@@ -2077,9 +2077,9 @@ int reference_handler(const char *name, sexp_ref_type type, int obj)
case sexp_src::MISSION_GOAL:
if (!Mission_goals[n].name.empty())
- sprintf(text, "mission goal \"%s\"", Mission_goals[n].name.c_str());
+ sprintf(text, "mission objective \"%s\"", Mission_goals[n].name.c_str());
else
- sprintf(text, "mission goal #%d", n);
+ sprintf(text, "mission objective #%d", n);
break;
diff --git a/fred2/missiongoalsdlg.cpp b/fred2/missiongoalsdlg.cpp
index 518704b37ab..8fbe21d85d4 100644
--- a/fred2/missiongoalsdlg.cpp
+++ b/fred2/missiongoalsdlg.cpp
@@ -394,8 +394,8 @@ void CMissionGoalsDlg::OnButtonNewGoal()
m_sig.push_back(-1);
m_goals.back().type = m_display_goal_types; // this also marks the goal as valid since bit not set
- m_goals.back().name = "Goal name";
- m_goals.back().message = "Mission goal text";
+ m_goals.back().name = "Objective name";
+ m_goals.back().message = "Mission objective text";
h = m_goals_tree.insert(m_goals.back().name.c_str());
m_goals_tree.item_index = -1;
diff --git a/qtfred/help-src/doc/concepts/campaign-flow.html b/qtfred/help-src/doc/concepts/campaign-flow.html
index c83471fdcfa..b3c5392be06 100644
--- a/qtfred/help-src/doc/concepts/campaign-flow.html
+++ b/qtfred/help-src/doc/concepts/campaign-flow.html
@@ -11,7 +11,7 @@
Campaign Flow
A campaign is a sequence of missions linked together in the
Campaign Editor. The campaign
file controls which mission plays next, branches the story based on outcomes, and
-carries state between missions through goals and variables.
+carries state between missions through objectives and variables.
How missions end
A mission ends when the player reaches the debrief screen. There are two
@@ -20,21 +20,21 @@
How missions end
Condition
When it occurs
What is saved
Mission completed
The player accepts the debriefing after
flying the mission.
Variables with Save on Mission
- Completed persistence, plus all goal states.
+ Completed persistence, plus all objective states.
Mission closed
The player exits the mission by any means,
including failure or replaying.
Variables with Save on Mission
Close persistence.
-
Goal states
-
Every mission goal ends in one of three states: complete, failed, or
+
Objective states
+
Every mission objective ends in one of three states: complete, failed, or
incomplete. The campaign SEXP tree reads these states using
goal-true and goal-false operators to decide which
mission to branch to next. This is how outcomes carry forward; whether an
important ship survived, whether a bonus objective was met, and so on.
-
Goals do not automatically determine success or failure. The campaign SEXPs
-are what interpret goal states and produce outcomes. A mission where all primary
-goals are complete can still branch to a "defeat" mission if the campaign logic
+
Objectives do not automatically determine success or failure. The campaign SEXPs
+are what interpret objective states and produce outcomes. A mission where all primary
+objectives are complete can still branch to a "defeat" mission if the campaign logic
is written that way.
Variables across missions
@@ -54,9 +54,9 @@
Branching
use the end-campaign SEXP.
Common branching patterns include:
-
Checking whether a primary goal succeeded to route to a victory or
+
Checking whether a primary objective succeeded to route to a victory or
defeat mission.
-
Checking whether an optional goal was completed to unlock bonus
+
Checking whether an optional objective was completed to unlock bonus
missions.
Reading a variable set earlier in the campaign to take a story
branch.
Mission Events — the primary place to author SEXP logic;
see the Mission Events dialog.
-
Mission Goals — the completion condition for each goal;
- see the Mission Goals dialog.
+
Mission Objectives — the completion condition for each objective;
+ see the Mission Objectives dialog.
Ship arrival/departure cues — conditions on when ships
enter and leave the mission.
Briefing and debriefing — stage-change conditions.
Editing SEXPs in QtFRED
-
The SEXP tree editor is embedded directly in the Mission Events and Mission Goals
+
The SEXP tree editor is embedded directly in the Mission Events and Mission Objectives
dialogs. Right-click any node in the tree to add, replace, or remove operators and
arguments. Hover over an operator name for a brief description of what it does.
Defines the goals shown to the player at the end of the briefing and tracked on
-the HUD during the mission. When a goal is completed or failed a HUD popup notifies
-the player. Goals are hidden during the briefing if the
-Toggle Showing Goals In Briefing flag is set in
-Mission Specs.
-
-
The UI uses the term Objective in some places (such as
-the New Obj. button) interchangeably with Goal. The
-canonical term is Goal, which matches the SEXP operator naming
-convention.
-
-
Goal types
-
Goal type is a classification that affects how goals are displayed and which music
-plays on completion or failure. The actual consequences of a goal being met or failed
-, which debriefing stage the player sees, whether the campaign advances, are
-determined by SEXPs in the
-Debriefing Editor and the
-Campaign Editor, which can query goal state
-using operators like goal-true and goal-false.
-
-
Type
Description
-
Primary
Shown to the player from the start of the mission.
- Completion or failure triggers the primary goal music stinger. By convention
- these are the core objectives designers tie campaign progression and debriefing
- outcomes to.
-
Secondary
Shown to the player from the start of the mission.
- Completion or failure triggers the secondary goal music stinger. Designers
- typically use these for optional objectives whose state is queried in the
- debriefing or campaign for bonus outcomes.
-
Bonus
Hidden from the player until the goal is achieved, at which
- point the goal text appears on the HUD. Their state is queryable by SEXPs the
- same as any other goal type.
-
-
-
Goal list
-
The main area displays all goals as SEXP
-trees. The dropdown at the top filters the list to show one type at a time;
-Primary, Secondary, or Bonus. Use New Obj. to append a new goal
-of the currently filtered type.
-
-
Goal properties
-
-
Field
Description
-
Type
Primary, Secondary, or Bonus. Changing this moves the goal
- into the corresponding type group.
-
Name
Internal identifier used in SEXPs such as
- goal-true and goal-false, and in mission log
- entries. Not shown to the player.
-
Goal text
Text displayed to the player in the briefing goal list
- and HUD objective display.
-
Score
Points awarded when this goal is completed.
-
Team
In multiplayer missions, the team this goal belongs
- to.
-
-
-
Goal flags
-
-
Flag
Description
-
Objective Invalid
Marks the goal as invalid from the start of
- the mission. Invalid goals are not shown to the player and are not evaluated.
- Goals can also be marked valid or invalid at runtime by SEXPs, making this
- useful for goals that are conditionally activated during play.
-
Don't Play Completion Music
Suppresses the event music stinger
- that normally plays when this goal is completed or failed.
Defines the objectives shown to the player at the end of the briefing and tracked on
+the HUD during the mission. When an objective is completed or failed a HUD popup notifies
+the player. Objectives are hidden during the briefing if the
+Toggle Showing Goals In Briefing flag is set in
+Mission Specs.
+
+
Objective types
+
Objective type is a classification that affects how objectives are displayed and which
+music plays on completion or failure. The actual consequences of an objective being met
+or failed — which debriefing stage the player sees, whether the campaign advances
+— are determined by SEXPs in the
+Debriefing Editor and the
+Campaign Editor, which can query objective state
+using operators like goal-true and goal-false.
+
+
Type
Description
+
Primary
Shown to the player from the start of the mission.
+ Completion or failure triggers the primary objective music stinger. By convention
+ these are the core objectives designers tie campaign progression and debriefing
+ outcomes to.
+
Secondary
Shown to the player from the start of the mission.
+ Completion or failure triggers the secondary objective music stinger. Designers
+ typically use these for optional objectives whose state is queried in the
+ debriefing or campaign for bonus outcomes.
+
Bonus
Hidden from the player until the objective is achieved, at
+ which point the objective text appears on the HUD. Their state is queryable by
+ SEXPs the same as any other objective type.
+
+
+
Objective list
+
The main area displays all objectives as SEXP
+trees. The dropdown at the top filters the list to show one type at a time;
+Primary, Secondary, or Bonus. Use New Objective to append a new
+objective of the currently filtered type.
+
+
Objective properties
+
+
Field
Description
+
Type
Primary, Secondary, or Bonus. Changing this moves the objective
+ into the corresponding type group.
+
Name
Internal identifier used in SEXPs such as
+ goal-true and goal-false, and in mission log
+ entries. Not shown to the player.
+
Objective text
Text displayed to the player in the briefing
+ objective list and HUD objective display.
+
Score
Points awarded when this objective is completed.
+
Team
In multiplayer missions, the team this objective belongs
+ to.
+
+
+
Objective flags
+
+
Flag
Description
+
Objective Invalid
Marks the objective as invalid from the start of
+ the mission. Invalid objectives are not shown to the player and are not
+ evaluated. Objectives can also be marked valid or invalid at runtime by SEXPs,
+ making this useful for objectives that are conditionally activated during
+ play.
+
Don't Play Completion Music
Suppresses the event music stinger
+ that normally plays when this objective is completed or failed.
must then be selected: Co-op, Team vs. Team, or
Dogfight (all players against all others).
Training
Intended for tutorial content. A Skip Training
- button appears on the briefing screen; selecting it marks all mission goals
+ button appears on the briefing screen; selecting it marks all mission objectives
complete and advances the campaign without the player having to fly the
mission.
Total counts: ships, wings, waypoint paths, jump nodes,
- mission events, mission goals, and messages.
+ mission events, mission objectives, and messages.
Ships
Every ship in the mission listed with its name, class, team,
and wing assignment.
Escort
Ships with the escort flag enabled in the
diff --git a/qtfred/help-src/doc/fundamentals.html b/qtfred/help-src/doc/fundamentals.html
index c6eb1410efa..6c2cab45c9e 100644
--- a/qtfred/help-src/doc/fundamentals.html
+++ b/qtfred/help-src/doc/fundamentals.html
@@ -31,7 +31,7 @@
1. Plan before you open QtFRED
A hostile fighter wing that arrives ~30 seconds in
A waypoint path for the transport to follow
Events: a timed trigger for the hostile arrival, a radio message when they arrive
-
A primary mission goal tied to the transport completing its route
+
A primary mission objective tied to the transport completing its route
A two-stage briefing and a debriefing
Knowing this upfront prevents building yourself into a corner. You will still
@@ -114,14 +114,14 @@
5. Send a message when the hostiles arrive
Save and test. The message should appear on screen as Epsilon jumps in.
-
6. Add a mission goal
-
Open Editors › Mission Goals. Add a primary goal:
+
6. Add a mission objective
+
Open Editors › Mission Objectives. Add a primary objective:
Description:Escort the transport to the rendezvous