Skip to content

Commit 6b5f9c9

Browse files
authored
Cleanup and fix hud_target_missile (#7051)
* Cleanup and fix `hud_target_missile` The function `hud_target_missile` is what runs when the `Target Hostile Bomb or Bomber` control is pressed. Notably, it does not work if there is only 1 hostile bomber. The issue is that the loop within `hud_target_missile` is designed to search for the "next" target, but when there's only one valid target, the loop logic skips over it. But, `hud_target_missile` correctly will target if there is only 1 bomb though, so the fix is to just update the ship bomber logic similarly. This PR updates the logic of the bomber search so it matches the bombs search, that way the bomber search can target a bomber if there is only 1 present in the mission (just as how the existing bomb search will let you target 1 bomb if there is only 1 bomb in the mission currently). This PR also takes the opportunity to cleanup the function with more clear variable and function naming, along with two new internal bools which will be very helpful for later planned PRs. Fixes #7050. Tested and works as expected. * rework hud_target_hostile_bomb_or_bomber * appease clang * additional cleanup and modernization * more cleanup for select previous
1 parent beaeafe commit 6b5f9c9

File tree

5 files changed

+141
-126
lines changed

5 files changed

+141
-126
lines changed

code/hud/hudtarget.cpp

Lines changed: 136 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,27 +1257,6 @@ void hud_target_prev(int team_mask)
12571257
hud_target_common(team_mask, 0);
12581258
}
12591259

