Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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/ai/ai.h
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ const char *ai_get_goal_target_name(const char *name, int *index);
void ai_clear_goal_target_names();

extern void init_ai_system(void);
extern void ai_attack_object(object *attacker, object *attacked, int ship_info_index = -1, int class_type = -1);
extern void ai_attack_object(object *attacker, object *attacked, int ship_info_index = -1, int class_type = -1, int turret_wip_index = -1);
extern void ai_evade_object(object *evader, object *evaded);
extern void ai_ignore_object(object *ignorer, object *ignored, int ignore_new);
extern void ai_ignore_wing(object *ignorer, int wingnum);
Expand All @@ -544,7 +544,7 @@ extern void init_ai_object(int objnum);
extern void ai_init(void); // Call this one to parse ai.tbl.
extern void ai_level_init(void); // Call before each level to reset AI

extern int ai_set_attack_subsystem(object *objp, int subnum);
extern int ai_set_attack_subsystem(object *objp, int subnum, int wip_index = -1);
extern int ai_issue_rearm_request(object *requester_objp); // Object requests rearm/repair.
extern int ai_abort_rearm_request(object *requester_objp); // Object aborts rearm/repair.
extern void ai_do_repair_frame(object *objp, ai_info *aip, float frametime); // Repair a ship object, player or AI.
Expand Down Expand Up @@ -597,7 +597,7 @@ extern int ai_maybe_fire_afterburner(object *objp, ai_info *aip);
extern void set_predicted_enemy_pos(vec3d *predicted_enemy_pos, object *pobjp, vec3d *enemy_pos, vec3d *enemy_vel, ai_info *aip);

extern int is_instructor(object *objp);
extern int find_enemy(int objnum, float range, int max_attackers, int ship_info_index = -1, int class_type = -1);
extern int find_enemy(int objnum, float range, int max_attackers, int ship_info_index = -1, int class_type = -1, int turret_wip_index = -1);

float ai_get_weapon_speed(const ship_weapon *swp);
void set_predicted_enemy_pos_turret(vec3d *predicted_enemy_pos, const vec3d *gun_pos, const object *pobjp, const vec3d *enemy_pos, const vec3d *enemy_vel, float weapon_speed, float time_enemy_in_range);
Expand All @@ -618,7 +618,7 @@ extern float dock_orient_and_approach(object *docker_objp, int docker_index, obj
void ai_set_mode_warp_out(object *objp, ai_info *aip);

// prototyped by Goober5000
int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float range, int max_attackers, int ship_info_index, int class_type = -1);
int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float range, int max_attackers, int ship_info_index, int class_type = -1, int turret_wip_index = -1);

