|
1 | | -#include <vector> |
| 1 | +#include <algorithm> |
2 | 2 | #include <set> |
| 3 | +#include <vector> |
3 | 4 |
|
4 | 5 | #include "creature_functions.h" |
5 | 6 | #include "avatar.h" |
@@ -50,31 +51,52 @@ auto auto_find_hostile_target( |
50 | 51 | // iff safety margin (degrees). less accuracy, more paranoia |
51 | 52 | units::angle iff_hangle = units::from_degrees( 15 + option.area ); |
52 | 53 | float best_target_rating = -1.0f; // bigger is better |
53 | | - units::angle u_angle = {}; // player angle relative to turret |
54 | 54 | int boo_hoo = 0; // how many targets were passed due to IFF. Tragically. |
55 | 55 | bool self_area_iff = false; // Need to check if the target is near the vehicle we're a part of |
56 | | - bool area_iff = false; // Need to check distance from target to player |
57 | | - bool angle_iff = true; // Need to check if player is in a cone between us and target |
58 | | - int pldist = rl_dist( creature.pos(), u.pos() ); |
59 | 56 | map &here = get_map(); |
60 | 57 | vehicle *in_veh = creature.is_fake() |
61 | 58 | ? veh_pointer_or_null( here.veh_at( creature.pos() ) ) : nullptr; |
62 | | - // Skip IFF for adjacent player if weapon is safe (bullets/rockets protected by ballistics). |
63 | | - // Always apply IFF for weapons with dangerous trails (lasers) even when adjacent. |
64 | | - const bool apply_iff = pldist < iff_dist && ( option.trail || pldist > 1 ) && creature.sees( u ); |
65 | | - if( apply_iff ) { |
66 | | - area_iff = option.area > 0; |
67 | | - angle_iff = true; |
68 | | - // Player inside vehicle won't be hit by shots from the roof, |
69 | | - // so we can fire "through" them just fine. |
70 | | - const optional_vpart_position vp = here.veh_at( u.pos() ); |
| 59 | + |
| 60 | + struct iff_guard_creature { |
| 61 | + const Creature *critter = nullptr; |
| 62 | + int dist = 0; |
| 63 | + bool area_iff = false; |
| 64 | + bool angle_iff = true; |
| 65 | + units::angle angle = {}; |
| 66 | + units::angle iff_hangle = {}; |
| 67 | + }; |
| 68 | + |
| 69 | + auto protected_creatures = std::vector<iff_guard_creature> {}; |
| 70 | + for( Creature *const critter : g->get_creatures_if( [&]( const Creature & other ) { |
| 71 | + return &other != &creature && creature.attitude_to( other ) == Attitude::A_FRIENDLY; |
| 72 | + } ) ) { |
| 73 | + const auto critter_dist = rl_dist( creature.pos(), critter->pos() ); |
| 74 | + // Skip IFF for adjacent friendlies if weapon is safe (bullets/rockets protected by ballistics). |
| 75 | + // Always apply IFF for weapons with dangerous trails (lasers) even when adjacent. |
| 76 | + if( critter_dist >= iff_dist || ( !option.trail && critter_dist <= 1 ) || |
| 77 | + !creature.sees( *critter ) ) { |
| 78 | + continue; |
| 79 | + } |
| 80 | + |
| 81 | + auto guard = iff_guard_creature{ |
| 82 | + .critter = critter, |
| 83 | + .dist = critter_dist, |
| 84 | + .area_iff = option.area > 0, |
| 85 | + .angle = coord_to_angle( creature.pos(), critter->pos() ), |
| 86 | + .iff_hangle = iff_hangle, |
| 87 | + }; |
| 88 | + |
| 89 | + // Occupants inside the same vehicle are safe from the turret's direct line of fire, |
| 90 | + // but still need AoE protection. |
| 91 | + const optional_vpart_position vp = here.veh_at( critter->pos() ); |
71 | 92 | if( in_veh && veh_pointer_or_null( vp ) == in_veh && vp->is_inside() ) { |
72 | | - angle_iff = false; // No angle IFF, but possibly area IFF |
73 | | - } else if( pldist < 3 ) { |
| 93 | + guard.angle_iff = false; |
| 94 | + } else if( critter_dist < 3 ) { |
74 | 95 | // granularity increases with proximity |
75 | | - iff_hangle = ( pldist == 2 ? 30_degrees : 60_degrees ); |
| 96 | + guard.iff_hangle = critter_dist == 2 ? 30_degrees : 60_degrees; |
76 | 97 | } |
77 | | - u_angle = coord_to_angle( creature.pos(), u.pos() ); |
| 98 | + |
| 99 | + protected_creatures.push_back( guard ); |
78 | 100 | } |
79 | 101 |
|
80 | 102 | if( option.area > 0 && in_veh != nullptr ) { |
@@ -141,34 +163,33 @@ auto auto_find_hostile_target( |
141 | 163 | // No shooting stuff on vehicle we're a part of |
142 | 164 | continue; |
143 | 165 | } |
144 | | - if( area_iff && rl_dist( u.pos(), m->pos() ) <= option.area ) { |
145 | | - // Player in AoE |
146 | | - boo_hoo++; |
147 | | - continue; |
148 | | - } |
149 | | - // Hostility check can be expensive, but we need to inform the player of boo_hoo |
150 | | - // only when the target is actually "hostile enough" |
151 | | - bool maybe_boo = false; |
152 | | - if( angle_iff ) { |
153 | | - units::angle tangle = coord_to_angle( creature.pos(), m->pos() ); |
154 | | - units::angle diff = units::fabs( u_angle - tangle ); |
155 | | - // Player is in the angle and not too far behind the target |
156 | | - if( ( diff + iff_hangle > 360_degrees || diff < iff_hangle ) && |
157 | | - ( dist * 3 / 2 + 6 > pldist ) ) { |
158 | | - maybe_boo = true; |
| 166 | + const auto target_angle = coord_to_angle( creature.pos(), m->pos() ); |
| 167 | + const auto blocked_by_friendly = std::ranges::any_of( protected_creatures, |
| 168 | + [&]( const iff_guard_creature & guard ) { |
| 169 | + if( guard.area_iff && rl_dist( guard.critter->pos(), m->pos() ) <= option.area ) { |
| 170 | + return true; |
159 | 171 | } |
160 | | - } |
161 | | - if( !maybe_boo && ( ( mon_rating + hostile_adj ) / dist <= best_target_rating ) ) { |
| 172 | + if( !guard.angle_iff ) { |
| 173 | + return false; |
| 174 | + } |
| 175 | + |
| 176 | + const auto diff = units::fabs( guard.angle - target_angle ); |
| 177 | + return ( diff + guard.iff_hangle > 360_degrees || diff < guard.iff_hangle ) && |
| 178 | + ( dist * 3 / 2 + 6 > guard.dist ); |
| 179 | + } ); |
| 180 | + if( !blocked_by_friendly && ( ( mon_rating + hostile_adj ) / dist <= best_target_rating ) ) { |
162 | 181 | // "Would we skip the target even if it was hostile?" |
163 | 182 | // Helps avoid (possibly expensive) attitude calculation |
164 | 183 | continue; |
165 | 184 | } |
166 | 185 | if( m->attitude_to( u ) == Attitude::A_HOSTILE ) { |
167 | 186 | target_rating = ( mon_rating + hostile_adj ) / dist; |
168 | | - if( maybe_boo ) { |
| 187 | + if( blocked_by_friendly ) { |
169 | 188 | boo_hoo++; |
170 | 189 | continue; |
171 | 190 | } |
| 191 | + } else if( blocked_by_friendly ) { |
| 192 | + continue; |
172 | 193 | } |
173 | 194 | if( target_rating <= best_target_rating || target_rating <= 0 ) { |
174 | 195 | continue; // Handle this late so that boo_hoo++ can happen |
|
0 commit comments