naev 0.12.5
pilot_ew.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <math.h>
11
12#include "naev.h"
14
15#include "array.h"
16#include "hook.h"
17#include "pilot.h"
18#include "player.h"
19#include "player_autonav.h"
20#include "space.h"
21
22static double ew_interference = 1.;
23
24/*
25 * Prototypes.
26 */
27static void pilot_ewUpdate( Pilot *p );
28static double pilot_ewMass( double mass );
29static double pilot_ewAsteroid( const Pilot *p );
30static double pilot_ewJumpPoint( const Pilot *p );
31static int pilot_ewStealthGetNearby( const Pilot *p, double *mod, int *close,
32 int *isplayer );
33
40double pilot_ewScanTime( const Pilot *p )
41{
42 /* Here larger is "better", so we divide by ew_hide and ew_signature instead
43 * of multiplying. */
44 return pow( p->solid.mass, 1. / 3. ) * 1.25 /
45 ( p->stats.ew_hide * p->stats.ew_signature ) *
46 p->stats.ew_scanned_time;
47}
48
55{
56 const Pilot *target = pilot_getTarget( p );
57 if ( target == NULL )
58 return;
59
60 /* Player did bad stuff and is getting scanned. */
61 if ( pilot_isPlayer( target ) && pilot_hasIllegal( target, p->faction ) )
63
64 /* Scan time. */
65 p->scantimer = pilot_ewScanTime( p );
66}
67
74int pilot_ewScanCheck( const Pilot *p )
75{
76 if ( p->target == p->id )
77 return 0;
78 return ( p->scantimer < 0. );
79}
80
84static void pilot_ewUpdate( Pilot *p )
85{
86 p->ew_detection = p->ew_mass * p->ew_asteroid * p->stats.ew_hide;
87 p->ew_signature =
88 p->ew_detection * 0.75 * ew_interference * p->stats.ew_signature;
89 /* For stealth we apply the ew_asteroid and ew_interference bonus outside of
90 * the max, so that it can go below 1000 with in-system features. */
91 p->ew_stealth =
92 MAX( 1000., p->ew_mass * p->stats.ew_hide * 0.25 * p->stats.ew_stealth ) *
93 p->ew_asteroid * ew_interference * p->ew_jumppoint;
94}
95
102{
103 p->ew_mass = pilot_ewMass( p->solid.mass );
104 pilot_ewUpdate( p );
105}
106
113void pilot_ewUpdateDynamic( Pilot *p, double dt )
114{
115 Pilot *t;
116
117 /* Electronic warfare values. */
119 p->ew_jumppoint = pilot_ewJumpPoint( p );
120 pilot_ewUpdate( p );
121
122 /* Already scanned so skipping. */
123 if ( p->scantimer < 0. )
124 return;
125
126 /* Get the target pilot. */
127 t = pilot_getTarget( p );
128 if ( t == NULL )
129 return;
130
131 /* Must be in evasion range. */
132 if ( vec2_dist2( &p->solid.pos, &t->solid.pos ) <
133 pow2( MAX( 0., p->stats.ew_detect * p->stats.ew_track *
134 t->ew_signature ) ) ) {
135 p->scantimer -= dt;
136
137 if ( p->scantimer < 0. ) {
138 HookParam hparam = { .type = HOOK_PARAM_PILOT };
139 /* Run scan hook. */
140 hparam.u.lp = t->id;
141 pilot_runHookParam( p, PILOT_HOOK_SCAN, &hparam, 1 );
142 /* Run scanned hook. */
143 hparam.u.lp = p->id;
144 pilot_runHookParam( t, PILOT_HOOK_SCANNED, &hparam, 1 );
145
146 /* Run outfit stuff. */
149
150 /* TODO handle case the player finished scanning by setting a flag or
151 * something. */
152 }
153 }
154}
155
162static double pilot_ewMass( double mass )
163{
164 return pow( mass, 1. / 1.8 ) * 350.;
165}
166
173static double pilot_ewAsteroid( const Pilot *p )
174{
175 int infield = asteroids_inField( &p->solid.pos );
176 if ( infield < 0 )
177 return 1.;
178 return 1. / ( 1. + 0.4 * cur_system->asteroids[infield].density );
179}
180
187static double pilot_ewJumpPoint( const Pilot *p )
188{
189 /* Don't have to really check when not in stealth. */
190 if ( !pilot_isFlag( p, PILOT_STEALTH ) )
191 return 1.;
192
193 /* Gets lower when near jump. */
194 for ( int i = 0; i < array_size( cur_system->jumps ); i++ ) {
195 JumpPoint *jp = &cur_system->jumps[i];
196 if ( jp_isFlag( jp, JP_EXITONLY ) || jp_isFlag( jp, JP_HIDDEN ) )
197 continue;
198 double d2 = vec2_dist2( &jp->pos, &p->solid.pos );
199 if ( d2 <= pow2( EW_JUMP_BONUS_RANGE ) )
200 return MAX( 0.5, sqrt( d2 ) / EW_JUMP_BONUS_RANGE );
201 }
202 return 1.;
203}
204
209{
210 ew_interference = 1. / ( 1. + cur_system->interference / 100. );
211}
212
218double pilot_sensorRange( void )
219{
220 return 7500.;
221}
222
231int pilot_inRange( const Pilot *p, double x, double y )
232{
233 double d = pow2( x - p->solid.pos.x ) + pow2( y - p->solid.pos.y );
234 double sr = pilot_sensorRange();
235 double sense = MAX( 0., sr * p->stats.ew_detect );
236 if ( d < pow2( sense ) )
237 return 1;
238 /* points can't evade.
239 sense = MAX( 0., sr * p->stats.ew_signature );
240 if (d > pow2(sense))
241 return -1;
242 */
243 return 0;
244}
245
256int pilot_inRangePilot( const Pilot *p, const Pilot *target, double *dist2 )
257{
258 double d;
259
260 /* Get distance if needed. */
261 if ( dist2 != NULL )
262 *dist2 = vec2_dist2( &p->solid.pos, &target->solid.pos );
263
264 /* Special case player or omni-visible. */
265 if ( ( pilot_isPlayer( p ) && pilot_isFlag( target, PILOT_VISPLAYER ) ) ||
266 pilot_isFlag( target, PILOT_VISIBLE ) || target->parent == p->id )
267 return 1;
268
269 /* Stealth detection. */
270 if ( pilot_isFlag( target, PILOT_STEALTH ) && !pilot_areAllies( p, target ) )
271 return 0;
272
273 /* No stealth so normal detection. */
274 d = ( dist2 != NULL ? *dist2
275 : vec2_dist2( &p->solid.pos, &target->solid.pos ) );
276 if ( d < pow2( MAX( 0., p->stats.ew_detect * p->stats.ew_track *
277 target->ew_signature ) ) )
278 return 1;
279 else if ( d < pow2( MAX( 0., p->stats.ew_detect * target->ew_detection ) ) )
280 return -1;
281
282 return 0;
283}
284
293int pilot_inRangeSpob( const Pilot *p, int target )
294{
295 double d;
296 Spob *pnt;
297 double sense;
298
299 /* pilot must exist */
300 if ( p == NULL )
301 return 0;
302
303 /* Get the spob. */
304 pnt = cur_system->spobs[target];
305 sense = EW_SPOBDETECT_DIST;
306
307 /* Get distance. */
308 d = vec2_dist2( &p->solid.pos, &pnt->pos );
309 if ( d < pow2( MAX( 0., sense * p->stats.ew_detect * pnt->hide ) ) )
310 return 1;
311
312 return 0;
313}
314
324int pilot_inRangeAsteroid( const Pilot *p, int ast, int fie )
325{
326 double d;
327 Asteroid *as;
329 double sense;
330
331 /* pilot must exist */
332 if ( p == NULL )
333 return 0;
334
335 /* Get the asteroid. */
336 f = &cur_system->asteroids[fie];
337 as = &f->asteroids[ast];
338
339 /* TODO something better than this. */
340 sense = EW_ASTEROID_DIST;
341
342 /* Get distance. */
343 d = vec2_dist2( &p->solid.pos, &as->sol.pos );
344
345 /* By default, asteroid's hide score is 1. It could be made changeable via
346 * xml.*/
347 if ( d < pow2( MAX( 0., sense * p->stats.ew_detect ) ) )
348 return 1;
349
350 return 0;
351}
352
361int pilot_inRangeJump( const Pilot *p, int i )
362{
363 double d;
364 JumpPoint *jp;
365 double sense;
366 double hide;
367
368 /* pilot must exist */
369 if ( p == NULL )
370 return 0;
371
372 /* Get the jump point. */
373 jp = &cur_system->jumps[i];
374
375 /* We don't want exit-only jumps. */
376 if ( jp_isFlag( jp, JP_EXITONLY ) )
377 return 0;
378
379 /* Jumps with 0. hide are considered to be highway points and always visible.
380 */
381 hide = jp->hide;
382 if ( hide == 0. )
383 return 1;
384
385 sense = EW_JUMPDETECT_DIST * p->stats.ew_jump_detect * p->stats.ew_detect;
386 /* Handle hidden jumps separately, as they use a special range parameter. */
387 if ( jp_isFlag( jp, JP_HIDDEN ) )
388 sense *= p->stats.misc_hidden_jump_detect;
389
390 /* Get distance. */
391 d = vec2_dist2( &p->solid.pos, &jp->pos );
392 if ( d < pow2( MAX( 0., sense * hide ) ) )
393 return 1;
394
395 return 0;
396}
397
407double pilot_ewWeaponTrack( const Pilot *p, const Pilot *t, double trackmin,
408 double trackmax )
409{
410 double mod;
411 if ( t == NULL )
412 return 1.;
413 mod = p->stats.ew_track * p->stats.ew_detect;
414 return CLAMP(
415 0., 1.,
416 ( t->ew_signature * mod - trackmin ) /
417 MAX( trackmax - trackmin,
418 DOUBLE_TOL ) ); /* Avoid divide by zero if trackmax==trackmin. */
419}
420
431static int pilot_ewStealthGetNearby( const Pilot *p, double *mod, int *close,
432 int *isplayer )
433{
434 Pilot *const *ps;
435 int n;
436
437 /* Check nearby non-allies. */
438 if ( mod != NULL )
439 *mod = 0.;
440 if ( close != NULL )
441 *close = 0;
442 if ( isplayer != NULL )
443 *isplayer = 0;
444 n = 0;
445 ps = pilot_getAll();
446 for ( int i = 0; i < array_size( ps ); i++ ) {
447 double dist;
448 Pilot *t = ps[i];
449
450 /* Quick checks first. */
451 if ( pilot_isDisabled( t ) )
452 continue;
453 if ( !pilot_canTarget( t ) )
454 continue;
455
456 /* Must not be landing nor taking off. */
457 if ( pilot_isFlag( t, PILOT_LANDING ) ||
458 pilot_isFlag( t, PILOT_TAKEOFF ) )
459 continue;
460
461 /* Allies are ignored. */
462 if ( pilot_areAllies( p, t ) )
463 continue;
464
465 /* Stealthed pilots don't reduce stealth. */
466 // if (pilot_isFlag(t, PILOT_STEALTH))
467 // continue;
468
469 /* Compute distance. */
470 dist = vec2_dist2( &p->solid.pos, &t->solid.pos );
471 /* TODO maybe not hardcode the close value. */
472 if ( ( close != NULL ) && !pilot_isFlag( t, PILOT_STEALTH ) &&
473 ( dist <
474 pow2( MAX( 0., p->ew_stealth * t->stats.ew_detect * 1.5 ) ) ) )
475 ( *close )++;
476 if ( dist > pow2( MAX( 0., p->ew_stealth * t->stats.ew_detect ) ) )
477 continue;
478
479 if ( mod != NULL )
480 *mod += 1.0 - sqrt( dist ) / ( p->ew_stealth * t->stats.ew_detect );
481
482 /* We found a pilot that is in range. */
483 n++;
484 if ( ( isplayer != NULL ) && pilot_isPlayer( t ) )
485 *isplayer = 1;
486 }
487
488 return n;
489}
490
497void pilot_ewUpdateStealth( Pilot *p, double dt )
498{
499 int n, close, isplayer;
500 double mod;
501
502 if ( !pilot_isFlag( p, PILOT_STEALTH ) )
503 return;
504
505 /* Get nearby pilots. */
506 if ( pilot_isPlayer( p ) ) {
507 if ( pilot_isFlag( p, PILOT_NONTARGETABLE ) )
508 return;
509
510 n = pilot_ewStealthGetNearby( p, &mod, &close, &isplayer );
511
512 /* Stop autonav if pilots are nearby. */
513 if ( close > 0 )
515 } else
516 n = pilot_ewStealthGetNearby( p, &mod, NULL, &isplayer );
517
518 /* Increases if nobody nearby. */
519 if ( n == 0 ) {
520 p->ew_stealth_timer += dt * 5e3 / p->ew_stealth;
521 if ( p->ew_stealth_timer > 1. )
522 p->ew_stealth_timer = 1.;
523 }
524 /* Otherwise decreases. */
525 else {
526 p->ew_stealth_timer -=
527 dt * ( p->ew_stealth / 10e3 + mod ) * p->stats.ew_stealth_timer;
528 if ( p->ew_stealth_timer < 0. ) {
529 pilot_destealth( p );
530 if ( pilot_isPlayer( p ) )
531 player_message( "#r%s", _( "You have been uncovered!" ) );
532 else if ( isplayer )
533 player_message( _( "You have uncovered '#%c%s#0'!" ),
534 pilot_getFactionColourChar( p ), p->name );
535 ai_discovered( p );
536 }
537 }
538}
539
544{
545 int n, ret;
546
547 if ( pilot_isFlag( p, PILOT_STEALTH ) )
548 return 1;
549
550 /* Can't stealth if locked on. */
551 /*
552 if ( p->lockons > 0 )
553 return 0;
554 */
555
556 /* Can't stealth if pilots nearby. */
557 pilot_setFlag( p, PILOT_STEALTH );
558 n = pilot_ewStealthGetNearby( p, NULL, NULL, NULL );
559 if ( n > 0 ) {
560 pilot_rmFlag( p, PILOT_STEALTH );
561 return 0;
562 }
563
564 /* Turn off all weapon sets. */
567
568 /* Turn off outfits. */
569 ret = pilot_outfitOffAllStealth( p );
570
571 /* Got into stealth. */
572 if ( !pilot_outfitLOnstealth( p ) || ret )
573 pilot_calcStats( p );
574 p->ew_stealth_timer = 0.;
575
576 /* Run hook. */
577 const HookParam hparam = { .type = HOOK_PARAM_BOOL, .u.b = 1 };
578 pilot_runHookParam( p, PILOT_HOOK_STEALTH, &hparam, 1 );
579 return 1;
580}
581
586{
587 if ( !pilot_isFlag( p, PILOT_STEALTH ) )
588 return;
589 pilot_rmFlag( p, PILOT_STEALTH );
590 p->ew_stealth_timer = 0.;
591 if ( !pilot_outfitLOnstealth( p ) )
592 pilot_calcStats( p );
593
594 /* Run hook. */
595 const HookParam hparam = { .type = HOOK_PARAM_BOOL, .u.b = 0 };
596 pilot_runHookParam( p, PILOT_HOOK_STEALTH, &hparam, 1 );
597}
void ai_discovered(Pilot *discovered)
Triggers the discovered() function in the pilot's AI.
Definition ai.c:989
Provides macros to work with dynamic arrays.
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:179
int asteroids_inField(const vec2 *p)
See if the position is in an asteroid field.
Definition asteroid.c:1109
void player_message(const char *fmt,...)
Adds a mesg to the queue to be displayed on screen.
Definition gui.c:353
Header file with generic functions and naev-specifics.
#define CLAMP(a, b, x)
Definition naev.h:41
#define pow2(x)
Definition naev.h:53
#define MAX(x, y)
Definition naev.h:37
char pilot_getFactionColourChar(const Pilot *p)
Gets the faction colour char, works like faction_reputationColourChar but for a pilot.
Definition pilot.c:1121
Pilot * pilot_getTarget(Pilot *p)
Gets the target of a pilot using a fancy caching system.
Definition pilot.c:655
int pilot_hasIllegal(const Pilot *p, int faction)
Checks to see if the pilot has illegal stuf to a faction.
Definition pilot.c:4567
Pilot *const * pilot_getAll(void)
Gets the pilot stack.
Definition pilot.c:93
int pilot_canTarget(const Pilot *p)
Same as pilot_validTarget but without the range check.
Definition pilot.c:270
int pilot_areAllies(const Pilot *p, const Pilot *target)
Like areAllies but for pilots.
Definition pilot.c:741
void pilot_ewUpdateStealth(Pilot *p, double dt)
Updates the stealth mode and checks to see if it is getting broken.
Definition pilot_ew.c:497
int pilot_inRangePilot(const Pilot *p, const Pilot *target, double *dist2)
Check to see if a pilot is in sensor range of another.
Definition pilot_ew.c:256
void pilot_ewUpdateDynamic(Pilot *p, double dt)
Updates the pilot's dynamic electronic warfare properties.
Definition pilot_ew.c:113
int pilot_ewScanCheck(const Pilot *p)
Checks to see if a scan is done.
Definition pilot_ew.c:74
static double pilot_ewJumpPoint(const Pilot *p)
Gets the electronic warfare jump point modifier.
Definition pilot_ew.c:187
int pilot_inRangeSpob(const Pilot *p, int target)
Check to see if a spob is in sensor range of the pilot.
Definition pilot_ew.c:293
static double ew_interference
Definition pilot_ew.c:22
void pilot_updateSensorRange(void)
Updates the system's base sensor range.
Definition pilot_ew.c:208
void pilot_destealth(Pilot *p)
Destealths a pilot.
Definition pilot_ew.c:585
int pilot_inRangeJump(const Pilot *p, int i)
Check to see if a jump point is in sensor range of the pilot.
Definition pilot_ew.c:361
void pilot_ewScanStart(Pilot *p)
Initializes the scan timer for a pilot.
Definition pilot_ew.c:54
double pilot_ewWeaponTrack(const Pilot *p, const Pilot *t, double trackmin, double trackmax)
Calculates the weapon lead (1. is 100%, 0. is 0%)..
Definition pilot_ew.c:407
void pilot_ewUpdateStatic(Pilot *p)
Updates the pilot's static electronic warfare properties.
Definition pilot_ew.c:101
int pilot_inRangeAsteroid(const Pilot *p, int ast, int fie)
Check to see if an asteroid is in sensor range of the pilot.
Definition pilot_ew.c:324
static int pilot_ewStealthGetNearby(const Pilot *p, double *mod, int *close, int *isplayer)
Checks to see if there are pilots nearby to a stealthed pilot that could break stealth.
Definition pilot_ew.c:431
static void pilot_ewUpdate(Pilot *p)
Updates all the internal values.
Definition pilot_ew.c:84
double pilot_sensorRange(void)
Returns the default sensor range for the current system.
Definition pilot_ew.c:218
static double pilot_ewAsteroid(const Pilot *p)
Gets the electronic warfare asteroid modifier.
Definition pilot_ew.c:173
double pilot_ewScanTime(const Pilot *p)
Gets the time it takes to scan a pilot.
Definition pilot_ew.c:40
int pilot_inRange(const Pilot *p, double x, double y)
Check to see if a position is in range of the pilot.
Definition pilot_ew.c:231
static double pilot_ewMass(double mass)
Gets the electronic warfare mass modifier for a given mass.
Definition pilot_ew.c:162
int pilot_stealth(Pilot *p)
Stealths a pilot.
Definition pilot_ew.c:543
void pilot_calcStats(Pilot *pilot)
Recalculates the pilot's stats based on his outfits.
int pilot_outfitLOnstealth(Pilot *pilot)
Runs the pilot's Lua outfits onhit script.
void pilot_outfitLOnscan(Pilot *pilot)
Runs Lua outfits when pilot scanned their target.
void pilot_outfitLOnscanned(Pilot *pilot, const Pilot *scanner)
Runs Lua outfits when pilot was scanned by scanner.
void pilot_weapSetAIClear(Pilot *p)
Useful function for AI, clears activeness of all weapon sets.
void pilot_weapSetUpdateOutfitState(Pilot *p)
Updates the local state of all the pilot's outfits based on the weapon sets.
int pilot_outfitOffAllStealth(Pilot *p)
Disables all active outfits for a pilot.
void player_autonavResetSpeed(void)
Resets the game speed.
static const double d[]
Definition rng.c:263
StarSystem * cur_system
Definition space.c:110
Represents an asteroid field anchor.
Definition asteroid.h:111
Represents a single asteroid.
Definition asteroid.h:88
Solid sol
Definition asteroid.h:98
The actual hook parameter.
Definition hook.h:40
LuaPilot lp
Definition hook.h:46
union HookParam::@065274143236224234262250043114351136253171035204 u
The representation of an in-game pilot.
Definition pilot.h:263
ShipStats stats
Definition pilot.h:348
unsigned int id
Definition pilot.h:264
unsigned int parent
Definition pilot.h:390
double ew_asteroid
Definition pilot.h:326
double ew_detection
Definition pilot.h:320
int faction
Definition pilot.h:269
Solid solid
Definition pilot.h:275
double ew_signature
Definition pilot.h:321
double ew_detect
Definition shipstats.h:277
vec2 pos
Definition physics.h:49
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition space.h:102
vec2 pos
Definition space.h:109
double hide
Definition space.h:122