1 /*
2  * See Licensing and Copyright notice in naev.h
3  */
4 
5 
6 /**
7  * @file pilot_ew.c
8  *
9  * @brief Pilot electronic warfare information.
10  */
11 
12 
13 #include "pilot.h"
14 
15 #include "naev.h"
16 
17 #include <math.h>
18 
19 #include "log.h"
20 #include "space.h"
21 #include "player.h"
22 
23 static double sensor_curRange    = 0.; /**< Current base sensor range, used to calculate
24                                          what is in range and what isn't. */
25 
26 #define EVASION_SCALE        1.3225 /**< 1.15 squared. Ensures that ships have higher evasion than hide. */
27 #define SENSOR_DEFAULT_RANGE 7500   /**< The default sensor range for all ships. */
28 
29 /**
30  * @brief Updates the pilot's static electronic warfare properties.
31  *
32  *    @param p Pilot to update.
33  */
pilot_ewUpdateStatic(Pilot * p)34 void pilot_ewUpdateStatic( Pilot *p )
35 {
36    /*
37     * Unlike the other values, heat isn't squared. The ew_hide formula is thus
38     * equivalent to: ew_base_hide * ew_mass * sqrt(ew_heat)
39     */
40    p->ew_mass     = pow2( pilot_ewMass( p->solid->mass ) );
41    p->ew_heat     = pilot_ewHeat( p->heat_T );
42    p->ew_asteroid = pilot_ewAsteroid( p );
43    p->ew_hide     = p->ew_base_hide * p->ew_mass * p->ew_heat * p->ew_asteroid;
44    p->ew_evasion  = p->ew_hide * EVASION_SCALE;
45 }
46 
47 
48 /**
49  * @brief Updates the pilot's dynamic electronic warfare properties.
50  *
51  *    @param p Pilot to update.
52  */
pilot_ewUpdateDynamic(Pilot * p)53 void pilot_ewUpdateDynamic( Pilot *p )
54 {
55    /* Update hide. */
56    p->ew_heat     = pilot_ewHeat( p->heat_T );
57    p->ew_asteroid = pilot_ewAsteroid( p );
58    p->ew_hide     = p->ew_base_hide * p->ew_mass * p->ew_heat * p->ew_asteroid;
59 
60    /* Update evasion. */
61    p->ew_movement = pilot_ewMovement( VMOD(p->solid->vel) );
62    p->ew_evasion  = p->ew_hide * EVASION_SCALE;
63 }
64 
65 
66 /**
67  * @brief Gets the electronic warfare movement modifier for a given velocity.
68  *
69  *    @param vmod Velocity to get electronic warfare movement modifier of.
70  *    @return The electronic warfare movement modifier.
71  */
pilot_ewMovement(double vmod)72 double pilot_ewMovement( double vmod )
73 {
74    return 1. + vmod / 100.;
75 }
76 
77 
78 /**
79  * @brief Gets the electronic warfare heat modifier for a given temperature.
80  *
81  *    @param T Temperature of the ship.
82  *    @return The electronic warfare heat modifier.
83  */
pilot_ewHeat(double T)84 double pilot_ewHeat( double T )
85 {
86    return 1. - 0.001 * (T - CONST_SPACE_STAR_TEMP);
87 }
88 
89 
90 /**
91  * @brief Gets the electronic warfare mass modifier for a given mass.
92  *
93  *    @param mass Mass to get the electronic warfare mass modifier of.
94  *    @return The electronic warfare mass modifier.
95  */
pilot_ewMass(double mass)96 double pilot_ewMass( double mass )
97 {
98    return 1. / (.3 + sqrt(mass) / 30. );
99 }
100 
101 
102 /**
103  * @brief Gets the electronic warfare asteroid modifier.
104  *
105  *    @param pilot.
106  *    @return The electronic warfare asteroid modifier.
107  */
pilot_ewAsteroid(Pilot * p)108 double pilot_ewAsteroid( Pilot *p )
109 {
110    int i;
111 
112    i = space_isInField(&p->solid->pos);
113    if ( i>=0 )
114       return 1. + cur_system->asteroids[i].density;
115    else
116       return 1.;
117 }
118 
119 
120 /**
121  * @brief Updates the system's base sensor range.
122  */
pilot_updateSensorRange(void)123 void pilot_updateSensorRange (void)
124 {
125    /* Adjust sensor range based on system interference. */
126    /* See: http://www.wolframalpha.com/input/?i=y+%3D+7500+%2F+%28%28x+%2B+200%29+%2F+200%29+from+x%3D0+to+1000 */
127    sensor_curRange = SENSOR_DEFAULT_RANGE / ((cur_system->interference + 200) / 200.);
128 
129    /* Speeds up calculations as we compare it against vectors later on
130     * and we want to avoid actually calculating the sqrt(). */
131    sensor_curRange = pow2(sensor_curRange);
132 }
133 
134 
135 /**
136  * @brief Returns the default sensor range for the current system.
137  *
138  *    @return Sensor range.
139  */
pilot_sensorRange(void)140 double pilot_sensorRange( void )
141 {
142    return sensor_curRange;
143 }
144 
145 
146 /**
147  * @brief Check to see if a position is in range of the pilot.
148  *
149  *    @param p Pilot to check to see if position is in their sensor range.
150  *    @param x X position to check.
151  *    @param y Y position to check.
152  *    @return 1 if the position is in range, 0 if it isn't.
153  */
pilot_inRange(const Pilot * p,double x,double y)154 int pilot_inRange( const Pilot *p, double x, double y )
155 {
156    double d, sense;
157 
158    /* Get distance. */
159    d = pow2(x-p->solid->pos.x) + pow2(y-p->solid->pos.y);
160 
161    sense = sensor_curRange * p->ew_detect;
162    if (d < sense)
163       return 1;
164 
165    return 0;
166 }
167 
168 
169 /**
170  * @brief Check to see if a pilot is in sensor range of another.
171  *
172  *    @param p Pilot who is trying to check to see if other is in sensor range.
173  *    @param target Target of p to check to see if is in sensor range.
174  *    @return 1 if they are in range, 0 if they aren't and -1 if they are detected fuzzily.
175  */
pilot_inRangePilot(const Pilot * p,const Pilot * target)176 int pilot_inRangePilot( const Pilot *p, const Pilot *target )
177 {
178    double d, sense;
179 
180    /* Special case player or omni-visible. */
181    if ((pilot_isPlayer(p) && pilot_isFlag(target, PILOT_VISPLAYER)) ||
182          pilot_isFlag(target, PILOT_VISIBLE) ||
183          target->parent == p->id)
184       return 1;
185 
186    /* Get distance. */
187    d = vect_dist2( &p->solid->pos, &target->solid->pos );
188 
189    sense = sensor_curRange * p->ew_detect;
190    if (d * target->ew_evasion < sense)
191       return 1;
192    else if  (d * target->ew_hide < sense)
193       return -1;
194 
195    return 0;
196 }
197 
198 
199 /**
200  * @brief Check to see if a planet is in sensor range of the pilot.
201  *
202  *    @param p Pilot who is trying to check to see if the planet is in sensor range.
203  *    @param target Planet to see if is in sensor range.
204  *    @return 1 if they are in range, 0 if they aren't.
205  */
pilot_inRangePlanet(const Pilot * p,int target)206 int pilot_inRangePlanet( const Pilot *p, int target )
207 {
208    double d;
209    Planet *pnt;
210    double sense;
211 
212    /* pilot must exist */
213    if ( p == NULL )
214       return 0;
215 
216    /* Get the planet. */
217    pnt = cur_system->planets[target];
218 
219    /* target must not be virtual */
220    if ( !pnt->real )
221       return 0;
222 
223    sense = sensor_curRange * p->ew_detect;
224 
225    /* Get distance. */
226    d = vect_dist2( &p->solid->pos, &pnt->pos );
227 
228    if (d * pnt->hide < sense )
229       return 1;
230 
231    return 0;
232 }
233 
234 /**
235  * @brief Check to see if a jump point is in sensor range of the pilot.
236  *
237  *    @param p Pilot who is trying to check to see if the jump point is in sensor range.
238  *    @param target Jump point to see if is in sensor range.
239  *    @return 1 if they are in range, 0 if they aren't.
240  */
pilot_inRangeJump(const Pilot * p,int i)241 int pilot_inRangeJump( const Pilot *p, int i )
242 {
243    double d;
244    JumpPoint *jp;
245    double sense;
246    double hide;
247 
248    /* pilot must exist */
249    if ( p == NULL )
250       return 0;
251 
252    /* Get the jump point. */
253    jp = &cur_system->jumps[i];
254 
255    /* We don't want exit-only jumps. */
256    if (jp_isFlag(jp, JP_EXITONLY))
257       return 0;
258 
259    /* Handle hidden jumps separately, as they use a special range parameter. */
260    if (jp_isFlag(jp, JP_HIDDEN))
261       sense = pow(p->stats.misc_hidden_jump_detect, 2);
262    else
263       sense = sensor_curRange * p->ew_jump_detect;
264 
265    hide = jp->hide;
266 
267    /* Get distance. */
268    d = vect_dist2( &p->solid->pos, &jp->pos );
269 
270    if (d * hide < sense)
271       return 1;
272 
273    return 0;
274 }
275 
276 /**
277  * @brief Calculates the weapon lead (1. is 100%, 0. is 0%)..
278  *
279  *    @param p Pilot tracking.
280  *    @param t Pilot being tracked.
281  *    @param track Track limit of the weapon.
282  *    @return The lead angle of the weapon.
283  */
pilot_ewWeaponTrack(const Pilot * p,const Pilot * t,double track)284 double pilot_ewWeaponTrack( const Pilot *p, const Pilot *t, double track )
285 {
286    double limit, lead;
287 
288    limit = track * p->ew_detect;
289    if (t->ew_evasion * t->ew_movement < limit)
290       lead = 1.;
291    else
292       lead = MAX( 0., 1. - 0.5*((t->ew_evasion  * t->ew_movement)/limit - 1.));
293    return lead;
294 }
295 
296 
297 
298