]> icculus.org git repositories - taylor/freespace2.git/blob - src/radar/radar.cpp
use SDL_arraysize() instead of sizeof() where appropriate
[taylor/freespace2.git] / src / radar / radar.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Radar/Radar.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C module containg functions to display and manage the radar
16  *
17  * $Log$
18  * Revision 1.6  2004/09/20 01:31:44  theoddone33
19  * GCC 3.4 fixes.
20  *
21  * Revision 1.5  2002/06/17 06:33:10  relnev
22  * ryan's struct patch for gcc 2.95
23  *
24  * Revision 1.4  2002/06/09 04:41:25  relnev
25  * added copyright header
26  *
27  * Revision 1.3  2002/06/02 04:26:34  relnev
28  * warning cleanup
29  *
30  * Revision 1.2  2002/05/07 03:16:51  theoddone33
31  * The Great Newline Fix
32  *
33  * Revision 1.1.1.1  2002/05/03 03:28:10  root
34  * Initial import.
35  *
36  * 
37  * 14    8/23/99 8:38p Andsager
38  * Added see_all debug console command for turning radar range infinite in
39  * nebula (but not targeting).
40  * 
41  * 13    6/10/99 3:43p Dave
42  * Do a better job of syncing text colors to HUD gauges.
43  * 
44  * 12    6/07/99 4:21p Andsager
45  * Add HUD color for tagged object.  Apply to target and radar.
46  * 
47  * 11    6/02/99 12:52p Andsager
48  * Added team-wide ship visibility.  Implemented for player.
49  * 
50  * 10    1/25/99 5:03a Dave
51  * First run of stealth, AWACS and TAG missile support. New mission type
52  * :)
53  * 
54  * 9     1/12/99 5:45p Dave
55  * Moved weapon pipeline in multiplayer to almost exclusively client side.
56  * Very good results. Bandwidth goes down, playability goes up for crappy
57  * connections. Fixed object update problem for ship subsystems.
58  * 
59  * 8     12/30/98 9:34a Jasen
60  * updated coords for hi res
61  * 
62  * 7     12/29/98 7:29p Dave
63  * Added some missing hi-res hud coord globalizations.
64  * 
65  * 6     12/29/98 2:30p Jasen
66  * added some new coords for 1024 HUD stuff
67  * 
68  * 5     12/28/98 3:17p Dave
69  * Support for multiple hud bitmap filenames for hi-res mode.
70  * 
71  * 4     11/05/98 4:18p Dave
72  * First run nebula support. Beefed up localization a bit. Removed all
73  * conditional compiles for foreign versions. Modified mission file
74  * format.
75  * 
76  * 3     10/13/98 9:29a Dave
77  * Started neatening up freespace.h. Many variables renamed and
78  * reorganized. Added AlphaColors.[h,cpp]
79  * 
80  * 2     10/07/98 10:53a Dave
81  * Initial checkin.
82  * 
83  * 1     10/07/98 10:51a Dave
84  * 
85  * 90    8/28/98 3:29p Dave
86  * EMP effect done. AI effects may need some tweaking as required.
87  * 
88  * 89    8/25/98 1:48p Dave
89  * First rev of EMP effect. Player side stuff basically done. Next comes
90  * AI code.
91  * 
92  * 88    6/12/98 4:52p Hoffoss
93  * Added support for special characters in in forgeign languages.
94  * 
95  * 87    6/09/98 10:31a Hoffoss
96  * Created index numbers for all xstr() references.  Any new xstr() stuff
97  * added from here on out should be added to the end if the list.  The
98  * current list count can be found in FreeSpace.cpp (search for
99  * XSTR_SIZE).
100  * 
101  * 86    5/19/98 10:26a John
102  * Fixed bug with radar blips not drawing in hardware.
103  * 
104  * 85    5/19/98 9:12a John
105  * Made radar blips render as font characters 132 and 133.   Needs a new
106  * font01.vf in the data tree.
107  * 
108  * 84    5/08/98 11:22a Allender
109  * fix ingame join trouble.  Small messaging fix.  Enable collisions for
110  * friendlies again
111  * 
112  * 83    5/01/98 12:24p Jim
113  * don't process radar_plot_obj on the standalone server
114  * 
115  * 82    4/07/98 4:05p Lawrance
116  * Only show hostile bombs on radar.
117  * 
118  * 81    3/26/98 5:26p John
119  * added new paging code. nonfunctional.
120  * 
121  * 80    3/15/98 3:11p Lawrance
122  * Always draw target radar blip bright.
123  * 
124  * 79    3/11/98 5:33p Lawrance
125  * Support rendering and targeting of jump nodes
126  * 
127  * 78    3/03/98 8:12p Lawrance
128  * Draw cargo as gray dots
129  * 
130  * 77    2/22/98 4:30p John
131  * More string externalization classification
132  * 
133  * 76    2/22/98 2:48p John
134  * More String Externalization Classification
135  * 
136  * 75    2/21/98 3:26p Lawrance
137  * Improve how blips get drawn for ships immune to sensors.
138  * 
139  * 74    2/16/98 11:58p Lawrance
140  * Add support for SF_HIDDEN_FROM_SENSORS flag.
141  * 
142  * 73    2/13/98 4:08p Lawrance
143  * Use more accurate distance formula when plotting radar dots... fixes
144  * "dead zone" black spot.
145  * 
146  * 72    2/12/98 4:58p Lawrance
147  * Change to new flashing method.
148  * 
149  * 71    2/11/98 12:04a Lawrance
150  * Only show bombs on radar, change code to use much less data.
151  * 
152  * 70    2/10/98 11:46a Lawrance
153  * Ensure TEAM_TRAITOR views other TEAM_TRAITOR ships as hostile.
154  * 
155  *
156  * $NoKeywords: $
157  *
158  */
159
160
161 #include "pstypes.h"
162 #include "font.h"
163 #include "floating.h"
164 #include "2d.h"
165 #include "3d.h"
166 #include "vecmat.h"
167 #include "palman.h"
168 #include "bmpman.h"
169 #include "object.h"
170 #include "ship.h"
171 #include "player.h"
172 #include "weapon.h"
173 #include "timer.h"
174 #include "ai.h"
175 #include "key.h"
176 #include "hud.h"
177 #include "hudtarget.h"
178 #include "hudconfig.h"
179 #include "subsysdamage.h"
180 #include "gamesnd.h"
181 #include "radar.h"
182 #include "linklist.h"
183 #include "multi.h"
184 #include "emp.h"
185 #include "freespace.h"
186 #include "localize.h"
187 #include "awacs.h"
188
189 int Radar_radius[GR_NUM_RESOLUTIONS][2] = {
190         { // GR_640
191                 120, 100
192         },
193         { // GR_1024
194                 192, 160
195         }
196 };
197
198 float Radar_center[GR_NUM_RESOLUTIONS][2] = {
199         { // GR_640
200                 322.0f, 422.0f
201         },
202         { // GR_1024
203                 515.0f, 675.0f
204         }
205 };
206
207 int Radar_coords[GR_NUM_RESOLUTIONS][2] = {
208         { // GR_640
209                 257, 369
210         }, 
211         { // GR_1024
212                 411, 590
213         }
214 };
215 char Radar_fname[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN] = {
216         "radar1",
217         "2_radar1"
218 };
219
220 int Radar_blip_radius_normal[GR_NUM_RESOLUTIONS] = {
221         2,
222         4
223 };
224 int Radar_blip_radius_target[GR_NUM_RESOLUTIONS] = {
225         5,
226         8
227 };
228
229 #define BLIP_MUTATE_TIME        100
230
231 float radx, rady;
232
233 #define MAX_RADAR_LEVELS        2               // bright and dim radar dots are allowed
234
235 #define BLIP_CURRENT_TARGET     (1<<0)
236 #define BLIP_DRAW_DIM                   (1<<1)  // object is farther than Radar_dim_range units away
237 #define BLIP_DRAW_DISTORTED     (1<<2)  // object is resistant to sensors, so draw distorted
238
239 typedef struct blip     {
240         blip    *prev, *next;
241         int     x, y, rad;
242         int     flags;  // BLIP_ flags defined above
243 } blip;
244
245 #define MAX_BLIPS 150
246 typedef struct rcol {
247         ubyte   r, g, b;
248 } rcol;
249
250 #define MAX_RADAR_COLORS                9
251
252 #define RCOL_HOSTILE                    0
253 #define RCOL_FRIENDLY                   1
254 #define RCOL_UNKNOWN                    2
255 #define RCOL_NEUTRAL                    3
256 #define RCOL_BOMB                               4
257 #define RCOL_NAVBUOYS                   5
258 #define  RCOL_WARPING_SHIP              6
259 #define RCOL_JUMP_NODE                  7
260 #define RCOL_TAGGED                             8
261
262 static float    Radar_dim_range;                                        // range at which we start dimming the radar blips
263 static int              Radar_calc_dim_dist_timer;              // timestamp at which we recalc Radar_dim_range
264
265 #define NUM_FLICKER_TIMERS      2
266 static int Radar_flicker_timer[NUM_FLICKER_TIMERS];                                     // timestamp used to flicker blips on and off
267 static int Radar_flicker_on[NUM_FLICKER_TIMERS];                                                // status of flickering
268
269 #define RADAR_BLIP_BRIGHT               0                               
270 #define RADAR_BLIP_DIM                  1
271
272 rcol Radar_color_rgb[MAX_RADAR_LEVELS][MAX_RADAR_COLORS] = {
273         {{ 0xff, 0x00, 0x00},           // hostile                      (red)
274         { 0x00, 0xff, 0x00},                    // friendly                     (green)
275         { 0xff, 0x00, 0xff},                    // unknown                      (purple)
276         { 0xff, 0x00, 0x00},                    //      neutral                 (red)
277         { 0x7f, 0x7f, 0x00},                    // homing missile (yellow)
278         { 0x7f, 0x7f, 0x7f},                    // navbuoy or cargo     (gray)
279         { 0x00, 0x00, 0xff},                    // warp ship            (blue)
280         { 0x7f, 0x7f, 0x7f},                    // jump node            (gray)
281         { 0xff, 0xff, 0x00}},           // tagged                       (yellow)
282
283         // 1/3 intensity of above colors
284         {{ 0x7f, 0x00, 0x00},           // hostile                      (red)
285         { 0x00, 0x7f, 0x00},                    // friendly                     (green)
286         { 0x7f, 0x00, 0x7f},                    // unknown                      (purple)
287         { 0x7f, 0x00, 0x00},                    //      neutral                 (red)
288         { 0x40, 0x40, 0x00},                    // homing missile (yellow)
289         { 0x40, 0x40, 0x40},                    // navbuoy or cargo     (gray)
290         { 0x00, 0x00, 0x7f},                    // warp ship            (blue)
291         { 0x40, 0x40, 0x40},                    // jump node            (gray)
292         { 0x7f, 0x7f, 0x00}},           // tagged                       (yellow)
293 };
294
295 color Radar_colors[MAX_RADAR_LEVELS][MAX_RADAR_COLORS];
296
297 blip    Blip_bright_list[MAX_RADAR_COLORS];             // linked list of bright blips
298 blip    Blip_dim_list[MAX_RADAR_COLORS];                        // linked list of dim blips
299 blip    Blips[MAX_BLIPS];                                                               // blips pool
300 int     N_blips;                                                                                        // next blip index to take from pool
301
302 float Radar_farthest_dist = 1000.0f;
303 static int Blip_mutate_id;
304
305 static int Radar_static_playing;                        // is static currently playing on the radar?
306 static int Radar_static_next;                           // next time to toggle static on radar
307 static int Radar_avail_prev_frame;              // was radar active last frame?
308 static int Radar_death_timer;                           // timestamp used to play static on radar
309 int Radar_static_looping;                                       // id for looping radar static sound
310
311 static hud_frames Radar_gauge;
312
313 int Radar_dist_coords[GR_NUM_RESOLUTIONS][RR_MAX_RANGES][2] = 
314 {
315         { // GR_640
316                 {367, 461},                                                             // short
317                 {364, 461},                                                             // long
318                 {368, 461}                                                              // infinity
319         },
320         { // GR_1024
321                 {595, 740},                                                             // short
322                 {592, 740},                                                             // long
323                 {596, 741}                                                              // infinity
324         }
325 };
326
327 // forward declarations
328 void draw_radar_blips(int desired_color, int is_dim, int distort=0);
329
330 void radar_init()
331 {
332         int i,j;
333
334         Radar_gauge.first_frame = bm_load_animation(Radar_fname[gr_screen.res], &Radar_gauge.num_frames);
335         if ( Radar_gauge.first_frame < 0 ) {
336                 Warning(LOCATION,"Cannot load hud ani: %s\n", Radar_fname[gr_screen.res]);
337         }
338
339         for (i=0; i<MAX_RADAR_LEVELS; i++ )     {
340                 for (j=0; j<MAX_RADAR_COLORS; j++ )     {
341                         gr_init_alphacolor( &Radar_colors[i][j], Radar_color_rgb[i][j].r, Radar_color_rgb[i][j].g, Radar_color_rgb[i][j].b, 255, AC_TYPE_HUD);
342                 }
343         }
344
345         Blip_mutate_id  = 1;
346 }
347
348 // determine what color the object blip should be drawn as
349 int radar_blip_color(object *objp)
350 {
351         int     color = 0;
352         ship    *shipp = NULL;
353
354         switch(objp->type) {
355         case OBJ_SHIP:
356                 shipp = &Ships[objp->instance];
357                 if ( shipp->flags & SF_ARRIVING_STAGE_1 )       {
358                         color = RCOL_WARPING_SHIP;
359                 } else if ( ship_is_tagged(objp) ) {
360                         color = RCOL_TAGGED;
361                 } else if ( Ship_info[shipp->ship_info_index].flags & (SIF_NAVBUOY|SIF_CARGO) ) {
362                         color = RCOL_NAVBUOYS;
363                 } else {
364                         if ( (Player_ship->team == shipp->team) && (Player_ship->team != TEAM_TRAITOR) ) {
365                                 color = RCOL_FRIENDLY;
366                         } else {
367                                 switch (shipp->team) {
368                                 case TEAM_FRIENDLY:
369                                 case TEAM_HOSTILE:
370                                 case TEAM_TRAITOR:
371                                         color = RCOL_HOSTILE;
372                                         break;
373                                 case TEAM_NEUTRAL:
374                                         color = RCOL_NEUTRAL;
375                                         break;
376                                 case TEAM_UNKNOWN:
377                                         color = RCOL_UNKNOWN;
378                                         break;
379                                 default:
380                                         color = RCOL_HOSTILE;
381                                         Int3(); //      Bogus team id in shipp->team
382                                         break;
383                                 }
384                         }
385                 }
386                 break;
387         case OBJ_WEAPON:
388                 color = RCOL_BOMB;
389                 break;
390         case OBJ_JUMP_NODE:
391                 color = RCOL_JUMP_NODE;
392                 break;
393         default:
394                 Error(LOCATION, "Illegal ship type in radar.");
395                 break;
396         }
397
398         return color;
399 }
400
401 int See_all = FALSE;
402 DCF_BOOL(see_all, See_all)
403
404 void radar_plot_object( object *objp )  
405 {
406         vector  pos, tempv;
407         float           dist, rscale, zdist, max_radar_dist;
408         int             xpos, ypos, color=0;
409         vector  *world_pos = &objp->pos;        
410         float           awacs_level;
411
412         // don't process anything here.  Somehow, a jumpnode object caused this function
413         // to get entered on server side.
414         if( Game_mode & GM_STANDALONE_SERVER ){
415                 return;
416         }
417
418         // multiplayer clients ingame joining should skip this function
419         if ( MULTIPLAYER_CLIENT && (Net_player->flags & NETINFO_FLAG_INGAME_JOIN) ){
420                 return;
421         }
422
423         // get team-wide awacs level for the object if not ship
424         int ship_is_visible = 0;
425         if (objp->type == OBJ_SHIP) {
426                 if (Player_ship != NULL) {
427                         if (ship_is_visible_by_team(objp->instance, Player_ship->team)) {
428                                 ship_is_visible = 1;
429                         }
430                 }
431         }
432
433         // only check awacs level if ship is not visible by team
434         awacs_level = 1.5f;
435         if (Player_ship != NULL && !ship_is_visible) {
436                 awacs_level = awacs_get_level(objp, Player_ship);
437         }
438
439         // if the awacs level is unviewable - bail
440         if(awacs_level < 0.0f && !See_all){
441                 return;
442         }
443
444         // Apply object type filters    
445         switch ( objp->type ) {
446         case OBJ_SHIP:
447                 // Place to cull ships, such as NavBuoys                
448                 break;
449                 
450         case OBJ_JUMP_NODE:
451                 // filter jump nodes here if required
452                 break;
453
454         case OBJ_WEAPON: {
455                 // if not a bomb, return
456                 if ( !(Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags & WIF_BOMB) ) {
457                         return;
458                 }
459
460                 // if bomb is on same team as player, return
461                 if ( (obj_team(objp) == Player_ship->team) && (Player_ship->team != TEAM_TRAITOR) ) {
462                         return;
463                 }
464                 break;
465         }
466
467         default:
468                 return;                 // if any other kind of object, don't want to show on radar
469                 break;
470         } // end switch
471
472         
473         // JAS -- new way of getting the rotated point that doesn't require this to be
474         // in a g3_start_frame/end_frame block.
475         vm_vec_sub(&tempv,world_pos,&Player_obj->pos);
476         vm_vec_rotate( &pos, &tempv, &Player_obj->orient );
477
478         // Apply range filter
479         dist = vm_vec_dist(world_pos, &Player_obj->pos);
480         max_radar_dist = Radar_ranges[HUD_config.rp_dist];
481         if ( dist > max_radar_dist ){
482                 return;
483         }
484
485         if ( dist < pos.xyz.z ) {
486                 rscale = 0.0f;
487         } else {
488                 rscale = (float) acos( pos.xyz.z/dist ) / 3.14159f;             //2.0f;
489         }
490
491         zdist = fl_sqrt( (pos.xyz.x*pos.xyz.x)+(pos.xyz.y*pos.xyz.y) );
492
493         float new_x_dist, clipped_x_dist;
494         float new_y_dist, clipped_y_dist;
495
496         if (zdist < 0.01f ) {
497                 new_x_dist = 0.0f;
498                 new_y_dist = 0.0f;
499         }
500         else {
501                 new_x_dist = (pos.xyz.x/zdist) * rscale * radx;
502                 new_y_dist = (pos.xyz.y/zdist) * rscale * rady;
503
504                 // force new_x_dist and new_y_dist to be inside the radar
505
506                 float hypotenuse;
507                 float max_radius;
508
509                 hypotenuse = hypotf(new_x_dist, new_y_dist);
510                 max_radius = i2fl(Radar_radius[gr_screen.res][0] - 5);
511
512                 if (hypotenuse >= (max_radius) ) {
513                         clipped_x_dist = max_radius * (new_x_dist / hypotenuse);
514                         clipped_y_dist = max_radius * (new_y_dist / hypotenuse);
515                         new_x_dist = clipped_x_dist;
516                         new_y_dist = clipped_y_dist;
517                 }
518         }
519
520         xpos = fl2i( Radar_center[gr_screen.res][0] + new_x_dist );
521         ypos = fl2i( Radar_center[gr_screen.res][1] - new_y_dist );
522
523         color = radar_blip_color(objp);
524
525         // Determine the distance at which we will dim the radar blip
526         if ( timestamp_elapsed(Radar_calc_dim_dist_timer) ) {
527                 Radar_calc_dim_dist_timer=timestamp(1000);
528                 Radar_dim_range = player_farthest_weapon_range();
529                 if ( Radar_dim_range <= 0 ) {
530                         Radar_dim_range=1500.0f;
531                 }
532         }
533
534         blip    *b;
535         int blip_dim=0;
536
537         if ( dist > Radar_dim_range ) {
538                 blip_dim=1;
539         }
540
541         if ( N_blips >= MAX_BLIPS ) {
542                 // out of blips, don't plot
543                 Int3();
544                 return;
545         }
546
547         b = &Blips[N_blips];
548         b->flags=0;
549
550         // flag the blip as a current target if it is
551         if (OBJ_INDEX(objp) == Player_ai->target_objnum)        {
552                 b->flags |= BLIP_CURRENT_TARGET;
553                 blip_dim = 0;
554         }
555
556         if ( blip_dim ) {
557                 list_append( &Blip_dim_list[color], b );
558         } else {
559                 list_append( &Blip_bright_list[color], b );
560         }
561
562         b->x = xpos;
563         b->y = ypos;
564
565         // see if blip should be drawn distorted
566         if (objp->type == OBJ_SHIP) {
567                 // ships specifically hidden from sensors
568                 if ( Ships[objp->instance].flags & SF_HIDDEN_FROM_SENSORS ) {
569                         b->flags |= BLIP_DRAW_DISTORTED;
570                 }
571
572                 // determine if its AWACS distorted
573                 if ( awacs_level < 1.0f ){
574                         b->flags |= BLIP_DRAW_DISTORTED;
575                 }
576         }                               
577
578         N_blips++;
579 }
580
581 // set N_blips for each color/brightness level to zero
582 void radar_null_nblips()
583 {
584         int i;
585
586         N_blips=0;
587
588         for (i=0; i<MAX_RADAR_COLORS; i++) {
589                 list_init(&Blip_bright_list[i]);
590                 list_init(&Blip_dim_list[i]);
591         }
592 }
593
594 // radar_mission_init() is called at the start of each mission.  
595 void radar_mission_init()
596 {
597         int i;
598
599         Blip_mutate_id                          = 1;
600         Radar_death_timer                       = 0;
601         Radar_static_playing            = 0;
602         Radar_static_next                       = 0;
603         Radar_avail_prev_frame  = 1;
604         Radar_calc_dim_dist_timer = timestamp(0);
605
606         for ( i=0; i<NUM_FLICKER_TIMERS; i++ ) {
607                 Radar_flicker_timer[i]=timestamp(0);
608                 Radar_flicker_on[i]=0;
609         }
610 }
611
612 #define SMALL_BLIP_CHAR (Lcl_special_chars + 5)
613 #define LARGE_BLIP_CHAR (Lcl_special_chars + 6)
614
615 int Small_blip_offset_x = 0;
616 int Small_blip_offset_y = 0;
617 int Large_blip_offset_x = 0;
618 int Large_blip_offset_y = 0;
619
620 char Small_blip_string[2];
621 char Large_blip_string[2];
622
623 void radar_frame_init()
624 {
625         radar_null_nblips();
626         radx = i2fl(Radar_radius[gr_screen.res][0])/2.0f;
627         rady = i2fl(Radar_radius[gr_screen.res][1])/2.0f;
628
629         int w,h;
630         gr_set_font(FONT1);
631
632         Small_blip_string[0] = ubyte(SMALL_BLIP_CHAR);
633         Small_blip_string[1] = 0;
634         gr_get_string_size( &w, &h, Small_blip_string );
635         Small_blip_offset_x = -w/2;
636         Small_blip_offset_y = -h/2;
637
638         Large_blip_string[0] = ubyte(LARGE_BLIP_CHAR);
639         Large_blip_string[1] = 0;
640         gr_get_string_size( &w, &h, Large_blip_string );
641         Large_blip_offset_x = -w/2;
642         Large_blip_offset_y = -h/2;
643 }
644
645 void radar_draw_circle( int x, int y, int rad )
646 {
647         if ( rad == Radar_blip_radius_target[gr_screen.res] )   {
648                 gr_string( Large_blip_offset_x+x, Large_blip_offset_y+y, Large_blip_string );
649         } else {
650                 // rad = RADAR_BLIP_RADIUS_NORMAL;
651                 gr_string( Small_blip_offset_x+x, Small_blip_offset_y+y, Small_blip_string );
652         }
653 }
654
655 // radar is damaged, so make blips dance around
656 void radar_blip_draw_distorted(blip *b)
657 {
658         int xdiff, ydiff;
659         float scale;
660         xdiff = -10 + rand()%20;
661         ydiff = -10 + rand()%20;
662
663         // maybe scale the effect if EMP is active
664         if(emp_active_local()){
665                 scale = emp_current_intensity();
666
667                 xdiff = (int)((float)xdiff * scale);
668                 ydiff = (int)((float)ydiff * scale);
669         }
670
671         radar_draw_circle( b->x+xdiff, b->y+ydiff, b->rad ); 
672 }
673
674 // blip is for a target immune to sensors, so cause to flicker in/out with mild distortion
675 void radar_blip_draw_flicker(blip *b)
676 {
677         int xdiff=0, ydiff=0, flicker_index;
678
679         if ( (b-Blips) & 1 ) {
680                 flicker_index=0;
681         } else {
682                 flicker_index=1;
683         }
684
685         if ( timestamp_elapsed(Radar_flicker_timer[flicker_index]) ) {
686                 Radar_flicker_timer[flicker_index] = timestamp_rand(50,1000);
687                 Radar_flicker_on[flicker_index] ^= 1;
688         }
689
690         if ( !Radar_flicker_on[flicker_index] ) {
691                 return;
692         }
693
694         if ( rand() & 1 ) {
695                 xdiff = -2 + rand()%4;
696                 ydiff = -2 + rand()%4;
697         }
698
699         radar_draw_circle( b->x+xdiff, b->y+ydiff, b->rad ); 
700 }
701
702 // Draw all the active radar blips
703 void draw_radar_blips(int rcol, int is_dim, int distort)
704 {
705         blip    *b=NULL;
706         blip    *blip_head=NULL;
707
708         // Need to set font.
709         gr_set_font(FONT1);
710
711         if ( is_dim ) {
712                 blip_head = &Blip_dim_list[rcol];
713         } else {
714                 blip_head = &Blip_bright_list[rcol];
715         }
716
717         for ( b = GET_FIRST(blip_head); b !=END_OF_LIST(blip_head); b = GET_NEXT(b) )   {
718
719                 SDL_assert((rcol >= 0) && (rcol < MAX_RADAR_COLORS));
720
721                 if ( is_dim ) {
722                         gr_set_color_fast( &Radar_colors[RADAR_BLIP_DIM][rcol] );
723                 } else {
724                         gr_set_color_fast( &Radar_colors[RADAR_BLIP_BRIGHT][rcol] );
725                 }
726
727                 if (b->flags & BLIP_CURRENT_TARGET) {
728                         // draw cool blip to indicate current target
729                         b->rad = Radar_blip_radius_target[gr_screen.res];                               
730                 } else {
731                         b->rad = Radar_blip_radius_normal[gr_screen.res];
732                 }
733
734                 if ( distort ) { 
735                         radar_blip_draw_distorted(b);
736                 } else if ( b->flags & BLIP_DRAW_DISTORTED ) {
737                         radar_blip_draw_flicker(b);
738                 } else{
739                         radar_draw_circle( b->x, b->y, b->rad );
740                 }
741         }
742 }
743
744 // Draw the radar blips
745 // input:       distorted       =>              0 (default) to draw normal, 1 to draw distorted 
746 void radar_draw_blips_sorted(int distort)
747 {
748         // draw dim blips first
749         draw_radar_blips(RCOL_JUMP_NODE, 1, distort);
750         draw_radar_blips(RCOL_WARPING_SHIP, 1, distort);
751         draw_radar_blips(RCOL_NAVBUOYS, 1, distort);
752         draw_radar_blips(RCOL_FRIENDLY, 1, distort);
753         draw_radar_blips(RCOL_UNKNOWN, 1, distort);
754         draw_radar_blips(RCOL_BOMB, 1, distort);
755         draw_radar_blips(RCOL_NEUTRAL, 1, distort);
756         draw_radar_blips(RCOL_HOSTILE, 1, distort);
757         draw_radar_blips(RCOL_TAGGED, 1, distort);
758
759         // draw bright blips
760         draw_radar_blips(RCOL_JUMP_NODE, 0, distort);
761         draw_radar_blips(RCOL_WARPING_SHIP, 0, distort);
762         draw_radar_blips(RCOL_NAVBUOYS, 0, distort);
763         draw_radar_blips(RCOL_FRIENDLY, 0, distort);
764         draw_radar_blips(RCOL_UNKNOWN, 0, distort);
765         draw_radar_blips(RCOL_BOMB, 0, distort);
766         draw_radar_blips(RCOL_NEUTRAL, 0, distort);
767         draw_radar_blips(RCOL_HOSTILE, 0, distort);
768         draw_radar_blips(RCOL_TAGGED, 0, distort);
769 }
770
771 void radar_draw_range()
772 {
773         char buf[32];
774
775         // hud_set_bright_color();
776         hud_set_gauge_color(HUD_RADAR, HUD_C_BRIGHT);
777
778         switch ( HUD_config.rp_dist ) {
779
780         case RR_SHORT:
781                 gr_printf(Radar_dist_coords[gr_screen.res][RR_SHORT][0], Radar_dist_coords[gr_screen.res][RR_SHORT][1], XSTR( "2k", 467));
782                 break;
783
784         case RR_LONG:
785                 gr_printf(Radar_dist_coords[gr_screen.res][RR_LONG][0], Radar_dist_coords[gr_screen.res][RR_LONG][1], XSTR( "10k", 468));
786                 break;
787
788         case RR_INFINITY:
789                 SDL_snprintf(buf, SDL_arraysize(buf), NOX("%c"), Lcl_special_chars);
790                 gr_printf(Radar_dist_coords[gr_screen.res][RR_INFINITY][0], Radar_dist_coords[gr_screen.res][RR_INFINITY][1], buf);
791                 break;
792
793         default:
794                 Int3(); // can't happen (get Alan if it does)
795                 break;
796         }
797
798         hud_set_default_color();
799 }
800
801 void radar_frame_render(float frametime)
802 {
803         float   sensors_str;
804         int ok_to_blit_radar;
805
806         ok_to_blit_radar = 1;
807
808         sensors_str = ship_get_subsystem_strength( Player_ship, SUBSYSTEM_SENSORS );
809
810         if ( ship_subsys_disrupted(Player_ship, SUBSYSTEM_SENSORS) ) {
811                 sensors_str = MIN_SENSOR_STR_TO_RADAR-1;
812         }
813
814         // note that on lowest skill level, there is no radar effects due to sensors damage
815         if ( (Game_skill_level == 0) || (sensors_str > SENSOR_STR_RADAR_NO_EFFECTS) ) {
816                 Radar_static_playing = 0;
817                 Radar_static_next = 0;
818                 Radar_death_timer = 0;
819                 Radar_avail_prev_frame = 1;
820         } else if ( sensors_str < MIN_SENSOR_STR_TO_RADAR ) {
821                 if ( Radar_avail_prev_frame ) {
822                         Radar_death_timer = timestamp(2000);
823                         Radar_static_next = 1;
824                 }
825                 Radar_avail_prev_frame = 0;
826         } else {
827                 Radar_death_timer = 0;
828                 if ( Radar_static_next == 0 )
829                         Radar_static_next = 1;
830         }
831
832         if ( timestamp_elapsed(Radar_death_timer) ) {
833                 ok_to_blit_radar = 0;
834         }
835
836         hud_set_gauge_color(HUD_RADAR);
837         radar_blit_gauge();
838         radar_draw_range();
839
840         if ( timestamp_elapsed(Radar_static_next) ) {
841                 Radar_static_playing ^= 1;
842                 Radar_static_next = timestamp_rand(50, 750);
843         }
844
845         // if the emp effect is active, always draw the radar wackily
846         if(emp_active_local()){
847                 Radar_static_playing = 1;
848         }
849
850         if ( ok_to_blit_radar ) {
851                 if ( Radar_static_playing ) {
852                         radar_draw_blips_sorted(1);     // passing 1 means to draw distorted
853                         if ( Radar_static_looping == -1 ) {
854                                 Radar_static_looping = snd_play_looping(&Snds[SND_STATIC]);
855                         }
856                 } else {
857                         radar_draw_blips_sorted();
858                         if ( Radar_static_looping != -1 ) {
859                                 snd_stop(Radar_static_looping);
860                                 Radar_static_looping = -1;
861                         }
862                 }
863         } else {
864                 if ( Radar_static_looping != -1 ) {
865                         snd_stop(Radar_static_looping);
866                         Radar_static_looping = -1;
867                 }
868         }
869 }
870
871 void radar_blit_gauge()
872 {
873         gr_set_bitmap(Radar_gauge.first_frame+1, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
874         gr_aabitmap( Radar_coords[gr_screen.res][0], Radar_coords[gr_screen.res][1] );
875
876
877 void radar_page_in()
878 {
879         bm_page_in_aabitmap( Radar_gauge.first_frame, Radar_gauge.num_frames );
880 }
881