Skip to content

Commit 414cada

Browse files
committed
add Clear_all_goals_first goal flag, allow it to be used with any goal, and adapt goal assignment accordingly
1 parent 279182e commit 414cada

2 files changed

Lines changed: 67 additions & 57 deletions

File tree

code/ai/ai_flags.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,12 @@ namespace AI {
4545
Subsys_needs_fixup, // when set, the subsystem index (for a destroy subsystem goal) is invalid and must be gotten from the subsys name stored in docker.name field!!
4646
Goal_override, // paired with ai_goal_type::DYNAMIC to mean this goal overrides any other goal
4747
Purge, // purge this goal next time we process
48-
Goals_purged, // this goal has already caused other goals to get purged
48+
Goals_purged, // this goal has already caused other goals to get purged (because it is something like ai-disarm that renders other goals invalid)
4949
Depart_sound_played,// Goober5000 - replacement for AL's hack ;)
5050
Target_own_team, // this attack goal is allowed to target friendlies
5151
Afterburn_hard, // afterburn as hard as possible to the goal
5252
Waypoints_in_reverse, // decrement instead of increment
53+
Clear_all_goals_first, // this goal wipes all goals (including itself) before it runs (handled separately, and in a different place, from purging invalid goals)
5354

5455
NUM_VALUES
5556
};

code/ai/aigoals.cpp

Lines changed: 65 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,10 @@ void ai_add_goal_sub_player(ai_goal_type type, ai_goal_mode mode, int submode, c
753753
if ( target_name != NULL )
754754
aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
755755

756+
// set up the clear-goals flag for certain goals
757+
if (mode == AI_GOAL_STAY_STILL || mode == AI_GOAL_FORM_ON_WING || mode == AI_GOAL_PLAY_DEAD)
758+
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
759+
756760
if (The_mission.ai_profile->flags[AI::Profile_Flags::Player_orders_afterburn_hard])
757761
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
758762

@@ -834,6 +838,10 @@ void ai_add_goal_sub_scripting(ai_goal_type type, ai_goal_mode mode, int submode
834838
if ( target_name != NULL )
835839
aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
836840

841+
// set up the clear-goals flag for certain goals
842+
if (mode == AI_GOAL_STAY_STILL || mode == AI_GOAL_FORM_ON_WING || mode == AI_GOAL_PLAY_DEAD)
843+
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
844+
837845
aigp->priority = priority;
838846
aigp->int_data = int_data;
839847
aigp->float_data = float_data;
@@ -1020,6 +1028,7 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
10201028
aigp->ai_mode = AI_GOAL_STAY_STILL;
10211029
aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index); // waypoint path name;
10221030
aigp->priority = eval_num(CDDR(node), priority_is_nan, priority_is_nan_forever);
1031+
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
10231032
break;
10241033

10251034
case OP_AI_DOCK:
@@ -1038,6 +1047,9 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
10381047
break;
10391048

10401049
case OP_AI_PLAY_DEAD:
1050+
// we don't clear out ship goals for the "persistent" goal variant
1051+
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
1052+
FALLTHROUGH;
10411053
case OP_AI_PLAY_DEAD_PERSISTENT:
10421054
aigp->priority = eval_num(CDR(node), priority_is_nan, priority_is_nan_forever);
10431055
aigp->ai_mode = (op == OP_AI_PLAY_DEAD) ? AI_GOAL_PLAY_DEAD : AI_GOAL_PLAY_DEAD_PERSISTENT;
@@ -1079,6 +1091,7 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
10791091
aigp->priority = 99;
10801092
aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index);
10811093
aigp->ai_mode = AI_GOAL_FORM_ON_WING;
1094+
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
10821095
break;
10831096

10841097
case OP_AI_CHASE:
@@ -1914,7 +1927,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
19141927
ai_goal_purge_invalid_goals(aigp, aip->goals, aip, -1);
19151928
aigp->flags.set(AI::Goal_Flags::Goals_purged);
19161929
}
1917-
}
1930+
}
19181931

