Skip to content

Commit

Permalink
Merge pull request scp-fs2open#5811 from Goober5000/perform_on_missio…
Browse files Browse the repository at this point in the history
…n_skip

implement on-mission-skip SEXP
  • Loading branch information
Goober5000 authored Dec 9, 2023
2 parents e316c28 + 25d796a commit de50f69
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 30 deletions.
38 changes: 18 additions & 20 deletions code/mission/missioncampaign.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1642,19 +1642,19 @@ void mission_campaign_end_close()

/**
* Skip to the next mission in the campaign
* this also posts the state change by default. pass 0 to override that
* this also posts the state change
*/
void mission_campaign_skip_to_next(int start_game)
void mission_campaign_skip_to_next()
{
// mark mission as skipped
Campaign.missions[Campaign.current_mission].flags |= CMISSION_FLAG_SKIPPED;

// mark all goals/events complete
// these do not really matter, since is-previous-event-* and is-previous-goal-* sexps check
// to see if the mission was skipped, and use defaults accordingly.
mission_goal_mark_objectives_complete();
mission_goal_mark_events_complete();

// mark mission as skipped
Campaign.missions[Campaign.current_mission].flags |= CMISSION_FLAG_SKIPPED;

// store
mission_campaign_store_goals_and_events_and_variables();

Expand All @@ -1665,22 +1665,20 @@ void mission_campaign_skip_to_next(int start_game)
Player->failures_this_session = 0;
Player->show_skip_popup = 1;

if (start_game) {
// proceed to next mission or main hall
if ((Campaign.missions[Campaign.current_mission].flags & CMISSION_FLAG_HAS_LOOP) && (Campaign.loop_mission != -1)) {
// go to loop solicitation
gameseq_post_event(GS_EVENT_LOOP_BRIEF);
} else {
// closes out mission stuff, sets up next one
mission_campaign_mission_over();
// proceed to next mission or main hall
if ((Campaign.missions[Campaign.current_mission].flags & CMISSION_FLAG_HAS_LOOP) && (Campaign.loop_mission != -1)) {
// go to loop solicitation
gameseq_post_event(GS_EVENT_LOOP_BRIEF);
} else {
// closes out mission stuff, sets up next one
mission_campaign_mission_over();

if ( Campaign.next_mission == -1 || (The_mission.flags[Mission::Mission_Flags::End_to_mainhall]) ) {
// go to main hall, either the campaign is over or the FREDer requested it.
gameseq_post_event(GS_EVENT_MAIN_MENU);
} else {
// go to next mission
gameseq_post_event(GS_EVENT_START_GAME);
}
if ( Campaign.next_mission == -1 || (The_mission.flags[Mission::Mission_Flags::End_to_mainhall]) ) {
// go to main hall, either the campaign is over or the FREDer requested it.
gameseq_post_event(GS_EVENT_MAIN_MENU);
} else {
// go to next mission
gameseq_post_event(GS_EVENT_START_GAME);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion code/mission/missioncampaign.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ void mission_campaign_eval_next_mission();
int mission_campaign_previous_mission();

// proceeds to next mission in campaign
void mission_campaign_skip_to_next(int start_game = 1);
void mission_campaign_skip_to_next();

// break out of loop
void mission_campaign_exit_loop();
Expand Down
19 changes: 11 additions & 8 deletions code/mission/missiongoals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1280,21 +1280,24 @@ void mission_goal_fail_incomplete()
// to skip past training misisons
void mission_goal_mark_objectives_complete()
{
int i;

for (i = 0; i < (int)Mission_goals.size(); i++ ) {
Mission_goals[i].satisfied = GOAL_COMPLETE;
for (auto &g: Mission_goals) {
g.satisfied = GOAL_COMPLETE;
}
}

// small function used to mark all events as completed. Used in the skipping of missions.
void mission_goal_mark_events_complete()
{
int i;
for (auto &e: Mission_events) {
// Handle on-mission-skip SEXPs if we have any. We could search the entire
// SEXP tree, but requiring the operator to be at the root limits potential
// unexpected side-effects.
if ((e.formula >= 0) && (get_operator_const(e.formula) == OP_ON_MISSION_SKIP)) {
eval_sexp(e.formula);
}

for (i = 0; i < (int)Mission_events.size(); i++ ) {
Mission_events[i].result = 1;
Mission_events[i].flags |= MEF_EVENT_IS_DONE; // in lieu of setting formula to -1
e.result = 1;
e.flags |= MEF_EVENT_IS_DONE; // in lieu of setting formula to -1
}
}

Expand Down
32 changes: 32 additions & 0 deletions code/parse/sexp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ SCP_vector<sexp_oper> Operators = {
{ "when-argument", OP_WHEN_ARGUMENT, 3, INT_MAX, SEXP_CONDITIONAL_OPERATOR,}, // Goober5000
{ "every-time", OP_EVERY_TIME, 2, INT_MAX, SEXP_CONDITIONAL_OPERATOR,}, // Goober5000
{ "every-time-argument", OP_EVERY_TIME_ARGUMENT, 3, INT_MAX, SEXP_CONDITIONAL_OPERATOR,}, // Goober5000
{ "on-mission-skip", OP_ON_MISSION_SKIP, 1, INT_MAX, SEXP_CONDITIONAL_OPERATOR, }, // Goober5000
{ "functional-when", OP_FUNCTIONAL_WHEN, 4, INT_MAX, SEXP_CONDITIONAL_OPERATOR, }, // Goober5000
{ "if-then-else", OP_IF_THEN_ELSE, 3, INT_MAX, SEXP_CONDITIONAL_OPERATOR,}, // Goober5000
{ "functional-if-then-else", OP_FUNCTIONAL_IF_THEN_ELSE, 3, 3, SEXP_CONDITIONAL_OPERATOR, }, // Goober5000
Expand Down Expand Up @@ -10522,6 +10523,24 @@ int eval_perform_actions(int n, int op_num)

actions = n;
}
else if (op_num == OP_ON_MISSION_SKIP)
{
retval_first = true;
actions = n;

// if the player is skipping the mission, we'll unconditionally perform the actions
if ((Game_mode & GM_CAMPAIGN_MODE) && (Campaign.current_mission >= 0) && (Campaign.missions[Campaign.current_mission].flags & CMISSION_FLAG_SKIPPED))
{
return_cond = Locked_sexp_true;
actions_cond = Locked_sexp_true;
}
// if the player isn't skipping the mission (which is most of the time), we'll return false
else
{
return_cond = Locked_sexp_false;
actions_cond = Locked_sexp_false;
}
}
else
{
UNREACHABLE("Unsupported SEXP %d!", op_num);
Expand Down Expand Up @@ -27294,6 +27313,7 @@ int eval_sexp(int cur_node, int referenced_node)
case OP_PERFORM_ACTIONS_BOOL_FIRST:
case OP_PERFORM_ACTIONS_BOOL_LAST:
case OP_FUNCTIONAL_WHEN:
case OP_ON_MISSION_SKIP:
sexp_val = eval_perform_actions( node, op_num );
break;

Expand Down Expand Up @@ -30045,6 +30065,7 @@ int query_operator_return_type(int op)
case OP_WHEN_ARGUMENT:
case OP_EVERY_TIME:
case OP_EVERY_TIME_ARGUMENT:
case OP_ON_MISSION_SKIP:
case OP_IF_THEN_ELSE:
case OP_SWITCH:
case OP_INVALIDATE_ARGUMENT:
Expand Down Expand Up @@ -31293,6 +31314,7 @@ int query_operator_argument_type(int op, int argnum)
return OPF_NULL;

case OP_DO_FOR_VALID_ARGUMENTS:
case OP_ON_MISSION_SKIP:
return OPF_NULL;

case OP_RANDOM_OF:
Expand Down Expand Up @@ -35034,6 +35056,7 @@ int get_category(int op_id)
case OP_WHEN_ARGUMENT:
case OP_EVERY_TIME:
case OP_EVERY_TIME_ARGUMENT:
case OP_ON_MISSION_SKIP:
case OP_ANY_OF:
case OP_EVERY_OF:
case OP_RANDOM_OF:
Expand Down Expand Up @@ -37045,6 +37068,15 @@ SCP_vector<sexp_help_struct> Sexp_help = {
"\t2:\tBoolean expression that must be true for actions to take place.\r\n"
"\tRest:\tActions to take when the boolean expression becomes true." },

// Goober5000
{ OP_ON_MISSION_SKIP, "on-mission-skip (Conditional operator)\r\n"
"\tThis is a special operator that performs its actions when, and only when, the player chooses to skip the current mission. "
"Since the player may do this in the debriefing, mission designers should limit these actions to campaign-specific things like "
"adding entries to the tech room, allowing ships and weapons, and calling scripts. Note that this operator must be the top-level "
"operator in its event in order to work.\r\n\r\n"
"Takes 1 or more arguments...\r\n"
"\tAll:\tActions to take if the player chooses to skip the current mission.\r\n" },

// Goober5000
{ OP_IF_THEN_ELSE, "If-then-else (Conditional operator)\r\n"
"\tPerforms one action if a condition is true (like \"when\"), or another action (or set of actions) if the condition is false. "
Expand Down
3 changes: 2 additions & 1 deletion code/parse/sexp.h
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,8 @@ enum : int {
OP_FUNCTIONAL_WHEN, // Goober5000
OP_FOR_CONTAINER_DATA, // jg18
OP_FOR_MAP_CONTAINER_KEYS, // jg18

OP_ON_MISSION_SKIP, // Goober5000

// OP_CATEGORY_CHANGE
// sexpressions with side-effects

Expand Down

0 comments on commit de50f69

Please sign in to comment.