Skip to content

Commit 69d48f8

Browse files
committed
address feedback
1 parent 40c69d9 commit 69d48f8

2 files changed

Lines changed: 54 additions & 41 deletions

File tree

code/ai/aigoals.cpp

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,32 @@ struct ship_registry_entry;
4747

4848
#define MAX_GOAL_PRIORITY 200
4949

50-
// define for which goals cause other goals to get purged
50+
// note: "purging" is not the same as "clearing" here
51+
// purging: any goal that no longer makes sense (i.e. is "invalid") in light of a new goal is removed
52+
// clearing: every goal is removed, including, ironically, the goal that caused the clearing
53+
5154
// Goober5000 - okay, this seems really stupid. If any ship in the mission is assigned a goal
5255
// in PURGE_GOALS_ALL_SHIPS, *every* other ship will have certain goals purged. So I added
5356
// PURGE_GOALS_ONE_SHIP for goals which should only purge other goals in the one ship.
5457
// Goober5000 - note that the new disable and disarm goals (AI_GOAL_DISABLE_SHIP_TACTICAL and
5558
// AI_GOAL_DISARM_SHIP_TACTICAL) do not purge ANY goals, not even the ones in the one ship
56-
[[nodiscard]] bool purge_goals_all_ships(ai_goal_mode ai_mode)
59+
[[nodiscard]] bool causes_invalid_goal_purge_all_ships(ai_goal_mode ai_mode)
5760
{
5861
return ai_mode == AI_GOAL_IGNORE || ai_mode == AI_GOAL_DISABLE_SHIP || ai_mode == AI_GOAL_DISARM_SHIP;
5962
}
60-
[[nodiscard]] bool purge_goals_one_ship(ai_goal_mode ai_mode)
63+
[[nodiscard]] bool causes_invalid_goal_purge_one_ship(ai_goal_mode ai_mode)
6164
{
6265
return ai_mode == AI_GOAL_IGNORE_NEW;
6366
}
6467

68+
// function for which goals cause other goals to be cleared -- see comments above on purging vs clearing
69+
[[nodiscard]] bool causes_goal_clearing(ai_goal_mode ai_mode)
70+
{
71+
return ((ai_mode == AI_GOAL_STAY_STILL && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_clear_goals_when_assigning_stay_still])
72+
|| (ai_mode == AI_GOAL_FORM_ON_WING && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_clear_goals_when_assigning_form_on_wing])
73+
|| (ai_mode == AI_GOAL_PLAY_DEAD));
74+
}
75+
6576
// goals given from the player to other ships in the game are also handled in this
6677
// code
6778

@@ -601,7 +612,7 @@ void ai_goal_purge_all_invalid_goals(ai_goal *aigp)
601612
ship_obj *sop;
602613

603614
// only purge goals if a new goal is one of the types in next statement
604-
if (!purge_goals_all_ships(aigp->ai_mode))
615+
if (!causes_invalid_goal_purge_all_ships(aigp->ai_mode))
605616
return;
606617

607618
for (sop = GET_FIRST(&Ship_obj_list); sop != END_OF_LIST(&Ship_obj_list); sop = GET_NEXT(sop))
@@ -770,10 +781,8 @@ void ai_add_goal_sub_player(ai_goal_type type, ai_goal_mode mode, int submode, c
770781
aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
771782

772783
// set up the clear-goals flag for certain goals
773-
if ((mode == AI_GOAL_STAY_STILL && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_clear_goals_when_assigning_stay_still])
774-
|| (mode == AI_GOAL_FORM_ON_WING && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_clear_goals_when_assigning_form_on_wing])
775-
|| (mode == AI_GOAL_PLAY_DEAD))
776-
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
784+
if (causes_goal_clearing(mode))
785+
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
777786