1260-
// -------------------------------------------------------------------
1261-
// advance_missile_obj()
1262-
//
1263-
missile_obj *advance_missile_obj(missile_obj *mo, int next_flag)
1264-
{
1265-
if (next_flag){
1266-
return GET_NEXT(mo);
1267-
}
1268-
1269-
return GET_LAST(mo);
1270-
}
1271-
1272-
ship_obj *advance_ship(ship_obj *so, int next_flag)
1273-
{
1274-
if (next_flag){
1275-
return GET_NEXT(so);
1276-
}
1277-
1278-
return GET_LAST(so);
1279-
}
1280-
12811260
/// \brief Iterates down to and selects the next target in a linked list
12821261
/// fashion ordered from closest to farthest from the
12831262
/// attacked_object_number, returning the next valid target.
@@ -1432,138 +1411,185 @@ static object* select_next_target_by_distance(const bool targeting_from_closest_
14321411

14331412
ship_obj *get_ship_obj_ptr_from_index(int index);
14341413
// -------------------------------------------------------------------
1435-
// hud_target_missile()
1414+
// hud_target_hostile_bomb_or_bomber()
14361415
//
14371416
// Target the closest locked missile that is locked on locked_obj
14381417
//
14391418
// input: source_obj => pointer to object that fired weapon
1440-
// next_flag => 0 -> previous 1 -> next
1419+
// next_flag => 0 -> previous 1 -> next
1420+
// target_bombs => true to target bombs or false to skip targeting of bombs
1421+
// target_bombers => true to target bombers or false to skip targeting of bombers
1422+
// target_closest => true to target closest objects instead of just next in list
14411423
//
1442-
// NOTE: this function is only allows targeting bombs
1443-
void hud_target_missile(object *source_obj, int next_flag)
1424+
// NOTE: this function allows targeting hostile bombs or bombers
1425+
void hud_target_hostile_bomb_or_bomber(object* source_obj, int next_flag, bool target_bombs, bool target_bombers, bool use_distance_sort)
14441426
{
1445-
missile_obj *end, *start, *mo;
1446-
object *A, *target_objp;
1447-
ai_info *aip;
1448-
weapon *wp;
1449-
weapon_info *wip;
1450-
int target_found = 0;
1451-
1452-
if ( source_obj->type != OBJ_SHIP )
1427+
if (source_obj->type != OBJ_SHIP)
14531428
return;
14541429

1455-
Assert( Ships[source_obj->instance].ai_index != -1 );
1456-
aip = &Ai_info[Ships[source_obj->instance].ai_index];
1430+
Assert(Ships[source_obj->instance].ai_index != -1);
14571431

1458-
end = &Missile_obj_list;
1459-
if (aip->target_objnum != -1) {
1460-
target_objp = &Objects[aip->target_objnum];
1461-
if ( target_objp->type == OBJ_WEAPON && Weapon_info[Weapons[target_objp->instance].weapon_info_index].subtype == WP_MISSILE ) { // must be a missile
1462-
end = missile_obj_return_address(Weapons[target_objp->instance].missile_list_index);
1463-
}
1464-
}
1432+
ai_info* aip = &Ai_info[Ships[source_obj->instance].ai_index];
1433+
float current_distance = 0.0f;
1434+
if (aip->target_objnum >= 0)
1435+
current_distance = hud_find_target_distance(&Objects[aip->target_objnum], Player_obj);
14651436

1466-
start = advance_missile_obj(end, next_flag);
1437+
object* A = nullptr;
1438+
object* nearest_object_ptr = nullptr;
1439+
object* minimum_object_ptr = nullptr;
1440+
object* maximum_object_ptr = nullptr;
14671441

1468-
for ( mo = start; mo != end; mo = advance_missile_obj(mo, next_flag) ) {
1469-
if ( mo == &Missile_obj_list ){
1470-
continue;
1471-
}
1442+
float nearest_distance = (next_flag > 0) ? 1e20f : 0.0f;
1443+
float minimum_distance = 1e20f;
1444+
float maximum_distance = 0.0f;
14721445

1473-
Assert(mo->objnum >= 0 && mo->objnum < MAX_OBJECTS);
1474-
A = &Objects[mo->objnum];
1475-
if (A->flags[Object::Object_Flags::Should_be_dead])
1476-
continue;
1446+
// sequential targeting - collect candidates
1447+
std::vector<object*> candidates;
1448+
int current_target_index = -1;
14771449

1478-
Assert(A->type == OBJ_WEAPON);
1479-
Assert((A->instance >= 0) && (A->instance < MAX_WEAPONS));
1480-
wp = &Weapons[A->instance];
1481-
wip = &Weapon_info[wp->weapon_info_index];
1450+
// helper lambda to process possible targets
1451+
auto process_candidate = [&](object* c_obj) {
1452+
if (use_distance_sort) {
1453+
// Distance targeting - skip current target
1454+
if (aip->target_objnum >= 0 && c_obj == &Objects[aip->target_objnum])
1455+
return;
14821456

1483-
// only allow targeting of bombs
1484-
if ( !(wip->wi_flags[Weapon::Info_Flags::Can_be_targeted]) ) {
1485-
if ( !(wip->wi_flags[Weapon::Info_Flags::Bomb]) ) {
1486-
continue;
1457+
float new_distance = hud_find_target_distance(c_obj, Player_obj);
1458+
1459+
// min/max tracking
1460+
if (new_distance <= minimum_distance) {
1461+
minimum_distance = new_distance;
1462+
minimum_object_ptr = c_obj;
1463+
}
1464+
if (new_distance >= maximum_distance) {
1465+
maximum_distance = new_distance;
1466+
maximum_object_ptr = c_obj;
14871467
}
1488-
}
14891468

1490-
if (wp->lssm_stage==3){
1491-
continue;
1469+
// nearest "next/previous" check
1470+
float diff = 0.0f;
1471+
if (next_flag > 0) { // forward - find closest target farther than current
1472+
diff = new_distance - current_distance;
1473+
if (diff > 0.0f) {
1474+
if (diff < (nearest_distance - current_distance)) {
1475+
nearest_distance = new_distance;
1476+
nearest_object_ptr = c_obj;
1477+
}
1478+
}
1479+
} else { // backward - find farthest target closer than current
1480+
diff = current_distance - new_distance;
1481+
if (diff > 0.0f) {
1482+
if (diff < (current_distance - nearest_distance)) {
1483+
nearest_distance = new_distance;
1484+
nearest_object_ptr = c_obj;
1485+
}
1486+
}
1487+
}
1488+
} else {
1489+
// sequential targeting - add to candidates
1490+
candidates.push_back(c_obj);
1491+
if (aip->target_objnum >= 0 && c_obj == &Objects[aip->target_objnum]) {
1492+
current_target_index = static_cast<int>(candidates.size()) - 1;
1493+
}
14921494
}
1495+
};
14931496

1494-
// only allow targeting of hostile bombs
1495-
if (!iff_x_attacks_y(Player_ship->team, obj_team(A))) {
1496-
continue;
1497-
}
1497+
// process bomb weapons
1498+
if (target_bombs) {
1499+
for (auto mo : list_range(&Missile_obj_list)) {
1500+
A = &Objects[mo->objnum];
14981501

1499-
if(hud_target_invalid_awacs(A)){
1500-
continue;
1501-
}
1502+
if (A->flags[Object::Object_Flags::Should_be_dead])
1503+
continue;
15021504

1503-
// if we've reached here, got a new target
1504-
target_found = TRUE;
1505-
set_target_objnum( aip, OBJ_INDEX(A) );
1506-
hud_shield_hit_reset(A);
1507-
break;
1508-
} // end for
1505+
weapon* wp = &Weapons[A->instance];
1506+
weapon_info* wip = &Weapon_info[wp->weapon_info_index];
15091507

1510-
if ( !target_found ) {
1511-
// if no bomb is found, search for bombers
1512-
ship_obj *startShip, *so;
1508+
// only allow targeting of bombs
1509+
if (!(wip->wi_flags[Weapon::Info_Flags::Can_be_targeted]) && !(wip->wi_flags[Weapon::Info_Flags::Bomb]))
1510+
continue;
15131511

1514-
if ( (aip->target_objnum != -1)
1515-
&& (Objects[aip->target_objnum].type == OBJ_SHIP)
1516-
&& ((Ship_info[Ships[Objects[aip->target_objnum].instance].ship_info_index].flags[Ship::Info_Flags::Bomber])
1517-
|| (Objects[aip->target_objnum].flags[Object::Object_Flags::Targetable_as_bomb]))) {
1518-
int index = Ships[Objects[aip->target_objnum].instance].ship_list_index;
1519-
startShip = get_ship_obj_ptr_from_index(index);
1520-
} else {
1521-
startShip = GET_FIRST(&Ship_obj_list);
1522-
}
1512+
if (wp->lssm_stage == 3)
1513+
continue;
15231514

1524-
for (so=advance_ship(startShip, next_flag); so!=startShip; so=advance_ship(so, next_flag)) {
1515+
if (!iff_x_attacks_y(Player_ship->team, obj_team(A)))
1516+
continue;
15251517

1526-
// don't look at header
1527-
if (so == &Ship_obj_list) {
1518+
if (hud_target_invalid_awacs(A))
15281519
continue;
1529-
}
15301520

1521+
process_candidate(A);
1522+
}
1523+
}
1524+
1525+
// process bomber ships
1526+
if (target_bombers) {
1527+
for (auto so : list_range(&Ship_obj_list)) {
15311528
A = &Objects[so->objnum];
1529+
15321530
if (A->flags[Object::Object_Flags::Should_be_dead])
15331531
continue;
15341532

1535-
Assertion(A->type == OBJ_SHIP, "hud_target_missile was about to call obj_team with a non-ship obejct with type %d. Please report!", A->type);
1536-
1537-
// only allow targeting of hostile bombs
1538-
if (!iff_x_attacks_y(Player_ship->team, obj_team(A))) {
1533+
if (!iff_x_attacks_y(Player_ship->team, obj_team(A)))
15391534
continue;
1540-
}
15411535

1542-
if(hud_target_invalid_awacs(A)){
1536+
if (hud_target_invalid_awacs(A))
15431537
continue;
1544-
}
15451538

15461539
// check if ship type is bomber
1547-
if ( !(Ship_info[Ships[A->instance].ship_info_index].flags[Ship::Info_Flags::Bomber]) && !(A->flags[Object::Object_Flags::Targetable_as_bomb]) ) {
1540+
if (!(Ship_info[Ships[A->instance].ship_info_index].flags[Ship::Info_Flags::Bomber]) && !(A->flags[Object::Object_Flags::Targetable_as_bomb]))
15481541
continue;
1549-
}
15501542

1551-
// check if ignore
1552-
if ( should_be_ignored(&Ships[A->instance]) ){
1543+
if (should_be_ignored(&Ships[A->instance]))
15531544
continue;
1554-
}
15551545

1556-
// found a good one
1557-
target_found = TRUE;
1558-
set_target_objnum( aip, OBJ_INDEX(A) );
1559-
hud_shield_hit_reset(A);
1560-
break;
1546+
process_candidate(A);
15611547
}
15621548
}
15631549

1564-
if ( !target_found ) {
1565-
snd_play( gamesnd_get_game_sound(GameSounds::TARGET_FAIL), 0.0f );
1550+
// choose final target
1551+
object* target_to_set = nullptr;
1552+
1553+
if (use_distance_sort) {
1554+
// distance targeting
1555+
if (nearest_object_ptr != nullptr) {
1556+
target_to_set = nearest_object_ptr;
1557+
} else {
1558+
if (next_flag > 0 && minimum_object_ptr != nullptr) {
1559+
target_to_set = minimum_object_ptr;
1560+
} else if (next_flag <= 0 && maximum_object_ptr != nullptr) {
1561+
target_to_set = maximum_object_ptr;
1562+
}
1563+
}
1564+
} else {
1565+
// sequential targeting
1566+
if (!candidates.empty()) {
1567+
if (current_target_index == -1) {
1568+
// no current target, pick first
1569+
target_to_set = candidates[0];
1570+
} else {
1571+
// cycle with wraparound
1572+
int next_index;
1573+
int num_candiates = static_cast<int>(candidates.size());
1574+
if (next_flag > 0) {
1575+
next_index = (current_target_index + 1) % num_candiates;
1576+
} else {
1577+
next_index = (current_target_index - 1 + num_candiates) % num_candiates;
1578+
}
1579+
target_to_set = candidates[next_index];
1580+
}
1581+
}
15661582
}
1583+
1584+
if (target_to_set != nullptr) {
1585+
// set if target found
1586+
set_target_objnum(aip, OBJ_INDEX(target_to_set));
1587+
hud_shield_hit_reset(target_to_set);
1588+
} else {
1589+
// fail sound if no target
1590+
snd_play(gamesnd_get_game_sound(GameSounds::TARGET_FAIL), 0.0f);
1591+
}
1592+
15671593
}
15681594

15691595
// Return !0 if shipp can be scanned, otherwise return 0

code/hud/hudtarget.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ void hud_target_subsystem_in_reticle();
101101
void hud_show_targeting_gauges(float frametime);
102102
void hud_target_targets_target();
103103
void hud_check_reticle_list();
104-
void hud_target_missile(object *source_obj, int next_flag);
104+
void hud_target_hostile_bomb_or_bomber(object *source_obj, int next_flag, bool target_bombs = true, bool target_bombers = true, bool target_closest = false);
105105
void hud_target_next_list(int hostile=1, int next_flag=1, int team_mask = -1, int attacked_objnum = -1, int play_fail_sound = TRUE, int filter = 0, int turret_attacking_target = 0);
106106
int hud_target_closest_repair_ship(int goal_objnum=-1);
107107
void hud_target_auto_target_next();

code/io/keycontrol.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2640,7 +2640,7 @@ int button_function(int n)
26402640

26412641
// target the next hostile target
26422642
case TARGET_NEXT_CLOSEST_HOSTILE:
2643-
hud_target_next_list();
2643+
hud_target_next_list(1,0);
26442644
break;
26452645

26462646
// target the previous closest hostile
@@ -2650,7 +2650,7 @@ int button_function(int n)
26502650

26512651
// target the next friendly ship
26522652
case TARGET_NEXT_CLOSEST_FRIENDLY:
2653-
hud_target_next_list(0);
2653+
hud_target_next_list(0,1);
26542654
break;
26552655

26562656
// target the closest friendly ship
@@ -2769,11 +2769,11 @@ int button_function(int n)
27692769
break;
27702770

27712771
case TARGET_NEXT_BOMB:
2772-
hud_target_missile(Player_obj, 1);
2772+
hud_target_hostile_bomb_or_bomber(Player_obj, 1, true, true, false);
27732773
break;
27742774

27752775
case TARGET_PREV_BOMB:
2776-
hud_target_missile(Player_obj, 0);
2776+
hud_target_hostile_bomb_or_bomber(Player_obj, 0, true, true, false);
27772777
break;
27782778

27792779
// wingman message: attack current target

code/weapon/weapon.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,6 @@ void weapon_area_apply_blast(const vec3d *force_apply_pos, object *ship_objp, co
10221022
int weapon_area_calc_damage(const object *objp, const vec3d *pos, float inner_rad, float outer_rad, float max_blast, float max_damage,
10231023
float *blast, float *damage, float limit);
10241024

1025-
missile_obj *missile_obj_return_address(int index);
10261025
void find_homing_object_cmeasures(const SCP_vector<object*> &cmeasure_list);
10271026

10281027
// THE FOLLOWING FUNCTION IS IN SHIP.CPP!!!!

code/weapon/weapons.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -367,16 +367,6 @@ void missle_obj_list_remove(int index)
367367
Missile_objs[index].flags = 0;
368368
}
369369

370-
/**
371-
* Called externally to generate an address from an index into
372-
* the Missile_objs[] array
373-
*/
374-
missile_obj *missile_obj_return_address(int index)
375-
{
376-
Assert(index >= 0 && index < MAX_MISSILE_OBJS);
377-
return &Missile_objs[index];
378-
}
379-
380370
/**
381371
* Return the index of Weapon_info[].name that is *name.
382372
*/

0 commit comments

Comments
 (0)