Skip to content
Open
8 changes: 4 additions & 4 deletions code/ai/ai.h
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ void ai_process( object * obj, int ai_index, float frametime );
const char *ai_get_goal_target_name(const char *name, int *index);

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 @@ -543,7 +543,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 @@ -596,7 +596,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 @@ -617,7 +617,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
44 changes: 29 additions & 15 deletions code/ai/aicode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2222,6 +2222,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 attacker_class_type;
int enemy_wing;
float range;
Expand Down Expand Up @@ -2259,6 +2260,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 @@ -2356,7 +2361,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 @@ -2367,6 +2372,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.attacker_class_type = Ship_info[Ships[Objects[objnum].instance].ship_info_index].class_type;
eno.enemy_wing = enemy_wing;
eno.max_attackers = max_attackers;
Expand Down Expand Up @@ -2523,7 +2529,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 Down Expand Up @@ -2551,13 +2557,15 @@ int find_enemy(int objnum, float range, int max_attackers, int ship_info_index,
if (target_shipp && iff_matches_mask(target_shipp->team, enemy_team_mask)) {
if (ship_info_index < 0 || ship_info_index == target_shipp->ship_info_index) {
if (class_type < 0 || class_type == Ship_info[target_shipp->ship_info_index].class_type) {
if (!(target_objp->flags[Object::Object_Flags::Protected])) {
// same as get_nearest_objnum: only skip an unpursued target for unconstrained searches
if (!The_mission.ai_profile->flags[AI::Profile_Flags::Fix_ai_target_recovery]
|| ship_info_index >= 0 || class_type >= 0
|| ai_class_type_actively_pursues(Ship_info[shipp->ship_info_index].class_type,
Ship_info[target_shipp->ship_info_index].class_type)) {
if (turret_wip_index < 0 || (ship_get_turret_type_aggregate_hits(target_shipp, turret_wip_index) > 0.0f)) {
if (!(target_objp->flags[Object::Object_Flags::Protected])) {
// same as get_nearest_objnum: only skip an unpursued target for unconstrained searches
if (!The_mission.ai_profile->flags[AI::Profile_Flags::Fix_ai_target_recovery]
|| ship_info_index >= 0 || class_type >= 0
|| ai_class_type_actively_pursues(Ship_info[shipp->ship_info_index].class_type,
Ship_info[target_shipp->ship_info_index].class_type)) {
return target_objnum;
}
}
}
}
Expand All @@ -2569,7 +2577,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 @@ -2610,7 +2618,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 @@ -2643,7 +2651,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 @@ -8205,7 +8213,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 @@ -8232,7 +8240,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 @@ -15577,18 +15587,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 All @@ -15597,8 +15611,8 @@ void ai_frame(int objnum)
set_targeted_subsys(aip, NULL, -1);
}
} else {
// targeted subsys is destroyed, so stop attacking it
set_targeted_subsys(aip, NULL, -1);
// targeted subsys is destroyed, so stop attacking it
}
}
}
Expand Down
Loading
Loading