778787
// also set up the override, since it's no longer done automatically in ai_mission_goal_achievable
779788
if (mode == AI_GOAL_FORM_ON_WING && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_set_override_when_assigning_form_on_wing])
@@ -812,15 +821,15 @@ void ai_add_goal_sub_player(ai_goal_type type, ai_goal_mode mode, int submode, c
812821
// my new docking code. :)
813822
int ai_goal_find_empty_slot( ai_goal *goals, int active_goal )
814823
{
815-
int oldest_index = -1, empty_index = -1;
824+
int oldest_index = -1, first_empty_index = -1;
816825

817826
for ( int gindex = 0; gindex < MAX_AI_GOALS; gindex++ )
818827
{
819828
// get the index for the first unused goal
820829
if (goals[gindex].ai_mode == AI_GOAL_NONE)
821830
{
822-
if (empty_index < 0)
823-
empty_index = gindex;
831+
if (first_empty_index < 0)
832+
first_empty_index = gindex;
824833
}
825834
// if any goal needs to be purged when we add a goal, set the flag
826835
else if (goals[gindex].flags[AI::Goal_Flags::Purge_when_new_goal_added])
@@ -838,8 +847,8 @@ int ai_goal_find_empty_slot( ai_goal *goals, int active_goal )
838847
}
839848

840849
// try to use the first empty slot
841-
if (empty_index >= 0)
842-
return empty_index;
850+
if (first_empty_index >= 0)
851+
return first_empty_index;
843852

844853
// if we didn't find an empty slot, use the oldest goal's slot
845854
return oldest_index;
@@ -874,10 +883,8 @@ void ai_add_goal_sub_scripting(ai_goal_type type, ai_goal_mode mode, int submode
874883
aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
875884

876885
// set up the clear-goals flag for certain goals
877-
if ((mode == AI_GOAL_STAY_STILL && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_clear_goals_when_assigning_stay_still])
878-
|| (mode == AI_GOAL_FORM_ON_WING && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_clear_goals_when_assigning_form_on_wing])
879-
|| (mode == AI_GOAL_PLAY_DEAD))
880-
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
886+
if (causes_goal_clearing(mode))
887+
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
881888

882889
// also set up the override, since it's no longer done automatically in ai_mission_goal_achievable
883890
if (mode == AI_GOAL_FORM_ON_WING && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_set_override_when_assigning_form_on_wing])
@@ -2034,11 +2041,11 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
20342041
// Goober5000 - see note at PURGE_GOALS_ALL_SHIPS... this is bizarre
20352042
if ((status == SHIP_STATUS_ARRIVED) && !(aigp->flags[AI::Goal_Flags::Goals_purged]))
20362043
{
2037-
if (purge_goals_all_ships(aigp->ai_mode)) {
2044+
if (causes_invalid_goal_purge_all_ships(aigp->ai_mode)) {
20382045
ai_goal_purge_all_invalid_goals(aigp);
20392046
aigp->flags.set(AI::Goal_Flags::Goals_purged);
20402047
}
2041-
else if (purge_goals_one_ship(aigp->ai_mode)) {
2048+
else if (causes_invalid_goal_purge_one_ship(aigp->ai_mode)) {
20422049
ai_goal_purge_invalid_goals(aigp, aip->goals, aip, -1);
20432050
aigp->flags.set(AI::Goal_Flags::Goals_purged);
20442051
}
@@ -2395,7 +2402,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
23952402
object *objp = &Objects[objnum];
23962403
object *other_obj;
23972404
ai_goal *current_goal;
2398-
int wingnum, shipnum;
2405+
int wingnum;
23992406
int original_signature;
24002407

24012408
/* if (!stricmp(Ships[objp->instance].ship_name, "gtt comet")) {
@@ -2470,12 +2477,14 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
24702477
}
24712478

24722479

2473-
// save the current goal (if any) first, in case it's wiped out by the next action
2474-
int current_goal_ai_mode = current_goal->ai_mode;
2475-
auto current_goal_target_name = current_goal->target_name;
2476-
auto current_goal_target_ship = current_goal_target_name ? ship_registry_get(current_goal_target_name) : nullptr;
2480+
std::unique_ptr<ai_goal> current_goal_backup;
2481+
auto current_goal_target_ship = current_goal->target_name ? ship_registry_get(current_goal->target_name) : nullptr;
24772482

24782483
if (current_goal->flags[AI::Goal_Flags::Clear_all_goals_first]) {
2484+
// save the current goal before we wipe it out by clearing everything
2485+
current_goal_backup.reset(new ai_goal(*current_goal));
2486+
current_goal = current_goal_backup.get();
2487+
24792488
// stay-still, form-on-wing, and play-dead all clear their goals here...
24802489
//
24812490
// clear out the object's goals. Seems to me that if a ship is staying still for a purpose
@@ -2490,10 +2499,10 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
24902499
ai_clear_ship_goals(aip);
24912500
}
24922501

2493-
switch ( current_goal_ai_mode ) {
2502+
switch ( current_goal->ai_mode ) {
24942503

24952504
case AI_GOAL_CHASE:
2496-
if (current_goal_target_name) {
2505+
if (current_goal->target_name) {
24972506
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
24982507
other_obj = current_goal_target_ship->objp();
24992508
} else
@@ -2526,7 +2535,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
25262535
break;
25272536

25282537
case AI_GOAL_GUARD_WING:
2529-
wingnum = wing_name_lookup( current_goal_target_name );
2538+
wingnum = wing_name_lookup( current_goal->target_name );
25302539
Assert (wingnum != -1 ); // shouldn't get here if this is false!!!!
25312540
ai_set_guard_wing(objp, wingnum);
25322541
aip->submode_start_time = Missiontime;
@@ -2535,7 +2544,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
25352544
case AI_GOAL_WAYPOINTS: // do nothing for waypoints
25362545
case AI_GOAL_WAYPOINTS_ONCE: {
25372546
int flags = 0;
2538-
if (current_goal_ai_mode == AI_GOAL_WAYPOINTS)
2547+
if (current_goal->ai_mode == AI_GOAL_WAYPOINTS)
25392548
flags |= WPF_REPEAT;
25402549
if (current_goal->flags[AI::Goal_Flags::Waypoints_in_reverse])
25412550
flags |= WPF_BACKTRACK;
@@ -2560,7 +2569,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
25602569
// goal cannot continue. Spit out a warning and remove the goal.
25612570

25622571
// Goober5000 - do we have a specific ship to undock from?
2563-
if (current_goal_target_name)
2572+
if (current_goal->target_name)
25642573
{
25652574
// hmm, perhaps he was destroyed
25662575
if (!current_goal_target_ship || !current_goal_target_ship->has_objp())
@@ -2629,7 +2638,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
26292638
ai_set_attack_subsystem( objp, current_goal->ai_submode ); // submode stored the subsystem type
26302639

26312640
// don't protect-ship for tactical goals
2632-
if (current_goal_ai_mode != AI_GOAL_DESTROY_SUBSYSTEM && current_goal_ai_mode != AI_GOAL_DISABLE_SHIP_TACTICAL && current_goal_ai_mode != AI_GOAL_DISARM_SHIP_TACTICAL) {
2641+
if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM && current_goal->ai_mode != AI_GOAL_DISABLE_SHIP_TACTICAL && current_goal->ai_mode != AI_GOAL_DISARM_SHIP_TACTICAL) {
26332642
if (aip->target_objnum != -1) {
26342643
int class_type = Ship_info[current_goal_target_ship->shipp()->ship_info_index].class_type;
26352644
// Only protect if _not_ a capital ship. We don't want the Lucifer accidentally getting protected.
@@ -2644,7 +2653,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
26442653
}
26452654

26462655
case AI_GOAL_CHASE_WING:
2647-
wingnum = wing_name_lookup( current_goal_target_name );
2656+
wingnum = wing_name_lookup( current_goal->target_name );
26482657
Assertion( wingnum >= 0, "The target of AI_GOAL_CHASE_WING must refer to a valid wing!" );
26492658
ai_attack_wing(objp, wingnum);
26502659
break;
@@ -2656,7 +2665,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
26562665
// chase-ship-class is chase-any but restricted to a subset of ships
26572666
case AI_GOAL_CHASE_SHIP_CLASS:
26582667
{
2659-
int ship_info_index = ship_info_lookup(current_goal_target_name);
2668+
int ship_info_index = ship_info_lookup(current_goal->target_name);
26602669
Assertion(ship_info_index >= 0, "The target of AI_GOAL_CHASE_SHIP_CLASS must refer to a valid ship class!");
26612670
ai_attack_object(objp, nullptr, ship_info_index);
26622671
break;
@@ -2733,7 +2742,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
27332742
break;
27342743

27352744
default:
2736-
UNREACHABLE("unsupported goal of %d found in ai_process_mission_orders. Please report to the SCP", current_goal_ai_mode);
2745+
UNREACHABLE("unsupported goal of %d found in ai_process_mission_orders. Please report to the SCP", current_goal->ai_mode);
27372746
break;
27382747
}
27392748

code/parse/sexp.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39975,8 +39975,11 @@ SCP_vector<sexp_help_struct> Sexp_help = {
3997539975

3997639976
{ OP_AI_STAY_STILL, "Ai-stay-still (Ship goal)\r\n"
3997739977
"\tCauses the specified ship to stay still. The ship will do nothing until attacked at "
39978-
"which time the ship will come to life and defend itself. By default all goals on the ship's goal list will be cleared when this goal runs.\r\n\r\n"
39979-
"Takes 2 arguments...\r\n"
39978+
"which time the ship will come to life and defend itself.\r\n\r\n"
39979+
"By default all goals on the ship's goal list will be cleared when this goal runs, which means that the ship forgets both "
39980+
"this goal and all previous goals, and if it receives any other goal in any way, "
39981+
"it will immediately begin a new behavior. Use the optional sexp flag (argument 3) to prevent this from happening.\r\n\r\n"
39982+
"Takes 2 to 3 arguments...\r\n"
3998039983
"\t1:\tShip or waypoint the ship staying still will directly face (currently not implemented)\r\n"
3998139984
"\t2:\tGoal priority (number between 0 and 89).\r\n"
3998239985
"\t3:\tWhether to clear all goals (optional). If not specified this will be true, or the value defined in ai_profiles.\r\n"
@@ -39986,10 +39989,9 @@ SCP_vector<sexp_help_struct> Sexp_help = {
3998639989
"\tCauses the specified ship to pretend that it is dead and not do anything. This "
3998739990
"expression should be used to indicate that a ship has no pilot and cannot respond "
3998839991
"to any enemy threats. A ship playing dead will not respond to any attack.\r\n\r\n"
39989-
"Do note that all goals on the ship's goal list will be cleared when this goal runs, which means that the ship forgets both "
39990-
"this goal and all previous goals, and that if it receives any other goal in any way, "
39991-
"it will immediately come back to life. Use ai-play-dead-persistent to prevent this "
39992-
"from happening.\r\n\r\n"
39992+
"By default all goals on the ship's goal list will be cleared when this goal runs, which means that the ship forgets both "
39993+
"this goal and all previous goals, and if it receives any other goal in any way, "
39994+
"it will immediately come back to life. Use ai-play-dead-persistent to prevent this from happening.\r\n\r\n"
3999339995
"Takes 1 argument...\r\n"
3999439996
"\t1:\tGoal priority (number between 0 and 89)." },
3999539997

@@ -40005,8 +40007,10 @@ SCP_vector<sexp_help_struct> Sexp_help = {
4000540007

4000640008
{ OP_AI_FORM_ON_WING, "Ai-form-on-wing (Ship Goal)\r\n"
4000740009
"\tCauses the ship to form on the specified ship's wing. This works analogous to the "
40008-
"player order, and by default will cause all goals on the ship's goal list to be cleared when this goal runs. "
40009-
"By default it will also take priority over all other goals.\r\n\r\n"
40010+
"player order, and by default will cause all goals on the ship's goal list to be cleared when this goal runs, which means that the ship forgets both "
40011+
"this goal and all previous goals, and if it receives any other goal in any way, "
40012+
"it will immediately begin a new behavior. By default it will also be given an internal override flag that will cause it to "
40013+
"take priority over all other goals.\r\n\r\n"
4001040014
"Takes 1 to 5 arguments...\r\n"
4001140015
"\t1:\tShip to form on.\r\n"
4001240016
"\t2:\tGoal priority (number between 0 and 89, optional). If not specified this will be 99, or the number defined in ai_profiles.\r\n"

0 commit comments

Comments
 (0)