19191932
// if we are docking, validate the docking indices on both ships. We might have to change names to indices.
19201933
// only enter this calculation if the ship we are docking with has arrived. If the ship is gone, then
@@ -2338,14 +2351,32 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
23382351
}
23392352

23402353

2354+
// save the current goal (if any) first, in case it's wiped out by the next action
2355+
int current_goal_ai_mode = current_goal->ai_mode;
2356+
auto current_goal_target_name = current_goal->target_name;
2357+
auto current_goal_target_ship = current_goal_target_name ? ship_registry_get(current_goal_target_name) : nullptr;
23412358

2342-
switch ( current_goal->ai_mode ) {
2359+
if (current_goal->flags[AI::Goal_Flags::Clear_all_goals_first]) {
2360+
// stay-still, form-on-wing, and play-dead all clear their goals here...
2361+
//
2362+
// clear out the object's goals. Seems to me that if a ship is staying still for a purpose
2363+
// then we need to clear everything out since there is not a real way to get rid of this goal
2364+
//
2365+
// for form on wing, we need to clear out all goals for this ship, and then call the form on wing AI code
2366+
//
2367+
// if a ship is playing dead, MWA says that it shouldn't try to do anything else.
2368+
//
2369+
// clearing out goals is okay here since we are now what mode to set this AI object to.
2370+
2371+
ai_clear_ship_goals(aip);
2372+
}
2373+
2374+
switch ( current_goal_ai_mode ) {
23432375

23442376
case AI_GOAL_CHASE:
2345-
if ( current_goal->target_name ) {
2346-
shipnum = ship_name_lookup( current_goal->target_name );
2347-
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
2348-
other_obj = &Objects[Ships[shipnum].objnum];
2377+
if (current_goal_target_name) {
2378+
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
2379+
other_obj = current_goal_target_ship->objp();
23492380
} else
23502381
other_obj = NULL; // we get this case when we tell ship to engage enemy!
23512382

@@ -2362,9 +2393,8 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
23622393
break;
23632394

23642395
case AI_GOAL_GUARD:
2365-
shipnum = ship_name_lookup( current_goal->target_name );
2366-
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
2367-
other_obj = &Objects[Ships[shipnum].objnum];
2396+
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
2397+
other_obj = current_goal_target_ship->objp();
23682398
// shipnum and other_obj are the shipnumber and object pointer of the object that you should
23692399
// guard.
23702400
if (objp != other_obj) {
@@ -2377,7 +2407,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
23772407
break;
23782408

23792409
case AI_GOAL_GUARD_WING:
2380-
wingnum = wing_name_lookup( current_goal->target_name );
2410+
wingnum = wing_name_lookup( current_goal_target_name );
23812411
Assert (wingnum != -1 ); // shouldn't get here if this is false!!!!
23822412
ai_set_guard_wing(objp, wingnum);
23832413
aip->submode_start_time = Missiontime;
@@ -2386,7 +2416,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
23862416
case AI_GOAL_WAYPOINTS: // do nothing for waypoints
23872417
case AI_GOAL_WAYPOINTS_ONCE: {
23882418
int flags = 0;
2389-
if (current_goal->ai_mode == AI_GOAL_WAYPOINTS)
2419+
if (current_goal_ai_mode == AI_GOAL_WAYPOINTS)
23902420
flags |= WPF_REPEAT;
23912421
if (current_goal->flags[AI::Goal_Flags::Waypoints_in_reverse])
23922422
flags |= WPF_BACKTRACK;
@@ -2395,9 +2425,8 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
23952425
}
23962426

23972427
case AI_GOAL_DOCK: {
2398-
shipnum = ship_name_lookup( current_goal->target_name );
2399-
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
2400-
other_obj = &Objects[Ships[shipnum].objnum];
2428+
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
2429+
other_obj = current_goal_target_ship->objp();
24012430

24022431
// be sure that we have indices for docking points here! If we ever had names, they should
24032432
// get fixed up in goal_achievable so that the points can be checked there for validity
@@ -2407,24 +2436,22 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
24072436
}
24082437

24092438
case AI_GOAL_UNDOCK:
2410-
// try to find the object which which this object is docked with. Use that object as the
2439+
// try to find the object with which this object is docked. Use that object as the
24112440
// "other object" for the undocking proceedure. If "other object" isn't found, then the undock
24122441
// goal cannot continue. Spit out a warning and remove the goal.
24132442

24142443
// Goober5000 - do we have a specific ship to undock from?
2415-
if ( current_goal->target_name != NULL )
2444+
if (current_goal_target_name)
24162445
{
2417-
shipnum = ship_name_lookup( current_goal->target_name );
2418-
24192446
// hmm, perhaps he was destroyed
2420-
if (shipnum == -1)
2447+
if (!current_goal_target_ship || !current_goal_target_ship->has_objp())
24212448
{
24222449
other_obj = NULL;
24232450
}
24242451
// he exists... let's undock from him
24252452
else
24262453
{
2427-
other_obj = &Objects[Ships[shipnum].objnum];
2454+
other_obj = current_goal_target_ship->objp();
24282455
}
24292456
}
24302457
// no specific ship
@@ -2477,16 +2504,15 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
24772504
case AI_GOAL_DISABLE_SHIP_TACTICAL:
24782505
case AI_GOAL_DISARM_SHIP:
24792506
case AI_GOAL_DISARM_SHIP_TACTICAL: {
2480-
shipnum = ship_name_lookup( current_goal->target_name );
2481-
Assert( shipnum >= 0 );
2482-
other_obj = &Objects[Ships[shipnum].objnum];
2507+
Assert(current_goal_target_ship && current_goal_target_ship->has_objp());
2508+
other_obj = current_goal_target_ship->objp();
24832509
ai_attack_object( objp, other_obj);
24842510
ai_set_attack_subsystem( objp, current_goal->ai_submode ); // submode stored the subsystem type
24852511

24862512
// don't protect-ship for tactical goals
2487-
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) {
2513+
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) {
24882514
if (aip->target_objnum != -1) {
2489-
int class_type = Ship_info[Ships[shipnum].ship_info_index].class_type;
2515+
int class_type = Ship_info[current_goal_target_ship->shipp()->ship_info_index].class_type;
24902516
// Only protect if _not_ a capital ship. We don't want the Lucifer accidentally getting protected.
24912517
if (class_type >= 0 && Ship_types[class_type].flags[Ship::Type_Info_Flags::AI_protected_on_cripple])
24922518
Objects[aip->target_objnum].flags.set(Object::Object_Flags::Protected);
@@ -2499,7 +2525,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
24992525
}
25002526

25012527
case AI_GOAL_CHASE_WING:
2502-
wingnum = wing_name_lookup( current_goal->target_name );
2528+
wingnum = wing_name_lookup( current_goal_target_name );
25032529
Assertion( wingnum >= 0, "The target of AI_GOAL_CHASE_WING must refer to a valid wing!" );
25042530
ai_attack_wing(objp, wingnum);
25052531
break;
@@ -2510,7 +2536,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
25102536

25112537
// chase-ship-class is chase-any but restricted to a subset of ships
25122538
case AI_GOAL_CHASE_SHIP_CLASS:
2513-
shipnum = ship_info_lookup( current_goal->target_name );
2539+
shipnum = ship_info_lookup( current_goal_target_name );
25142540
Assertion( shipnum >= 0, "The target of AI_GOAL_CHASE_SHIP_CLASS must refer to a valid ship class!" );
25152541
ai_attack_object( objp, nullptr, shipnum );
25162542
break;
@@ -2521,44 +2547,29 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
25212547
}
25222548

25232549
case AI_GOAL_EVADE_SHIP:
2524-
shipnum = ship_name_lookup( current_goal->target_name );
2525-
Assert( shipnum >= 0 );
2526-
other_obj = &Objects[Ships[shipnum].objnum];
2550+
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
2551+
other_obj = current_goal_target_ship->objp();
25272552
ai_evade_object( objp, other_obj);
25282553
break;
25292554

25302555
case AI_GOAL_STAY_STILL:
2556+
// NOTE: goal clearing moved above this enclosing switch block
25312557
// for now, ignore any other parameters!!!!
2532-
// clear out the object's goals. Seems to me that if a ship is staying still for a purpose
2533-
// then we need to clear everything out since there is not a real way to get rid of this goal
2534-
// clearing out goals is okay here since we are now what mode to set this AI object to.
2535-
ai_clear_ship_goals( aip );
25362558
ai_stay_still( objp, NULL );
25372559
break;
25382560

25392561
case AI_GOAL_PLAY_DEAD:
25402562
case AI_GOAL_PLAY_DEAD_PERSISTENT:
2541-
// we don't clear out ship goals for the "persistent" goal variant
2542-
if (current_goal->ai_mode == AI_GOAL_PLAY_DEAD)
2543-
{
2544-
// if a ship is playing dead, MWA says that it shouldn't try to do anything else.
2545-
// clearing out goals is okay here since we are now what mode to set this AI object to.
2546-
ai_clear_ship_goals(aip);
2547-
}
2563+
// NOTE: goal clearing moved above this enclosing switch block
25482564
aip->mode = AIM_PLAY_DEAD;
25492565
aip->submode = -1;
25502566
aip->submode_start_time = Missiontime;
25512567
break;
25522568

25532569
case AI_GOAL_FORM_ON_WING:
2554-
// get the ship first, since we're going to wipe it out next
2555-
shipnum = ship_name_lookup( current_goal->target_name );
2556-
Assert( shipnum >= 0 );
2557-
other_obj = &Objects[Ships[shipnum].objnum];
2558-
// for form on wing, we need to clear out all goals for this ship, and then call the form
2559-
// on wing AI code
2560-
// clearing out goals is okay here since we are now what mode to set this AI object to.
2561-
ai_clear_ship_goals( aip );
2570+
// NOTE: goal clearing moved above this enclosing switch block
2571+
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
2572+
other_obj = current_goal_target_ship->objp();
25622573
ai_form_on_wing( objp, other_obj );
25632574
break;
25642575

@@ -2567,9 +2578,8 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
25672578
case AI_GOAL_STAY_NEAR_SHIP:
25682579
case AI_GOAL_FLY_TO_SHIP:
25692580
{
2570-
shipnum = ship_name_lookup( current_goal->target_name );
2571-
Assert( shipnum >= 0 );
2572-
other_obj = &Objects[Ships[shipnum].objnum];
2581+
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
2582+
other_obj = current_goal_target_ship->objp();
25732583
float dist = current_goal->float_data; // How far away to stay from ship. Should be set in SEXP?
25742584
int additional_data = current_goal->int_data; // Whether to target a particular point as if escorting
25752585
ai_do_stay_near(objp, other_obj, dist, additional_data);
@@ -2584,9 +2594,8 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
25842594
break;
25852595

25862596
case AI_GOAL_REARM_REPAIR:
2587-
shipnum = ship_name_lookup( current_goal->target_name );
2588-
Assert( shipnum >= 0 );
2589-
other_obj = &Objects[Ships[shipnum].objnum];
2597+
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
2598+
other_obj = current_goal_target_ship->objp();
25902599
ai_rearm_repair( objp, current_goal->docker.index, other_obj, current_goal->dockee.index );
25912600
break;
25922601

@@ -2595,7 +2604,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
25952604
break;
25962605

25972606
default:
2598-
UNREACHABLE("unsupported goal of %d found in ai_process_mission_orders. Please report to the SCP", current_goal->ai_mode);
2607+
UNREACHABLE("unsupported goal of %d found in ai_process_mission_orders. Please report to the SCP", current_goal_ai_mode);
25992608
break;
26002609
}
26012610

0 commit comments

Comments
 (0)