// moved to header file by Goober5000
void ai_announce_ship_dying(object *dying_objp);
Expand Down
34 changes: 24 additions & 10 deletions code/ai/aicode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2210,6 +2210,7 @@ typedef struct eval_nearest_objnum {
int enemy_team_mask;
int enemy_ship_info_index;
int enemy_class_type;
int enemy_turret_wip_index;
int enemy_wing;
float range;
int max_attackers;
Expand Down Expand Up @@ -2247,6 +2248,10 @@ void evaluate_object_as_nearest_objnum(eval_nearest_objnum *eno)
if ((eno->enemy_class_type >= 0) && (Ship_info[shipp->ship_info_index].class_type != eno->enemy_class_type))
return;

// If only supposed to attack turrets carrying a certain weapon, don't attack ships without any such live turrets.
if ((eno->enemy_turret_wip_index >= 0) && (ship_get_turret_type_aggregate_hits(shipp, eno->enemy_turret_wip_index) <= 0.0f))
return;

// Don't keep firing at a ship that is in its death throes.
if (shipp->flags[Ship::Ship_Flags::Dying])
return;
Expand Down Expand Up @@ -2337,7 +2342,7 @@ void evaluate_object_as_nearest_objnum(eval_nearest_objnum *eno)
* @param ship_info_index If >=0, the enemy object must be of the specified ship class
* @param class_type If >=0, the enemy object must be of the specified ship type
*/
int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float range, int max_attackers, int ship_info_index, int class_type)
int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float range, int max_attackers, int ship_info_index, int class_type, int turret_wip_index)
{
object *danger_weapon_objp;
ai_info *aip;
Expand All @@ -2348,6 +2353,7 @@ int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float ra
eno.enemy_team_mask = enemy_team_mask;
eno.enemy_ship_info_index = ship_info_index;
eno.enemy_class_type = class_type;
eno.enemy_turret_wip_index = turret_wip_index;
eno.enemy_wing = enemy_wing;
eno.max_attackers = max_attackers;
eno.objnum = objnum;
Expand Down Expand Up @@ -2503,7 +2509,7 @@ int get_enemy_timestamp()
* @param ship_info_index If specified, restrict the search to enemies with this ship class
* @param class_type If specified, restrict the search to enemies with this ship type
*/
int find_enemy(int objnum, float range, int max_attackers, int ship_info_index, int class_type)
int find_enemy(int objnum, float range, int max_attackers, int ship_info_index, int class_type, int turret_wip_index)
{
int enemy_team_mask;

Expand All @@ -2529,8 +2535,10 @@ int find_enemy(int objnum, float range, int max_attackers, int ship_info_index,
if (ship_info_index < 0 || ship_info_index == target_shipp->ship_info_index) {
if (class_type < 0 || (target_shipp->ship_info_index >= 0 &&
class_type == Ship_info[target_shipp->ship_info_index].class_type)) {
if (!(Objects[target_objnum].flags[Object::Object_Flags::Protected])) {
return target_objnum;
if (turret_wip_index < 0 || (ship_get_turret_type_aggregate_hits(target_shipp, turret_wip_index) > 0.0f)) {
if (!(Objects[target_objnum].flags[Object::Object_Flags::Protected])) {
return target_objnum;
}
}
}
}
Expand All @@ -2541,7 +2549,7 @@ int find_enemy(int objnum, float range, int max_attackers, int ship_info_index,
}
}

return get_nearest_objnum(objnum, enemy_team_mask, aip->enemy_wing, range, max_attackers, ship_info_index, class_type);
return get_nearest_objnum(objnum, enemy_team_mask, aip->enemy_wing, range, max_attackers, ship_info_index, class_type, turret_wip_index);
} else {
aip->target_objnum = -1;
aip->target_signature = -1;
Expand Down Expand Up @@ -2582,7 +2590,7 @@ void force_avoid_player_check(object *objp, ai_info *aip)
* If attacked == NULL, then attack any enemy object.
* Attack point *rel_pos on object. This is for supporting attacking subsystems.
*/
void ai_attack_object(object* attacker, object* attacked, int ship_info_index, int class_type)
void ai_attack_object(object* attacker, object* attacked, int ship_info_index, int class_type, int turret_wip_index)
{
int temp;
ai_info* aip;
Expand Down Expand Up @@ -2615,7 +2623,7 @@ void ai_attack_object(object* attacker, object* attacked, int ship_info_index, i
if (attacked == nullptr) {
aip->choose_enemy_timestamp = timestamp(0);
// nebula safe
set_target_objnum(aip, find_enemy(OBJ_INDEX(attacker), 99999.9f, 4, ship_info_index, class_type));
set_target_objnum(aip, find_enemy(OBJ_INDEX(attacker), 99999.9f, 4, ship_info_index, class_type, turret_wip_index));
} else {
// check if we can see attacked in nebula
if (aip->target_objnum != OBJ_INDEX(attacked)) {
Expand Down Expand Up @@ -8168,7 +8176,7 @@ void ai_chase_ga(ai_info *aip, ship_info *sip)
// Make object *objp attack subsystem with ID = subnum.
// Return true if found a subsystem to attack, else return false.
// Note, can fail if subsystem exists, but has no hits.
int ai_set_attack_subsystem(object *objp, int subnum)
int ai_set_attack_subsystem(object *objp, int subnum, int wip_index)
{
int temp;
ship *shipp, *attacker_shipp;
Expand All @@ -8195,7 +8203,9 @@ int ai_set_attack_subsystem(object *objp, int subnum)
shipp = &Ships[attacked_objp->instance]; // need to get our target's ship pointer!!!

// When subnum is >= 0, it indicates a specific subsystem. Otherwise it is a subsystem type. See ai_submode
if (subnum >= 0)
if (wip_index >= 0) {
ssp = ship_find_first_subsys(shipp, SUBSYSTEM_TURRET, &objp->pos, wip_index);
} else if (subnum >= 0)
ssp = ship_get_indexed_subsys(shipp, subnum);
else
ssp = ship_find_first_subsys(shipp, -subnum, &objp->pos);
Expand Down Expand Up @@ -15526,18 +15536,22 @@ void ai_frame(int objnum)
Assert(En_objp->type == OBJ_SHIP);
if ( aip->targeted_subsys->current_hits <= 0.0f ) {
int subsys_type;
int turret_wip_index = -1;

if ( aip->goals[0].ai_mode == AI_GOAL_DISABLE_SHIP || aip->goals[0].ai_mode == AI_GOAL_DISABLE_SHIP_TACTICAL ) {
subsys_type = SUBSYSTEM_ENGINE;
} else if ( aip->goals[0].ai_mode == AI_GOAL_DISARM_SHIP || aip->goals[0].ai_mode == AI_GOAL_DISARM_SHIP_TACTICAL ) {
subsys_type = SUBSYSTEM_TURRET;
} else if (aip->goals[0].ai_mode == AI_GOAL_DESTROY_TURRET_TYPE || aip->goals[0].ai_mode == AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP) {
subsys_type = SUBSYSTEM_TURRET;
turret_wip_index = aip->goals[0].int_data;
} else {
subsys_type = -1;
}

if ( subsys_type != -1 ) {
ship_subsys *new_subsys;
new_subsys = ship_return_next_subsys(&Ships[En_objp->instance], subsys_type, &Pl_objp->pos);
new_subsys = ship_return_next_subsys(&Ships[En_objp->instance], subsys_type, &Pl_objp->pos, turret_wip_index);
if ( new_subsys != NULL ) {
set_targeted_subsys(aip, new_subsys, aip->target_objnum);
} else {
Expand Down
133 changes: 101 additions & 32 deletions code/ai/aigoals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,35 +87,37 @@ char Ai_dock_names[MAX_AI_DOCK_NAMES][NAME_LENGTH];
// Used in objecttypes.tbl to define custom ship types
ai_goal_list Ai_goal_names[] =
{
{ "Attack ship", AI_GOAL_CHASE, 0 },
{ "Dock", AI_GOAL_DOCK, 0 },
{ "Waypoints", AI_GOAL_WAYPOINTS, 0 },
{ "Waypoints once", AI_GOAL_WAYPOINTS_ONCE, 0 },
{ "Depart", AI_GOAL_WARP, 0 },
{ "Attack subsys", AI_GOAL_DESTROY_SUBSYSTEM, 0 },
{ "Form on wing", AI_GOAL_FORM_ON_WING, 0 },
{ "Undock", AI_GOAL_UNDOCK, 0 },
{ "Attack wing", AI_GOAL_CHASE_WING, 0 },
{ "Guard ship", AI_GOAL_GUARD, 0 },
{ "Disable ship", AI_GOAL_DISABLE_SHIP, 0 },
{ "Disable ship (tactical)",AI_GOAL_DISABLE_SHIP_TACTICAL, 0 },
{ "Disarm ship", AI_GOAL_DISARM_SHIP, 0 },
{ "Disarm ship (tactical)", AI_GOAL_DISARM_SHIP_TACTICAL, 0 },
{ "Attack any", AI_GOAL_CHASE_ANY, 0 },
{ "Ignore ship", AI_GOAL_IGNORE, 0 },
{ "Ignore ship (new)", AI_GOAL_IGNORE_NEW, 0 },
{ "Guard wing", AI_GOAL_GUARD_WING, 0 },
{ "Evade ship", AI_GOAL_EVADE_SHIP, 0 },
{ "Stay near ship", AI_GOAL_STAY_NEAR_SHIP, 0 },
{ "Keep safe dist", AI_GOAL_KEEP_SAFE_DISTANCE, 0 },
{ "Rearm ship", AI_GOAL_REARM_REPAIR, 0 },
{ "Stay still", AI_GOAL_STAY_STILL, 0 },
{ "Play dead", AI_GOAL_PLAY_DEAD, 0 },
{ "Play dead (persistent)", AI_GOAL_PLAY_DEAD_PERSISTENT, 0 },
{ "Attack weapon", AI_GOAL_CHASE_WEAPON, 0 },
{ "Fly to ship", AI_GOAL_FLY_TO_SHIP, 0 },
{ "Attack ship class", AI_GOAL_CHASE_SHIP_CLASS, 0 },
{ "Attack ship type", AI_GOAL_CHASE_SHIP_TYPE, 0 },
{ "Attack ship", AI_GOAL_CHASE, 0 },
{ "Dock", AI_GOAL_DOCK, 0 },
{ "Waypoints", AI_GOAL_WAYPOINTS, 0 },
{ "Waypoints once", AI_GOAL_WAYPOINTS_ONCE, 0 },
{ "Depart", AI_GOAL_WARP, 0 },
{ "Attack subsys", AI_GOAL_DESTROY_SUBSYSTEM, 0 },
{ "Form on wing", AI_GOAL_FORM_ON_WING, 0 },
{ "Undock", AI_GOAL_UNDOCK, 0 },
{ "Attack wing", AI_GOAL_CHASE_WING, 0 },
{ "Guard ship", AI_GOAL_GUARD, 0 },
{ "Disable ship", AI_GOAL_DISABLE_SHIP, 0 },
{ "Disable ship (tactical)", AI_GOAL_DISABLE_SHIP_TACTICAL, 0 },
{ "Disarm ship", AI_GOAL_DISARM_SHIP, 0 },
{ "Disarm ship (tactical)", AI_GOAL_DISARM_SHIP_TACTICAL, 0 },
{ "Attack any", AI_GOAL_CHASE_ANY, 0 },
{ "Ignore ship", AI_GOAL_IGNORE, 0 },
{ "Ignore ship (new)", AI_GOAL_IGNORE_NEW, 0 },
{ "Guard wing", AI_GOAL_GUARD_WING, 0 },
{ "Evade ship", AI_GOAL_EVADE_SHIP, 0 },
{ "Stay near ship", AI_GOAL_STAY_NEAR_SHIP, 0 },
{ "Keep safe dist", AI_GOAL_KEEP_SAFE_DISTANCE, 0 },
{ "Rearm ship", AI_GOAL_REARM_REPAIR, 0 },
{ "Stay still", AI_GOAL_STAY_STILL, 0 },
{ "Play dead", AI_GOAL_PLAY_DEAD, 0 },
{ "Play dead (persistent)", AI_GOAL_PLAY_DEAD_PERSISTENT, 0 },
{ "Attack weapon", AI_GOAL_CHASE_WEAPON, 0 },
{ "Fly to ship", AI_GOAL_FLY_TO_SHIP, 0 },
{ "Attack ship class", AI_GOAL_CHASE_SHIP_CLASS, 0 },
{ "Attack ship type", AI_GOAL_CHASE_SHIP_TYPE, 0 },
{ "Attack turret type", AI_GOAL_DESTROY_TURRET_TYPE, 0 },
{ "Attack turret type on ship",AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP,0 },
};

int Num_ai_goals = sizeof(Ai_goal_names) / sizeof(ai_goal_list);
Expand All @@ -131,6 +133,8 @@ const char *Ai_goal_text(ai_goal_mode goal, int submode)
case AI_GOAL_CHASE_WING:
case AI_GOAL_CHASE_SHIP_CLASS:
case AI_GOAL_CHASE_SHIP_TYPE:
case AI_GOAL_DESTROY_TURRET_TYPE:
case AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP:
return XSTR( "attack ", 474);
case AI_GOAL_DOCK:
return XSTR( "dock ", 475);
Expand Down Expand Up @@ -1045,6 +1049,17 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
aigp->ai_submode = -SUBSYSTEM_TURRET;
aigp->priority = eval_num(CDDR(node), priority_is_nan, priority_is_nan_forever);
break;

case OP_AI_DESTROY_TURRET_TYPE:
aigp->ai_mode = AI_GOAL_DESTROY_TURRET_TYPE;
aigp->int_data = weapon_info_lookup(ai_get_goal_target_name( CTEXT(CDR(node)), &dummy ));
break;

case OP_AI_DESTROY_TURRET_TYPE_ON_SHIP:
aigp->ai_mode = AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP;
aigp->int_data = weapon_info_lookup(ai_get_goal_target_name( CTEXT(CDR(node)), &dummy ));
aigp->target_name = ai_get_goal_target_name( CTEXT(CDDR(node)), &aigp->target_name_index );
break;

case OP_AI_WARP_OUT:
aigp->ai_mode = AI_GOAL_WARP;
Expand Down Expand Up @@ -1313,7 +1328,8 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
if (op == OP_AI_GUARD ||
op == OP_AI_GUARD_WING ||
op == OP_AI_WAYPOINTS ||
op == OP_AI_WAYPOINTS_ONCE) {
op == OP_AI_WAYPOINTS_ONCE ||
op == OP_AI_DESTROY_TURRET_TYPE) {
if (is_sexp_true(CDDDR(node)))
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
}
Expand All @@ -1326,7 +1342,8 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
op == OP_AI_DISARM_SHIP ||
op == OP_AI_DISARM_SHIP_TACTICAL ||
op == OP_AI_STAY_NEAR_SHIP ||
op == OP_AI_FLY_TO_SHIP) {
op == OP_AI_FLY_TO_SHIP ||
op == OP_AI_DESTROY_TURRET_TYPE_ON_SHIP) {
if (is_sexp_true(CDDDDR(node)))
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
}
Expand Down Expand Up @@ -1538,6 +1555,14 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more )
priority = eval_priority_et_seq(CDDR(node));
goalmode = AI_GOAL_REARM_REPAIR;
break;
case OP_AI_DESTROY_TURRET_TYPE:
priority = eval_priority_et_seq(CDDR(node));
goalmode = AI_GOAL_REARM_REPAIR;
break;
case OP_AI_DESTROY_TURRET_TYPE_ON_SHIP:
priority = eval_priority_et_seq(CDDDR(node));
goalmode = AI_GOAL_REARM_REPAIR;
Comment thread
Goober5000 marked this conversation as resolved.
Outdated
break;
default:
const ai_mode_lua* luaAIMode = ai_lua_find_mode(op);
if(luaAIMode != nullptr){
Expand Down Expand Up @@ -1836,6 +1861,19 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
}
return ai_achievability::NOT_KNOWN;
}
// similarly for attacking all turrets with a certain weapon class
if (aigp->ai_mode == AI_GOAL_DESTROY_TURRET_TYPE) {
for (auto so : list_range(&Ship_obj_list)) {
auto type_objp = &Objects[so->objnum];
if (type_objp->type != OBJ_SHIP || type_objp->flags[Object::Object_Flags::Should_be_dead] || aigp->int_data < 0 || aigp->int_data >= sz2i(Weapon_info.size()))
Comment thread
Goober5000 marked this conversation as resolved.
Outdated
continue;
ship *potential_target_shipp = &Ships[type_objp->instance];
if (ship_get_turret_type_aggregate_hits(potential_target_shipp, aigp->int_data) > 0.0f) {
return ai_achievability::ACHIEVABLE;
}
}
return ai_achievability::NOT_KNOWN;
}

return_val = ai_achievability::SATISFIED;

Expand Down Expand Up @@ -1912,6 +1950,19 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
}
break;
}
case AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP:
{
// shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
// destroyed when shipnum is valid

// can't determine the status of this goal if ship not valid
if (!target_ship_entry || !target_ship_entry->has_shipp() || aigp->int_data < 0 || aigp->int_data >= sz2i(Weapon_info.size())) {
Comment thread
Goober5000 marked this conversation as resolved.
Outdated
status = 0;
} else {
status = (ship_get_turret_type_aggregate_hits(target_ship_entry->shipp(), aigp->int_data) <= 0.0f) ? 1 : 0;
}
break;
}

// to guard or ignore a ship, the goal cannot continue if the ship being guarded is either destroyed
// or has departed.
Expand Down Expand Up @@ -2049,7 +2100,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
}

// Goober5000 - before doing anything else, check if this is a disarm goal for an arrived ship...
if ((status == SHIP_STATUS_ARRIVED) && (aigp->ai_mode == AI_GOAL_DISARM_SHIP || aigp->ai_mode == AI_GOAL_DISARM_SHIP_TACTICAL))
if ((status == SHIP_STATUS_ARRIVED) && (aigp->ai_mode == AI_GOAL_DISARM_SHIP || aigp->ai_mode == AI_GOAL_DISARM_SHIP_TACTICAL || aigp->ai_mode == AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP should be lumped in with standard disarm here. I think it needs its own separate handling, just like the other places.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. What other behavior are you envisioning? I suppose I could check whether any turret aboard the ship has the specified weapon.

{
if (target_ship_entry && target_ship_entry->has_shipp()) {
// if the ship has no turrets, we can't disarm it!
Expand Down Expand Up @@ -2212,6 +2263,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
case AI_GOAL_EVADE_SHIP:
case AI_GOAL_STAY_NEAR_SHIP:
case AI_GOAL_FLY_TO_SHIP:
case AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP:
{
if ( status == SHIP_STATUS_ARRIVED )
return ai_achievability::ACHIEVABLE;
Expand Down Expand Up @@ -2676,6 +2728,15 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
break;
}

case AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP: {
Assert(current_goal_target_ship && current_goal_target_ship->has_objp());
Assertion(current_goal->int_data >= 0, "The target of AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP must refer to a valid weapon class!");
other_obj = current_goal_target_ship->objp();
ai_attack_object( objp, other_obj);
ai_set_attack_subsystem( objp, 0, current_goal->int_data );
Comment thread
Goober5000 marked this conversation as resolved.
Outdated
break;
}

case AI_GOAL_CHASE_WING:
wingnum = wing_name_lookup( current_goal->target_name );
Assertion( wingnum >= 0, "The target of AI_GOAL_CHASE_WING must refer to a valid wing!" );
Expand All @@ -2686,6 +2747,12 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
ai_attack_object( objp, nullptr);
break;

case AI_GOAL_DESTROY_TURRET_TYPE:
Assertion(current_goal->int_data >= 0, "The target of AI_GOAL_DESTROY_TURRET_TYPE must refer to a valid weapon class!");
ai_attack_object( objp, nullptr, -1, -1, current_goal->int_data);
ai_set_attack_subsystem( objp, 0, current_goal->int_data );
Comment thread
Goober5000 marked this conversation as resolved.
Outdated
break;

// chase-ship-class is chase-any but restricted to a subset of ships
case AI_GOAL_CHASE_SHIP_CLASS:
{
Expand Down Expand Up @@ -2796,6 +2863,7 @@ void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *o
case AI_GOAL_DISABLE_SHIP_TACTICAL:
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISARM_SHIP_TACTICAL:
case AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP:
case AI_GOAL_IGNORE:
case AI_GOAL_IGNORE_NEW:
case AI_GOAL_EVADE_SHIP:
Expand Down Expand Up @@ -2876,6 +2944,7 @@ bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char
case AI_GOAL_IGNORE_NEW:
case AI_GOAL_EVADE_SHIP:
case AI_GOAL_STAY_NEAR_SHIP:
case AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP:
flag = 1;
}
break;
Expand Down
Loading
Loading