@@ -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
14331412ship_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
0 commit comments