]> icculus.org git repositories - taylor/freespace2.git/blob - src/hud/hud.cpp
initial loading/progress screen for emscripten
[taylor/freespace2.git] / src / hud / hud.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/Hud/HUD.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C module that contains all the HUD functions at a high level
16  *
17  * $Log$
18  * Revision 1.9  2005/10/01 22:04:58  taylor
19  * fix FS1 (de)briefing voices, the directory names are different in FS1
20  * hard code the table values so that the fs1.vp file isn't needed
21  * hard code a mission fix for sm2-08a since a have no idea how to fix it otherwise
22  * generally cleanup some FS1 code
23  * fix volume sliders in the options screen that never went all the way up
24  *
25  * Revision 1.8  2004/09/20 01:31:44  theoddone33
26  * GCC 3.4 fixes.
27  *
28  * Revision 1.7  2003/08/03 16:10:29  taylor
29  * cleanup; compile warning fixes
30  *
31  * Revision 1.6  2003/06/03 04:00:40  taylor
32  * Polish language support (Janusz Dziemidowicz)
33  *
34  * Revision 1.5  2003/05/25 02:30:42  taylor
35  * Freespace 1 support
36  *
37  * Revision 1.4  2003/05/18 03:55:30  taylor
38  * automatic language selection support
39  *
40  * Revision 1.3  2002/06/17 06:33:09  relnev
41  * ryan's struct patch for gcc 2.95
42  *
43  * Revision 1.2  2002/06/09 04:41:21  relnev
44  * added copyright header
45  *
46  * Revision 1.1.1.1  2002/05/03 03:28:09  root
47  * Initial import.
48  *
49  * 
50  * 58    10/28/99 2:04a Jefff
51  * some german specific coords.  
52  * 
53  * 57    10/25/99 5:43p Jefff
54  * added (and subsequently commented) some scoring debug code.  checked in
55  * to work on later
56  * 
57  * 56    9/09/99 3:55a Andsager
58  * Reset Hud_support_objnum to -1 when guage stops displaying
59  * 
60  * 55    9/01/99 11:16a Andsager
61  * Fix bug where support ship guage would not show up if second support
62  * ship called in whlile 1st one dying.
63  * 
64  * 54    8/23/99 1:49p Dave
65  * Fixed damage popup (hopefully)
66  * 
67  * 53    8/23/99 11:34a Dave
68  * Fixed shield intensity rendering problems.
69  * 
70  * 52    8/19/99 6:16p Jefff
71  * 
72  * 51    8/17/99 7:15p Jefff
73  * auto-target & auto-speed text drawn in code
74  * 
75  * 50    8/16/99 4:04p Dave
76  * Big honking checkin.
77  * 
78  * 49    8/09/99 3:47p Dave
79  * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
80  * non-nebula missions.
81  * 
82  * 48    8/09/99 3:14p Dave
83  * Make "launch" warning gauge draw in code.
84  * 
85  * 47    8/05/99 2:05a Dave
86  * Fixes. Optimized detail level stuff.
87  * 
88  * 46    8/04/99 2:56p Jefff
89  * fixed black box behind pilot head in hi-res
90  * 
91  * 45    8/04/99 9:54a Andsager
92  * Auto target turrets on big ships.
93  * 
94  * 44    8/01/99 12:39p Dave
95  * Added HUD contrast control key (for nebula).
96  * 
97  * 43    7/31/99 4:15p Dave
98  * Fixed supernova particle velocities. Handle OBJ_NONE in target
99  * monitoring view. Properly use objectives notify gauge colors.
100  * 
101  * 42    7/31/99 1:16p Dave
102  * Use larger font for 1024 HUD flash text box. Make beam weapons aware of
103  * weapon subsystem damage on firing ship.
104  * 
105  * 41    7/26/99 10:41a Jefff
106  * added call to hud_maybe_show_damage() in hud_render_2d().  not sure how
107  * this got out in the 1st place.
108  * 
109  * 40    7/24/99 1:54p Dave
110  * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
111  * missions.
112  * 
113  * 39    7/22/99 4:00p Dave
114  * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
115  * 
116  * 38    7/21/99 8:10p Dave
117  * First run of supernova effect.
118  * 
119  * 37    7/21/99 3:19p Jefff
120  * adjusted subspace and red alert popup text coords
121  * 
122  * 36    7/19/99 2:13p Dave
123  * Added some new strings for Heiko.
124  * 
125  * 35    7/19/99 11:48a Jefff
126  * Countermeasure success sound added
127  * 
128  * 34    7/16/99 12:22p Jefff
129  * Added sound FX to objective popups
130  * 
131  * 33    7/15/99 7:16p Jefff
132  * Red Alert box is now red
133  * 
134  * 32    7/09/99 12:00a Andsager
135  * Added target box with distance for remote detonate weapons
136  * 
137  * 31    6/28/99 4:33p Jasenw
138  * Fixed coords for hi res engine wash gauge
139  * 
140  * 30    6/11/99 11:13a Dave
141  * last minute changes before press tour build.
142  * 
143  * 29    6/10/99 3:43p Dave
144  * Do a better job of syncing text colors to HUD gauges.
145  * 
146  * 28    6/08/99 1:14a Dave
147  * Multi colored hud test.
148  * 
149  * 27    6/07/99 4:20p Andsager
150  * Add HUD color for tagged object.  Apply to target and radar.
151  * 
152  * 26    5/28/99 5:36p Andsager
153  * stupid comment
154  * 
155  * 25    5/28/99 10:00a Andsager
156  * Make player hud target affected by Nebula range
157  * 
158  * 24    5/22/99 5:35p Dave
159  * Debrief and chatbox screens. Fixed small hi-res HUD bug.
160  * 
161  * 23    5/21/99 5:36p Andsager
162  * Put in high res engine wash gauge and approx coords
163  * 
164  * 22    5/21/99 1:44p Andsager
165  * Add engine wash gauge
166  * 
167  * 21    4/20/99 6:39p Dave
168  * Almost done with artillery targeting. Added support for downloading
169  * images on the PXO screen.
170  * 
171  * 20    2/25/99 4:19p Dave
172  * Added multiplayer_beta defines. Added cd_check define. Fixed a few
173  * release build warnings. Added more data to the squad war request and
174  * response packets.
175  * 
176  * 19    2/24/99 4:02p Dave
177  * Fixed weapon locking and homing problems for multiplayer dogfight mode.
178  * 
179  * 18    2/17/99 2:10p Dave
180  * First full run of squad war. All freespace and tracker side stuff
181  * works.
182  * 
183  * 17    2/03/99 8:37a Jasen
184  * Fixed dock in coords
185  * 
186  * 16    2/01/99 9:24a Jasen
187  * Fixed subspace and objectives displays for hi res.
188  * 
189  * 15    1/25/99 5:03a Dave
190  * First run of stealth, AWACS and TAG missile support. New mission type
191  * :)
192  * 
193  * 14    1/21/99 9:28p Dave
194  * Fixed damage gauge coords.
195  * 
196  * 13    1/07/99 9:05a Jasen
197  * coords, coords, coords
198  * 
199  * 12    1/06/99 3:24p Dave
200  * Fixed stupid code.
201  * 
202  * 11    1/06/99 3:14p Jasen
203  * more new coords
204  * 
205  * 10    1/06/99 2:33p Jasen
206  * updated coords
207  * 
208  * 9     1/06/99 1:27p Dave
209  * Removed duplicate global var.
210  * 
211  * 8     1/06/99 1:26p Dave
212  * Put in seperate X coords for "dock in" and the associated time value
213  * for the support ship gauge.
214  * 
215  * 7     12/28/98 3:17p Dave
216  * Support for multiple hud bitmap filenames for hi-res mode.
217  * 
218  * 6     12/21/98 5:02p Dave
219  * Modified all hud elements to be multi-resolution friendly.
220  * 
221  * 5     12/18/98 1:13a Dave
222  * Rough 1024x768 support for Direct3D. Proper detection and usage through
223  * the launcher.
224  * 
225  * 4     11/05/98 4:18p Dave
226  * First run nebula support. Beefed up localization a bit. Removed all
227  * conditional compiles for foreign versions. Modified mission file
228  * format.
229  * 
230  * 3     10/13/98 9:28a Dave
231  * Started neatening up freespace.h. Many variables renamed and
232  * reorganized. Added AlphaColors.[h,cpp]
233  * 
234  * 2     10/07/98 10:53a Dave
235  * Initial checkin.
236  * 
237  * 1     10/07/98 10:49a Dave
238  * 
239  * 223   8/28/98 3:28p Dave
240  * EMP effect done. AI effects may need some tweaking as required.
241  * 
242  * 222   8/25/98 1:48p Dave
243  * First rev of EMP effect. Player side stuff basically done. Next comes
244  * AI code.
245  * 
246  * 221   8/09/98 4:45p Lawrance
247  * center various HUD text - fixes problems in the German version
248  * 
249  * 220   6/18/98 10:10a Allender
250  * fixed compiler warnings
251  * 
252  * 219   6/17/98 11:03a Lawrance
253  * position subspace notify correctly for german version
254  * 
255  * 218   6/13/98 10:48p Lawrance
256  * Changed code to utilize proper fixed-space 1 character.
257  * 
258  * 217   6/13/98 6:01p Hoffoss
259  * Externalized all new (or forgot to be added) strings to all the code.
260  * 
261  * 216   6/12/98 2:49p Dave
262  * Patch 1.02 changes.
263  * 
264  * 215   6/09/98 10:31a Hoffoss
265  * Created index numbers for all xstr() references.  Any new xstr() stuff
266  * added from here on out should be added to the end if the list.  The
267  * current list count can be found in FreeSpace.cpp (search for
268  * XSTR_SIZE).
269  * 
270  * 214   6/01/98 11:43a John
271  * JAS & MK:  Classified all strings for localization.
272  * 
273  * 213   5/23/98 4:14p John
274  * Added code to preload textures to video card for AGP.   Added in code
275  * to page in some bitmaps that weren't getting paged in at level start.
276  * 
277  * 212   5/17/98 3:32p Lawrance
278  * Allow red alert orders to get downloaded when in an out-of-cockpit view
279  * 
280  * 211   5/15/98 8:36p Lawrance
281  * Add 'target ship that last sent transmission' target key
282  * 
283  * 210   5/10/98 5:28p Lawrance
284  * Ensure hud messages and talking heads show up when viewing from another
285  * ship
286  * 
287  * 209   5/10/98 12:11a Lawrance
288  * Fix a couple of problems with 2D gauges showing up in external views
289  * 
290  * 208   5/09/98 4:52p Lawrance
291  * Implement padlock view (up/rear/left/right)
292  * 
293  * 207   5/09/98 12:20a Lawrance
294  * Show hud messages in all views
295  * 
296  * 206   5/08/98 5:32p Lawrance
297  * Allow cargo scanning even if target gauge is disabled
298  * 
299  * 205   5/08/98 10:13a Lawrance
300  * Don't allow targeting of ships that have SF_EXPLODED flag set
301  * 
302  * 204   5/07/98 1:01a Chad
303  * Yet another hud gauage which shouldn't be rendered as a multiplayer
304  * observer.
305  * 
306  * 203   5/04/98 12:08p Ed
307  * from allender:  move hud_target_change_check() after code which does
308  * possible auto target change.  Fixed multiplayer problem where locking
309  * subsys does not match ship currently targeted
310  * 
311  * 202   5/04/98 6:12p Lawrance
312  * Write generic function hud_end_string_at_first_hash_symbol(), to use in
313  * various spots on the HUD
314  * 
315  * 201   4/30/98 3:32p Lawrance
316  * Cull dead/departed ships from escort ship in hud_update_frame()
317  * 
318  * 200   4/23/98 10:24p Mike
319  * Int3(), then recover gracefully from some error in which ship to be
320  * repaired is killed. 
321  * 
322  * $NoKeywords: $
323  *
324 */
325
326 #include "pstypes.h"
327 #include "freespace.h"
328 #include "systemvars.h"
329 #include "hud.h"
330 #include "hudtarget.h"
331 #include "hudreticle.h"
332 #include "hudmessage.h"
333 #include "sound.h"
334 #include "player.h"
335 #include "multi.h"
336 #include "multiutil.h"
337 #include "gamesnd.h"
338 #include "hudsquadmsg.h"
339 #include "timer.h"
340 #include "eventmusic.h"
341 #include "hudlock.h"
342 #include "hudets.h"
343 #include "2d.h"
344 #include "3d.h"
345 #include "ai.h"
346 #include "aigoals.h"
347 #include "hudescort.h"
348 #include "hudshield.h"
349 #include "linklist.h"
350 #include "hudtargetbox.h"
351 #include "missionmessage.h"
352 #include "missiontraining.h"
353 #include "bmpman.h"
354 #include "radar.h"
355 #include "hudobserver.h"
356 #include "hudtargetbox.h"
357 #include "hudconfig.h"
358 #include "missiongoals.h"
359 #include "asteroid.h"
360 #include "starfield.h"
361 #include "hudwingmanstatus.h"
362 #include "multi_voice.h"
363 #include "multi_pmsg.h"
364 #include "redalert.h"
365 #include "emp.h"
366 #include "alphacolors.h"
367 #include "localize.h"
368 #include "supernova.h"
369 #include "font.h"
370
371 // new values for HUD alpha
372 #define HUD_NEW_ALPHA_DIM                               80      
373 #define HUD_NEW_ALPHA_NORMAL                    120
374 #define HUD_NEW_ALPHA_BRIGHT                    220
375
376 // high contrast
377 #define HUD_NEW_ALPHA_DIM_HI                    130
378 #define HUD_NEW_ALPHA_NORMAL_HI         190
379 #define HUD_NEW_ALPHA_BRIGHT_HI         255
380
381 // globals that will control the color of the HUD gauges
382 int HUD_color_red = 0;
383 int HUD_color_green = 255;
384 int HUD_color_blue = 0;
385 int HUD_color_alpha = HUD_COLOR_ALPHA_DEFAULT;          // 1 -> HUD_COLOR_ALPHA_USER_MAX
386
387 int HUD_contrast = 0;                                                                           // high or lo contrast (for nebula, etc)
388
389 color HUD_color_defaults[HUD_NUM_COLOR_LEVELS];         // array of colors with different alpha blending
390 color HUD_color_debug;                                                                          // grey debug text shown on HUD
391
392 static int Player_engine_snd_loop = -1;
393
394 // animations for damages gauges
395 hud_anim Target_static;
396 hud_anim        Radar_static;
397
398 // HUD render frame offsets
399 float HUD_offset_x = 0.0f;
400 float HUD_offset_y = 0.0f;
401
402 // Global: integrity of player's target
403 float Pl_target_integrity;
404
405 static int Hud_last_can_target; // whether Player is able to target in the last frame
406 static int Hud_can_target_timer;        // timestamp to allow target gauge to draw static once targeting functions are not allowed
407
408 // centered text message gauges (collision, emp, etc)
409 char Hud_text_flash[512] = "";
410 int Hud_text_flash_coords[GR_NUM_RESOLUTIONS][2] = {
411         { // GR_640
412                 -1, 172
413         },
414         { // GR_1024
415                 -1, 275
416         }
417 };
418 void hud_init_text_flash_gauge();
419 void hud_start_text_flash(const char *txt, int t);
420 void hud_maybe_show_text_flash_icon();
421
422
423 // multiplayer messaging text
424 int Multi_msg_coords[GR_NUM_RESOLUTIONS][2] = {
425         { // GR_640
426                 5, 150
427         },
428         { // GR_1024
429                 8, 240
430         }
431 };
432
433 // multiplayer voice stuff
434 int Voice_coords[GR_NUM_RESOLUTIONS][2] = {
435         { // GR_640
436                 5, 165
437         },
438         { // GR_1024
439                 8, 255
440         }
441 };
442
443 // redalert downloading new orders text
444 int Red_text_coords[GR_NUM_RESOLUTIONS][2] = {
445         { // GR_640
446                 -1, 116
447         },
448         { // GR_1024
449                 -1, 186
450         }
451 };
452 int Red_text_val_coords[GR_NUM_RESOLUTIONS][2] = {
453         { // GR_640
454                 -1, 124
455         },
456         { // GR_1024
457                 -1, 194
458         }
459 };
460
461 // subspace popup
462 int Subspace_text_coords[GR_NUM_RESOLUTIONS][2] = {
463         { // GR_640
464                 -1, 116
465         },
466         { // GR_1024
467                 -1, 186
468         }
469 };
470 int Subspace_text_val_coords[GR_NUM_RESOLUTIONS][2] = {
471         { // GR_640
472                 100, 124
473         },
474         { // GR_1024
475                 140, 194
476         }
477 };
478
479 // message text coords
480 int Head_message_coords[GR_NUM_RESOLUTIONS][2] = {
481         { // GR_640
482                 7, 37
483         },
484         { // GR_1024
485                 11, 57
486         }
487 };
488
489 // ping text coords
490 int Ping_coords[GR_NUM_RESOLUTIONS][2] = {
491         { // GR_640
492                 560, 3
493         },
494         { // GR_1024
495                 896, 5
496         }
497 };
498
499 // supernova coords
500 int Supernova_coords[GR_NUM_RESOLUTIONS][2] = {
501         { // GR_640
502                 100, 100
503         },
504         { // GR_1024
505                 170, 170
506         }
507 };
508         
509 // used to draw the netlag icon on the HUD
510 hud_frames Netlag_icon;
511 int Netlag_icon_loaded=0;
512 int Netlag_coords[GR_NUM_RESOLUTIONS][2] = {
513         { // GR_640
514                 386, 331
515         },
516         { // GR_1024
517                 627, 529
518         }
519 };
520 const char *Netlag_fname[GR_NUM_RESOLUTIONS] = {
521         "netlag1",
522         "netlag1"
523 };
524
525 // used to draw the kills gauge
526 hud_frames Kills_gauge;
527 int Kills_gauge_loaded = 0;
528 int Kills_gauge_coords[GR_NUM_RESOLUTIONS][2] = {
529         { // GR_640
530                 497, 361
531         },
532         { // GR_1024
533                 880, 624
534         }
535 };
536 int Kills_text_coords[GR_NUM_RESOLUTIONS][2] = {
537         { // GR_640
538                 503, 365
539         },
540         { // GR_1024
541                 886, 628
542         }
543 };
544
545 // for German version
546 int Kills_text_val_coords_gr[GR_NUM_RESOLUTIONS][2] = {
547         { // GR_640
548                 615, 365
549         },
550         { // GR_1024
551                 984, 628
552         }
553 };
554
555 int Kills_text_val_coords[GR_NUM_RESOLUTIONS][2] = {
556         { // GR_640
557                 571, 365
558         },
559         { // GR_1024
560                 954, 628
561         }
562 };
563
564 const char *Kills_fname[GR_NUM_RESOLUTIONS] = {
565         "kills1",
566         "kills1"
567 };
568
569 // used to draw border around a talking head
570 static hud_frames Head_frame_gauge;
571 static int Head_frame_gauge_loaded = 0;
572 int Head_frame_coords[GR_NUM_RESOLUTIONS][2] = {
573         { // GR_640
574                 5, 35
575         },
576         { // GR_1024
577                 5, 56
578         }
579 };
580 const char *Head_fname[GR_NUM_RESOLUTIONS] = {
581         "head1",
582         "head1"
583 };
584
585 // mission time frame
586 static hud_frames Mission_time_gauge;
587 static int Mission_time_gauge_loaded = 0;
588 int Mission_time_coords[GR_NUM_RESOLUTIONS][2] = {
589         { // GR_640
590                 587, 448
591         },
592         { // GR_1024
593                 969, 716
594         }
595 };
596 int Mission_time_text_coords[GR_NUM_RESOLUTIONS][2] = {
597         { // GR_640
598                 591, 452
599         },
600         { // GR_1024
601                 973, 720
602         }
603 };
604 int Mission_time_text_val_coords[GR_NUM_RESOLUTIONS][2] = {
605         { // GR_640
606                 613, 460
607         },
608         { // GR_640
609                 995, 728
610         }
611 };
612 const char *Mission_time_fname[GR_NUM_RESOLUTIONS] = {
613         "time1",
614         "time1"
615 };
616
617 // used to draw the hud support view
618 static hud_frames Support_view_gauge;
619 static int Support_view_gauge_loaded = 0;
620 static int Hud_support_view_active;
621 static int Hud_support_view_abort;              // active when we need to display abort message
622 static int Hud_support_view_fade;               // timer
623 static int Hud_support_obj_sig, Hud_support_objnum, Hud_support_target_sig;
624 int Support_view_coords[GR_NUM_RESOLUTIONS][2] = {
625         { // GR_640
626                 265, 334
627         },
628         { // GR_1024
629                 459, 534
630         }
631 };
632 int Support_text_coords[GR_NUM_RESOLUTIONS][2] = {
633         { // GR_640
634                 267, 335
635         },
636         { // GR_1024
637                 462, 536
638         }
639 };
640 int Support_text_val_coords[GR_NUM_RESOLUTIONS][2] = {
641         { // GR_640
642                 -1, 348
643         },
644         { // GR_1024
645                 -1, 546
646         }
647 };
648 int Support_text_dock_coords[GR_NUM_RESOLUTIONS][2] = {                 // "dock in" x coord
649         { // GR_640
650                 270, -1
651         },
652         { // GR_1024
653                 465, -1
654         }
655 };
656 int Support_text_dock_val_coords[GR_NUM_RESOLUTIONS][2] = {             // time value for "dock in" x coord
657         { // GR_640
658                 328, -1
659         },
660         { // GR_1024
661                 524, -1
662         }
663 };
664 const char *Support_fname[GR_NUM_RESOLUTIONS] = {
665         "support1",
666         "support1"
667 };
668
669 // damage gauge stuff
670 #define NUM_DAMAGE_GAUGES       3
671 static hud_frames Damage_gauges[NUM_DAMAGE_GAUGES];
672 static int Damage_gauges_loaded = 0;
673 const char *Damage_gauge_fnames[GR_NUM_RESOLUTIONS][NUM_DAMAGE_GAUGES] = 
674 {
675         //XSTR:OFF
676         { // GR_640
677                 "damage1",
678                 "damage2",
679                 "damage3",
680         },
681         { // GR_1024
682                 "damage1",
683                 "damage2",
684                 "damage3",
685         }
686 //XSTR:ON
687 };
688 int Damage_gauge_line_h[GR_NUM_RESOLUTIONS] = { 
689         9, 
690         9
691 };
692 int Damage_gauge_coords[GR_NUM_RESOLUTIONS][2][2] = {
693         { // GR_640
694                 {245, 38},
695                 {245, 63}
696         },
697         { // GR_1024
698                 {440, 61},
699                 {440, 86}
700         }
701         // These #'s seem to work, although I really don't know why. Frankly, it frightens me,
702         // because it means the 640 coords _shouldn't_. This may be due to D3D strangeness, so
703         // we'll have to investigate when we get hi-res Glide in.
704 };
705 int Damage_text_coords[GR_NUM_RESOLUTIONS][2] = {
706         { // GR_640
707                 248, 40
708         },
709         { // GR_1024
710                 443, 63
711         }
712 };
713 int Hull_integ_coords[GR_NUM_RESOLUTIONS][2] = {
714         { // GR_640
715                 249, 53
716         },
717         { // GR_1024
718                 444, 76
719         }
720 };
721 int Hull_integ_val_coords[GR_NUM_RESOLUTIONS][2] = {
722         { // GR_640
723                 387, 53
724         },
725         { // GR_1024
726                 582, 76
727         },
728 };
729 int Damage_subsys_text_coords[GR_NUM_RESOLUTIONS][2] = {
730         { // GR_640
731                 249, 65
732         },
733         { // GR_1024
734                 444, 88
735         }
736 };
737
738
739 // flashing gauges
740 #define HUD_GAUGE_FLASH_DURATION                5000
741 #define HUD_GAUGE_FLASH_INTERVAL                200
742 int HUD_gauge_flash_duration[NUM_HUD_GAUGES];
743 int HUD_gauge_flash_next[NUM_HUD_GAUGES];
744 int HUD_gauge_bright;
745
746 // Objective display
747 typedef struct objective_display_info
748 {
749         int display_timer;
750         int goal_type;
751         int goal_status;
752         int goal_ntotal;
753         int goal_nresolved;
754
755 } objective_display_info;
756
757 static objective_display_info Objective_display;
758
759 static int                      Objective_display_gauge_inited=0;
760 static hud_frames       Objective_display_gauge;
761 int Objective_display_coords[GR_NUM_RESOLUTIONS][2] = {
762         { // GR_640
763                 245, 114
764         },
765         { // GR_1024
766                 436, 184
767         }
768 };
769 int Objective_text_coords[GR_NUM_RESOLUTIONS][2] = {
770         { // GR_640
771                 -1, 116
772         },
773         { // GR_1024
774                 -1, 186
775         }
776 };
777 int Objective_text_val_coords[GR_NUM_RESOLUTIONS][2] = {
778         { // GR_640
779                 -1, 125
780         },
781         { // GR_1024
782                 -1, 195
783         }
784 };
785 char Objective_fname[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN] = {
786         "objective1",
787         "objective1"
788 };
789
790 // Subspace notify display
791 static int Subspace_notify_active;
792 static int Objective_notify_active;
793 static int HUD_abort_subspace_timer = 1;
794
795 // used to track how player subsystems are getting damaged
796 typedef struct hud_subsys_info
797 {
798         float   last_str;
799         int     flash_duration_timestamp;
800 } hud_subsys_info;
801
802 static hud_subsys_info  Pl_hud_subsys_info[SUBSYSTEM_MAX];
803 static int                                      Pl_hud_next_flash_timestamp;
804 static int                                      Pl_hud_is_bright;
805
806 #define SUBSYS_DAMAGE_FLASH_DURATION    1800
807 #define SUBSYS_DAMAGE_FLASH_INTERVAL    100
808
809 // timers used for popup gauges
810 int HUD_popup_timers[NUM_HUD_GAUGES];
811
812 // forward declarations
813 void update_throttle_sound();
814 void hud_show_damage_popup();
815 void hud_damage_popup_init();
816 void hud_support_view_init();
817 void hud_gauge_flash_init();
818 void hud_objective_message_init();
819 void hud_maybe_display_objective_message();
820 void hud_stop_subspace_notify();
821 void hud_start_subspace_notify();
822 void hud_stop_objective_notify();
823 void hud_start_objective_notify();
824 int hud_subspace_notify_active();
825 int hud_objective_notify_active();
826 void hud_subspace_notify_abort();
827 void hud_maybe_display_subspace_notify();
828 void hud_init_netlag_icon();
829 void hud_maybe_show_netlag_icon();
830 void hud_maybe_display_red_alert();
831 void hud_init_kills_gauge();
832 void hud_show_kills_gauge();
833 int hud_maybe_render_emp_icon();
834 void hud_init_emp_icon();
835
836 //      Saturate a value in minv..maxv.
837 void saturate(int *i, int minv, int maxv)
838 {
839         if (*i < minv)
840                 *i = minv;
841         else if (*i > maxv)
842                 *i = maxv;
843 }
844
845 // init the colors used for the different shades of the HUD
846 void HUD_init_hud_color_array()
847 {
848         int i;
849
850         for ( i = 0; i < HUD_NUM_COLOR_LEVELS; i++ ) {
851                 gr_init_alphacolor( &HUD_color_defaults[i], HUD_color_red, HUD_color_green, HUD_color_blue, (i+1)*16, AC_TYPE_HUD );
852         }
853 }
854
855 // HUD_init will call all the various HUD gauge init functions.  This function is called at the
856 // start of each mission (level)
857 void HUD_init_colors()
858 {
859         saturate(&HUD_color_red, 0, 255);
860         saturate(&HUD_color_green, 0, 255);
861         saturate(&HUD_color_blue, 0, 255);
862         saturate(&HUD_color_alpha, 0, HUD_COLOR_ALPHA_USER_MAX);
863
864         gr_init_alphacolor( &HUD_color_debug, 128, 255, 128, HUD_color_alpha*16, AC_TYPE_HUD );
865         HUD_init_hud_color_array();
866
867         hud_init_targeting_colors();
868         hud_gauge_flash_init();
869 }
870
871 // The following global data is used to determine if we should change the engine sound.
872 // We only check if the throttle has changed every THROTTLE_SOUND_CHECK_INTERVAL ms, and
873 // then we make sure that the throttle has actually changed.  If it has changed, we start
874 // a new sound and/or adjust the volume.  This occurs in update_throttle_sound()
875 //
876 static float last_percent_throttle;
877 #define THROTTLE_SOUND_CHECK_INTERVAL   50      // in ms
878 static int throttle_sound_check_id;
879
880 // used for the display of damaged subsystems
881 typedef struct hud_subsys_damage
882 {
883         int     str;
884         int     type;
885         char    *name;
886 } hud_subsys_damage;
887
888 #define DAMAGE_FLASH_TIME 150
889 static int Damage_flash_bright;
890 static int Damage_flash_timer;
891
892 // initialize the timers used for popup gauges
893 void hud_init_popup_timers()
894 {
895         int i;
896         for (i=0; i<NUM_HUD_GAUGES; i++) {
897                 HUD_popup_timers[i] = timestamp(0);
898         }
899 }
900
901 // Load in the bitmap for the talking head gauge if required
902 void hud_init_talking_head_gauge()
903 {
904         // ensure the talking head border is loaded
905         if ( !Head_frame_gauge_loaded ) {
906                 Head_frame_gauge.first_frame = bm_load_animation(Head_fname[gr_screen.res], &Head_frame_gauge.num_frames);
907                 if ( Head_frame_gauge.first_frame == -1 ) {
908                         Warning(LOCATION, "Could not load in ani: Head_fname[gr_screen.res]\n");
909                 }
910                 Head_frame_gauge_loaded = 1;
911         }
912 }
913
914 // Load in the bitmap for the mission time gauge if required
915 void hud_init_mission_time_gauge()
916 {
917         // ensure the talking head border is loaded
918         if ( !Mission_time_gauge_loaded ) {
919                 Mission_time_gauge.first_frame = bm_load_animation(Mission_time_fname[gr_screen.res], &Mission_time_gauge.num_frames);
920                 if ( Mission_time_gauge.first_frame == -1 ) {
921                         Warning(LOCATION, "Could not load in ani: Mission_time_fname[gr_screen.res]\n");
922                 }
923                 Mission_time_gauge_loaded = 1;
924         }
925 }
926
927 // ----------------------------------------------------------------------
928 // HUD_init()
929 //
930 // Called each level to initalize HUD systems
931 //
932 void HUD_init()
933 {
934         HUD_init_colors();
935         hud_init_msg_window();
936         hud_init_targeting();
937         hud_init_reticle();
938         hud_shield_level_init();
939         hud_init_ets();
940         hud_targetbox_init();
941         hud_escort_init();
942         hud_damage_popup_init();
943         hud_support_view_init();
944         hud_init_squadmsg();            // initialize the vars needed for squadmate messaging
945         hud_init_popup_timers();
946         hud_objective_message_init();
947         hud_init_wingman_status_gauge();
948         hud_anim_init(&Target_static, Target_window_coords[gr_screen.res][0], Target_window_coords[gr_screen.res][1], NOX("TargetStatic"));
949         hud_targetbox_static_init();
950         hud_init_text_flash_gauge();
951         hud_init_netlag_icon(); 
952         hud_init_talking_head_gauge();
953         hud_init_mission_time_gauge();
954         hud_init_kills_gauge();
955         hud_stop_subspace_notify();
956         hud_stop_objective_notify();
957         hud_target_last_transmit_level_init();
958
959         throttle_sound_check_id = timestamp(THROTTLE_SOUND_CHECK_INTERVAL);
960         HUD_abort_subspace_timer = 1;
961         Hud_last_can_target = 1;
962         Hud_can_target_timer = 1;
963         last_percent_throttle = 0.0f;
964
965         // default to high contrast in the nebula
966         HUD_contrast = 0;
967         if(The_mission.flags & MISSION_FLAG_FULLNEB){
968                 HUD_contrast = 1;
969         } 
970 }
971
972 // return !0 if HUD is disabled (ie no gauges are shown/usable), otherwise return 0
973 int hud_disabled()
974 {
975         // if ( Ship_info[Player_ship->ship_info_index].species != SPECIES_TERRAN ) {
976                 //return 1;
977         //}
978
979         return 0;
980 }
981
982 // Determine if we should popup the weapons gauge on the HUD.
983 void hud_maybe_popup_weapons_gauge()
984 {
985         if ( hud_gauge_is_popup(HUD_WEAPONS_GAUGE) ) {
986                 ship_weapon *swp = &Player_ship->weapons;
987                 int                     i;
988
989                 for ( i = 0; i < swp->num_secondary_banks; i++ ) {
990                         if ( swp->secondary_bank_ammo[i] > 0 ) {
991                                 int ms_till_fire = timestamp_until(swp->next_secondary_fire_stamp[i]);
992                                 if ( ms_till_fire >= 1000 ) {
993                                         hud_gauge_popup_start(HUD_WEAPONS_GAUGE, 2500);
994                                 }
995                         }
996                 }
997         }
998 }
999
1000 // hud_update_frame() will update hud systems
1001 //
1002 // This function updates those parts of the hud that are not dependant on the
1003 // rendering of the hud.
1004 void hud_update_frame()
1005 {
1006         object  *targetp;
1007         int             can_target;
1008
1009         update_throttle_sound();
1010         hud_check_reticle_list();
1011         hud_wingman_status_update();
1012
1013         // Check hotkey selections to see if any ships need to be removed
1014         hud_prune_hotkeys();
1015
1016         // Remove dead/departed ships from the escort list
1017         hud_escort_cull_list();
1018
1019         hud_update_reticle( Player );
1020         hud_shield_hit_update();
1021         hud_maybe_popup_weapons_gauge();        
1022
1023         // if emp is active we have to allow targeting by the "random emp" system
1024         // we will intercept player targeting requests in hud_sensors_ok() when checking key commands
1025         // DB - 8/24/98
1026         can_target = hud_sensors_ok(Player_ship, 0);
1027         if(emp_active_local()){
1028                 can_target = 1;
1029         }
1030         if ( !can_target && Hud_last_can_target ) {
1031                 Hud_can_target_timer = timestamp(1200);         
1032         }
1033         Hud_last_can_target = can_target;
1034
1035         if ( timestamp_elapsed(Hud_can_target_timer) ) {
1036                 if ( (Player_ai->target_objnum != -1) && !can_target ){
1037                         Player_ai->target_objnum = -1;
1038                 }
1039         }
1040
1041         // if there is no target, check if auto-targeting is enabled, and select new target
1042         int retarget = 0;
1043         int retarget_turret = 0;
1044
1045         if (Player_ai->target_objnum == -1){
1046                 retarget = 1;
1047         } else if (Objects[Player_ai->target_objnum].type == OBJ_SHIP) {
1048                 if (Ships[Objects[Player_ai->target_objnum].instance].flags & SF_DYING){
1049                         if (timestamp_elapsed(Ships[Objects[Player_ai->target_objnum].instance].final_death_time)) {
1050                                 retarget = 1;
1051                         }
1052                 }
1053         }
1054
1055         // check if big ship and currently selected subsys is turret and turret is dead
1056         // only do this is not retargeting
1057         if ((!retarget) && (Player_ai->target_objnum != -1)) {
1058                 if (Objects[Player_ai->target_objnum].type == OBJ_SHIP) {
1059                         if ( !(Ships[Objects[Player_ai->target_objnum].instance].flags & SF_DYING) ) {
1060                                 if ( Ship_info[Ships[Objects[Player_ai->target_objnum].instance].ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP) ) {
1061                                         ship_subsys *ss = Player_ai->targeted_subsys;
1062                                         if (ss != NULL) {
1063                                                 if ((ss->system_info->type == SUBSYSTEM_TURRET) && (ss->current_hits == 0)) {
1064                                                         retarget_turret = 1;
1065                                                 }
1066                                         }
1067                                 }
1068                         }
1069                 }
1070         }
1071
1072         if ( retarget && can_target ) {
1073                 Player_ai->current_target_is_locked = 0;
1074                 if ( Players[Player_num].flags & PLAYER_FLAGS_AUTO_TARGETING ) {
1075                         Player_ai->target_objnum = -1;
1076                         hud_target_auto_target_next();
1077                 }
1078         }
1079
1080         if (retarget_turret && can_target) {
1081                 SDL_assert(!retarget);
1082                 // get closest weighted live turret
1083                 // hud_target_closest(OBJ_INDEX(Player_obj), FALSE, FALSE);
1084                 void hud_update_closest_turret();
1085                 hud_update_closest_turret();
1086         }
1087
1088         hud_target_change_check();
1089
1090         if (Player_ai->target_objnum == -1) {
1091                 if ( Target_static_looping != -1 ) {
1092                         snd_stop(Target_static_looping);
1093                 }
1094                 return;
1095         }
1096
1097         targetp = &Objects[Player_ai->target_objnum];
1098
1099
1100         int stop_targetting_this_thing = 0;
1101
1102         // check to see if the target is still alive
1103         if ( targetp->flags&OF_SHOULD_BE_DEAD ) {
1104                 stop_targetting_this_thing = 1;
1105         }
1106
1107         Player->target_is_dying = FALSE;
1108         ship    *target_shipp = NULL;
1109         
1110         if ( targetp->type == OBJ_SHIP ) {
1111                 SDL_assert ( targetp->instance >=0 && targetp->instance < MAX_SHIPS );
1112                 target_shipp = &Ships[targetp->instance];
1113                 Player->target_is_dying = target_shipp->flags & SF_DYING;
1114
1115                 // If it is warping out (or exploded), turn off targeting
1116                 if ( target_shipp->flags & (SF_DEPART_WARP|SF_EXPLODED) ) {
1117                         stop_targetting_this_thing = 1;
1118                 }
1119         }
1120
1121         // Check if can still be seen in Nebula
1122         if ( hud_target_invalid_awacs(targetp) ) {
1123                 stop_targetting_this_thing = 1;
1124         }
1125
1126         // If this was found to be something we shouldn't
1127         // target anymore, just remove it
1128         if ( stop_targetting_this_thing )       {
1129                 Player_ai->target_objnum = -1;
1130                 Player_ai->targeted_subsys = NULL;
1131                 hud_stop_looped_locking_sounds();
1132         }
1133         
1134         if (Player->target_is_dying) {
1135                 hud_stop_looped_locking_sounds();
1136                 if ( Players[Player_num].flags & PLAYER_FLAGS_AUTO_TARGETING ) {
1137                         hud_target_auto_target_next();
1138                 }
1139         }
1140
1141         // Switch to battle track when a targeted ship is hostile and within BATTLE_START_MIN_TARGET_DIST
1142         if ( target_shipp && targetp->type == OBJ_SHIP && Event_Music_battle_started == 0 ) {
1143                 if (opposing_team_mask(Player_ship->team)) {
1144                         float   dist_to_target;
1145
1146                         dist_to_target = vm_vec_dist_quick(&targetp->pos, &Player_obj->pos);
1147                         if (dist_to_target < BATTLE_START_MIN_TARGET_DIST) {
1148
1149                                 // If the target has an AI class of none, it is a Cargo, NavBuoy or other non-aggressive
1150                                 // ship, so don't start the battle music        
1151                                 if (SDL_strcasecmp(Ai_class_names[Ai_info[target_shipp->ai_index].ai_class], NOX("none")))
1152                                         event_music_battle_start();
1153                         }
1154                 }
1155         }
1156
1157         // Since we need to reference the player's target integrity in several places this upcoming 
1158         // frame, only calculate once here
1159         if ( target_shipp ) {
1160                 float initial_hull;
1161                 initial_hull = Ship_info[target_shipp->ship_info_index].initial_hull_strength;
1162                 if (  initial_hull <= 0 ) {
1163                         Int3(); // illegal initial hull strength
1164                         Pl_target_integrity = 0.0f;
1165                 } else {
1166                         Pl_target_integrity = targetp->hull_strength / initial_hull;
1167                         if (Pl_target_integrity < 0)
1168                                 Pl_target_integrity = 0.0f;
1169                 }
1170         }
1171
1172         hud_update_cargo_scan_sound();
1173
1174 }
1175
1176 void HUD_render_forward_icon(object *objp)
1177 {
1178         vertex  v0;
1179         vector  p0;
1180
1181         vm_vec_scale_add(&p0, &objp->pos, &objp->orient.v.fvec, 100.0f);
1182         g3_rotate_vertex(&v0, &p0);
1183
1184         gr_set_color(255, 0, 0);
1185         if ((!(v0.flags & PF_OVERFLOW)) && (v0.codes == 0)) // make sure point projected
1186                 g3_draw_sphere(&v0, 1.25f);
1187         else if (v0.codes != 0) { // target center is not on screen
1188                 // draw the offscreen indicator at the edge of the screen where the target is closest to
1189                 hud_draw_offscreen_indicator(&v0, &p0);
1190         }
1191 }
1192
1193 // Draw white brackets around asteroids which has the AF_DRAW_BRACKETS flag set
1194 void hud_show_asteroid_brackets()
1195 {
1196         if ( hud_sensors_ok(Player_ship, 0) ) {
1197                 asteroid_show_brackets();
1198         }
1199 }
1200
1201 // Draw radar gauge on the HUD
1202 void hud_show_radar()
1203 {
1204         if ( hud_disabled() ) {
1205                 return;
1206         }
1207
1208         if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY ))) {
1209                 if ( Game_detail_flags & DETAIL_FLAG_HUD )      {
1210                         if ( hud_gauge_active(HUD_RADAR) ) {
1211                                 HUD_reset_clip();
1212                                 radar_frame_render(flFrametime);
1213                         }
1214                 }
1215         }
1216 }
1217
1218 // Render model of target in the target view box
1219 void hud_show_target_model()
1220 {
1221         if ( hud_disabled() ) {
1222                 return;
1223         }
1224
1225         // display the miniature model of the target in the target box and shade
1226         if ( Game_detail_flags & DETAIL_FLAG_HUD )      {
1227                 if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY)))
1228                         hud_render_target_model();
1229         }
1230 }
1231
1232 void hud_show_common_3d_gauges(float frametime, int in_cockpit)
1233 {
1234         // draw boxes around current selection set, if any
1235         hud_show_selection_set();
1236
1237         // draw the targeting data around any message sender
1238         hud_show_message_sender();
1239
1240         // draw brackets around asteroids is necessary
1241         hud_show_asteroid_brackets();
1242
1243         // draw targetting data around the current target
1244         hud_show_targeting_gauges(frametime, in_cockpit);
1245
1246         // draw brackets and distance to remote detonate missile
1247         hud_show_remote_detonate_missile();
1248 }
1249
1250 // Render gauges that need to be between a g3_start_frame() and a g3_end_frame()
1251 void HUD_render_3d(float frametime)
1252 {
1253         Player->subsys_in_view = -1;
1254
1255         if ( hud_disabled() ) {
1256                 return;
1257         }
1258
1259         if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY))) {
1260
1261                 hud_show_common_3d_gauges(frametime, 1);
1262
1263                 //      Show all homing missiles locked onto the player.
1264                 //      Currently not supporting a way to toggle this as I'm not sure we'll stick wtih this gauge. -- MK, 3/17/97.
1265                 if ( hud_gauge_active(HUD_MISSILE_WARNING_ARROW) ) {
1266                         hud_show_homing_missiles();
1267                 }
1268
1269         } else if ( Viewer_mode & (VM_CHASE | VM_EXTERNAL | VM_WARP_CHASE | VM_PADLOCK_ANY ) ) {
1270                 // If the player is warping out, don't draw the targeting gauges
1271                 SDL_assert(Player != NULL);
1272                 if ( Player->control_mode != PCM_NORMAL ) {
1273                         return;
1274                 }
1275
1276                 hud_show_common_3d_gauges(frametime, 0);
1277         }
1278
1279         if (Viewer_mode & VM_SLEWED) {
1280                 HUD_render_forward_icon(Player_obj);
1281         }
1282 }
1283
1284
1285 // call from HUD_render_2d() when in gameplay, and call when in navmap
1286 void hud_show_messages()
1287 {
1288         // draw the message window
1289         hud_show_msg_window();
1290         hud_show_fixed_text();
1291 }
1292
1293 // decide if we want to blit damage status to the screen
1294 void hud_maybe_show_damage()
1295 {
1296         if ( !hud_gauge_active(HUD_DAMAGE_GAUGE) ) {
1297                 return;
1298         }
1299
1300         // display the current weapon info for the player ship, with ammo/energy counts
1301         if ( hud_gauge_active(HUD_DAMAGE_GAUGE) ) {
1302                 int show_gauge_flag;
1303
1304                 if ( (Ship_info[Player_ship->ship_info_index].initial_hull_strength - Player_obj->hull_strength) > 1.0f ) {
1305                         show_gauge_flag = 1;
1306                 } else {
1307                         show_gauge_flag = 0;
1308                 }
1309
1310                 // is gauge configured as a popup?
1311                 if ( hud_gauge_is_popup(HUD_DAMAGE_GAUGE) ) {
1312                         if ( !hud_gauge_popup_active(HUD_DAMAGE_GAUGE) ) {
1313                                 show_gauge_flag=0;
1314                         }
1315                 }
1316                         
1317                 if ( show_gauge_flag ) {
1318                         hud_show_damage_popup();
1319                 }
1320         }
1321 }
1322
1323 // The damage toggle button was pressed, so change state
1324 void hud_damage_popup_toggle()
1325 {
1326         snd_play(&Snds[SND_SQUADMSGING_ON]);
1327         
1328         // If gague is disabled (off), make it on all the time
1329         if ( !hud_gauge_active(HUD_DAMAGE_GAUGE) ) {
1330                 hud_config_set_gauge_flags(HUD_DAMAGE_GAUGE,1,0);               
1331                 return;
1332         }
1333
1334         // if gauge is popup, turn it off if it is current up, otherwise force it to be up
1335         if ( hud_gauge_is_popup(HUD_DAMAGE_GAUGE) ) {
1336                 if ( Player_obj->hull_strength == Ship_info[Player_ship->ship_info_index].initial_hull_strength ) {
1337                         hud_config_set_gauge_flags(HUD_DAMAGE_GAUGE,1,0);               
1338                 } else {
1339                         hud_config_set_gauge_flags(HUD_DAMAGE_GAUGE,0,0);               
1340                 }
1341                 return;
1342         }
1343
1344         // gauge is on, without any popup... so force it to be off
1345         hud_config_set_gauge_flags(HUD_DAMAGE_GAUGE,0,0);               
1346 }
1347
1348
1349 // Display the current mission time in MM:SS format
1350 void hud_show_mission_time()
1351 {
1352         float mission_time, time_comp;
1353         int minutes=0;
1354         int seconds=0;
1355         
1356         mission_time = f2fl(Missiontime);  // convert to seconds
1357
1358         minutes=(int)(mission_time/60);
1359         seconds=(int)mission_time%60;
1360
1361         hud_set_gauge_color(HUD_MISSION_TIME);
1362
1363         // blit background frame
1364         if ( Mission_time_gauge.first_frame >= 0 ) {
1365                 GR_AABITMAP(Mission_time_gauge.first_frame, Mission_time_coords[gr_screen.res][0], Mission_time_coords[gr_screen.res][1]);                              
1366         }
1367
1368         // print out mission time in MM:SS format
1369         gr_printf(Mission_time_text_coords[gr_screen.res][0], Mission_time_text_coords[gr_screen.res][1], NOX("%02d:%02d"), minutes, seconds);
1370
1371         // display time compression as xN
1372         time_comp = f2fl(Game_time_compression);
1373         if ( time_comp < 1 ) {
1374                 gr_printf(Mission_time_text_val_coords[gr_screen.res][0], Mission_time_text_val_coords[gr_screen.res][1], XSTR( "x%.1f", 215), time_comp);
1375         } else {
1376                 gr_printf(Mission_time_text_val_coords[gr_screen.res][0], Mission_time_text_val_coords[gr_screen.res][1], XSTR( "x%.0f", 216), time_comp);
1377         }
1378 }
1379
1380 // If a head animation is playing, then blit a border around it
1381 void hud_maybe_blit_head_border()
1382 {
1383         if ( Head_frame_gauge.first_frame == -1 ){
1384                 return;
1385         }
1386
1387         if ( message_anim_is_playing() ) {
1388                 // draw frame
1389                 // hud_set_default_color();
1390                 hud_set_gauge_color(HUD_TALKING_HEAD);
1391
1392                 GR_AABITMAP(Head_frame_gauge.first_frame, Head_frame_coords[gr_screen.res][0], Head_frame_coords[gr_screen.res][1]);            
1393
1394                 // draw title
1395                 gr_string(Head_message_coords[gr_screen.res][0], Head_message_coords[gr_screen.res][1], XSTR("message", 217));
1396         }
1397 }
1398
1399 // Black out area behind head animation
1400 void hud_maybe_clear_head_area()
1401 {
1402         if ( Head_frame_gauge.first_frame == -1 ) {
1403                 return;
1404         }
1405
1406         if ( message_anim_is_playing() ) {
1407                 // clear
1408                 if (gr_screen.res == GR_640) {
1409                         HUD_set_clip(7, 45, 160, 120);          // these coords are set in MissionMessage.cpp
1410                 } else {
1411                         HUD_set_clip(7, 66, 160, 120);
1412                 }
1413                 gr_clear();
1414                 HUD_reset_clip();
1415         }
1416 }
1417
1418 void hud_maybe_display_supernova()
1419 {
1420         float time_left;
1421
1422         // if there's a supernova coming
1423         time_left = supernova_time_left();
1424         if(time_left < 0.0f){
1425                 return;
1426         }
1427
1428         gr_set_color_fast(&Color_bright_red);
1429         if(Lcl_pl) {
1430             gr_printf(Supernova_coords[gr_screen.res][0], Supernova_coords[gr_screen.res][1], "Wybuch supernowej : %.2f s", time_left);
1431         } else {
1432             gr_printf(Supernova_coords[gr_screen.res][0], Supernova_coords[gr_screen.res][1], "Supernova Warning : %.2f s", time_left);
1433         }
1434 }
1435
1436 // render multiplayer ping time to the server if appropriate
1437 void hud_render_multi_ping()
1438 {
1439         // if we shouldn't be displaying a ping time, return here
1440         if(!multi_show_ingame_ping()){
1441                 return;
1442         }
1443         
1444         // if we're in multiplayer mode, display our ping time to the server
1445         if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1446                 char ping_str[50];
1447                 memset(ping_str,0,50);
1448
1449                 // if our ping is positive, display it
1450                 if((Netgame.server != NULL) && (Netgame.server->s_info.ping.ping_avg > 0)){
1451                         // get the string
1452                         if(Netgame.server->s_info.ping.ping_avg >= 1000){
1453                                 SDL_strlcpy(ping_str, XSTR("> 1 sec",628), SDL_arraysize(ping_str));
1454                         } else {
1455                                 SDL_snprintf(ping_str, SDL_arraysize(ping_str), XSTR("%d ms", 629), Netgame.server->s_info.ping.ping_avg);
1456                         }
1457
1458                         // blit the string out
1459                         hud_set_default_color();
1460                         gr_string(Ping_coords[gr_screen.res][0], Ping_coords[gr_screen.res][1], ping_str);
1461                 }
1462         }
1463 }
1464
1465 // render all the 2D gauges on the HUD
1466 void HUD_render_2d(float frametime)
1467 {
1468         int show_gauge_flag;
1469
1470         HUD_reset_clip();
1471
1472 /*
1473         // show some scoring debug stuff
1474         {
1475                 extern char Scoring_debug_text[];
1476                 gr_string( 10, 40, Scoring_debug_text );
1477         }
1478 */
1479         if ( hud_disabled() ) {
1480                 return;
1481         }
1482
1483         if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY ))) {           
1484                 // display Energy Transfer System gauges
1485                 if ( hud_gauge_active(HUD_ETS_GAUGE) ) {
1486                         show_gauge_flag=1;
1487                         // is gauge configured as a popup?
1488                         if ( hud_gauge_is_popup(HUD_ETS_GAUGE) ) {
1489                                 if ( !hud_gauge_popup_active(HUD_ETS_GAUGE) ) {
1490                                         show_gauge_flag=0;
1491                                 }
1492                         }
1493                         
1494                         if ( show_gauge_flag ) {
1495                                 hud_show_ets();
1496                         }
1497                 }
1498
1499                 // display afterburner fuel gauge
1500                 if ( hud_gauge_active(HUD_AFTERBURNER_ENERGY) ) {
1501                         hud_set_gauge_color(HUD_AFTERBURNER_ENERGY);
1502                         hud_show_afterburner_gauge();
1503                 }               
1504
1505                 // text flash gauge
1506                 hud_maybe_show_text_flash_icon();
1507
1508                 // maybe show the netlag icon
1509                 if(Game_mode & GM_MULTIPLAYER){
1510                         hud_maybe_show_netlag_icon();
1511
1512                         if(Net_player->flags & NETINFO_FLAG_OBSERVER){
1513                                 hud_render_observer();                                  
1514                         }
1515                 }
1516
1517                 // draw the reticle
1518                 hud_show_reticle();
1519
1520                 /*
1521                 // why is this here twice?
1522                 // display Energy Transfer System gauges
1523                 if ( hud_gauge_active(HUD_ETS_GAUGE) ) {
1524                         show_gauge_flag=1;
1525                         // is gauge configured as a popup?
1526                         if ( hud_gauge_is_popup(HUD_ETS_GAUGE) ) {
1527                                 if ( !hud_gauge_popup_active(HUD_ETS_GAUGE) ) {
1528                                         show_gauge_flag=0;
1529                                 }
1530                         }
1531                         
1532                         if ( show_gauge_flag ) {
1533                                 hud_show_ets();
1534                         }
1535                 }
1536                 */
1537
1538                 // display info on the ships in the escort list
1539                 if ( hud_gauge_active(HUD_ESCORT_VIEW) ) {
1540                         show_gauge_flag=1;
1541                         // is gauge configured as a popup?
1542                         if ( hud_gauge_is_popup(HUD_ESCORT_VIEW) ) {
1543                                 if ( !hud_gauge_popup_active(HUD_ESCORT_VIEW) ) {
1544                                         show_gauge_flag=0;
1545                                 }
1546                         }
1547                         
1548                         if ( show_gauge_flag ) {
1549                                 hud_set_gauge_color(HUD_ESCORT_VIEW);
1550                                 hud_display_escort();
1551                         }
1552                 }
1553
1554                 // display the current weapon info for the player ship, with ammo/energy counts
1555                 if ( hud_gauge_active(HUD_WEAPONS_GAUGE) ) {
1556                         show_gauge_flag=1;
1557                         // is gauge configured as a popup?
1558                         if ( hud_gauge_is_popup(HUD_WEAPONS_GAUGE) ) {
1559                                 if ( !hud_gauge_popup_active(HUD_WEAPONS_GAUGE) ) {
1560                                         show_gauge_flag=0;
1561                                 }
1562                         }
1563                         
1564                         if ( show_gauge_flag ) {
1565                                 hud_show_weapons();
1566                         }
1567                 }
1568
1569                 // display player countermeasures count
1570                 if ( hud_gauge_active(HUD_CMEASURE_GAUGE) ) {
1571                         show_gauge_flag=1;
1572                         // is gauge configured as a popup?
1573                         if ( hud_gauge_is_popup(HUD_CMEASURE_GAUGE) ) {
1574                                 if ( !hud_gauge_popup_active(HUD_CMEASURE_GAUGE) ) {
1575                                         show_gauge_flag=0;
1576                                 }
1577                         }
1578                         
1579                         if ( show_gauge_flag ) {
1580                                 hud_show_cmeasure_gague();
1581                         }
1582                 }
1583
1584                 if ( hud_gauge_active(HUD_WEAPONS_ENERGY) ) {
1585                         hud_show_weapon_energy_gauge();
1586                 }
1587
1588                 // show the auto-target icons
1589                 hud_show_auto_icons();                          
1590
1591                 // draw a border around a talking head if it is playing
1592                 hud_maybe_blit_head_border();
1593
1594                 // draw the status of support ship servicing the player
1595                 hud_support_view_blit();
1596
1597                 // draw the damage status
1598                 hud_maybe_show_damage();
1599
1600                 // show mission time 
1601                 if ( hud_gauge_active(HUD_MISSION_TIME) ) {
1602                         hud_show_mission_time();
1603                 }
1604
1605                 // show subspace notify gauge
1606                 hud_maybe_display_subspace_notify();
1607
1608                 // show objective status gauge
1609                 if ( hud_gauge_active(HUD_OBJECTIVES_NOTIFY_GAUGE) ) {
1610                         hud_maybe_display_objective_message();
1611                 }
1612
1613                 if ( hud_gauge_active(HUD_WINGMEN_STATUS) ) {
1614                         hud_wingman_status_render();
1615                 }
1616
1617                 if ( hud_gauge_active(HUD_KILLS_GAUGE) ) {
1618                         show_gauge_flag=1;
1619                         // is gauge configured as a popup?
1620                         if ( hud_gauge_is_popup(HUD_KILLS_GAUGE) ) {
1621                                 if ( !hud_gauge_popup_active(HUD_KILLS_GAUGE) ) {
1622                                         show_gauge_flag=0;
1623                                 }
1624                         }
1625                         
1626                         if ( show_gauge_flag ) {
1627                                 hud_show_kills_gauge();
1628                         }
1629                 }
1630
1631                 // show the player shields
1632                 if ( hud_gauge_active(HUD_PLAYER_SHIELD_ICON) ) {
1633                         hud_shield_show(Player_obj);
1634                 }
1635
1636                 // show the directives popup and/or training popup
1637                 message_training_display();
1638
1639                 // if this is a multiplayer game, blit any icons/bitmaps indicating voice recording or playback
1640                 if(Game_mode & GM_MULTIPLAYER){
1641                         hud_show_voice_status();
1642                 }
1643         }
1644
1645         hud_show_messages();
1646
1647         // maybe render any necessary multiplayer text messaging strings being entered
1648         hud_maybe_render_multi_text();
1649
1650         // show red alert notify gauge when moving to red alert
1651         hud_maybe_display_red_alert();  
1652
1653         // display supernova warning
1654         hud_maybe_display_supernova();
1655
1656         // check to see if we are in messaging mode.  If so, send the key to the code
1657         // to deal with the message.  hud_sqaudmsg_do_frame will return 0 if the key
1658         // wasn't used in messaging mode, otherwise 1.  In the event the key was used,
1659         // return immediately out of this function.
1660         if ( Players->flags & PLAYER_FLAGS_MSG_MODE ) {
1661                 if ( hud_squadmsg_do_frame() ){
1662                         return;
1663                 }
1664         }
1665
1666         hud_render_multi_ping();        
1667 }
1668
1669
1670 // hud_stop_looped_engine_sounds()
1671 //
1672 // This function will set the loop id's for the engine noises to -1, this will force any
1673 // looping engine sounds to stop.  This should only be called when the game decides to
1674 // stop all looping sounds
1675 //
1676
1677 void hud_stop_looped_engine_sounds()
1678 {
1679         if ( Player_engine_snd_loop > -1 )      {
1680                 snd_stop(Player_engine_snd_loop);
1681                 //snd_chg_loop_status(Player_engine_snd_loop, 0);
1682                 Player_engine_snd_loop = -1;
1683         }
1684 }
1685
1686 #define ZERO_PERCENT                    0.01f
1687 #define ENGINE_MAX_VOL          1.0f
1688 #define ENGINE_MAX_PITCH        44100
1689
1690 void update_throttle_sound()
1691 {
1692         // determine what engine sound to play
1693         float percent_throttle;
1694 //      float throttle_pitch;
1695
1696         // if we're a multiplayer observer, stop any engine sounds from playing and return
1697         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
1698                 // stop engine sound if it is playing
1699                 if(Player_engine_snd_loop != -1){
1700                         snd_stop(Player_engine_snd_loop);
1701                         Player_engine_snd_loop = -1;
1702                 }
1703
1704                 // return
1705                 return;
1706         }
1707
1708         if ( timestamp_elapsed(throttle_sound_check_id) ) {
1709
1710                 throttle_sound_check_id = timestamp(THROTTLE_SOUND_CHECK_INTERVAL);
1711         
1712                 if ( Ships[Player_obj->instance].current_max_speed == 0 ) {
1713                         percent_throttle = Player_obj->phys_info.fspeed / Ship_info[Ships[Player_obj->instance].ship_info_index].max_speed;
1714                 } else {
1715                         percent_throttle = Player_obj->phys_info.fspeed / Ships[Player_obj->instance].current_max_speed;
1716                 }
1717
1718                 // If the throttle has changed, modify the sound
1719                 if ( percent_throttle != last_percent_throttle || Player_engine_snd_loop == -1 ) {
1720
1721                         if ( percent_throttle < ZERO_PERCENT ) {
1722                                 if ( Player_engine_snd_loop > -1 )      {
1723                                         snd_chg_loop_status(Player_engine_snd_loop, 0);
1724                                         Player_engine_snd_loop = -1;
1725                                 }
1726                         }
1727                         else {
1728                                 if ( Player_engine_snd_loop == -1 ){
1729                                         Player_engine_snd_loop = snd_play_looping( &Snds[SND_ENGINE], 0.0f, percent_throttle * ENGINE_MAX_VOL );
1730                                 } else {
1731                                         // The sound may have been trashed at the low-level if sound channel overflow.
1732                                         // TODO: implement system where certain sounds cannot be interrupted (priority?)
1733                                         if ( snd_is_playing(Player_engine_snd_loop) ) {
1734                                                 snd_set_volume(Player_engine_snd_loop, percent_throttle * ENGINE_MAX_VOL);
1735                                         }
1736                                         else {
1737                                                 Player_engine_snd_loop = -1;
1738                                         }
1739                                 }
1740                         }
1741
1742 //                      throttle_pitch = snd_get_pitch(Player_engine_snd_loop);
1743 //                      if ( percent_throttle > 0.5f ) {
1744 //                              snd_set_pitch(Player_engine_snd_loop, 1.0f + (percent_throttle-0.5f)*1.0f));
1745 //                      }
1746
1747                 }       // end if (percent_throttle != last_percent_throttle)
1748
1749                 last_percent_throttle = percent_throttle;
1750
1751         }       // end if ( timestamp_elapsed(throttle_sound_check_id) )
1752 }
1753
1754 // called at the beginning of each level.  Loads frame data in once, and initializes any damage
1755 // gauge specific data
1756 void hud_damage_popup_init()
1757 {
1758         int i;
1759
1760         if ( !Damage_gauges_loaded ) {
1761                 for ( i = 0; i < NUM_DAMAGE_GAUGES; i++ ) {
1762                         Damage_gauges[i].first_frame = bm_load_animation(Damage_gauge_fnames[gr_screen.res][i], &Damage_gauges[i].num_frames);
1763                         if ( Damage_gauges[i].first_frame == -1 ) {
1764                                 Warning(LOCATION, "Could not load in the ani: %s\n", Damage_gauge_fnames[gr_screen.res][i]);
1765                                 return;
1766                         }
1767                 }
1768                 Damage_gauges_loaded = 1;
1769         }
1770
1771         Damage_flash_bright = 0;
1772         Damage_flash_timer =    1;
1773
1774         for ( i = 0; i < SUBSYSTEM_MAX; i++ ) {
1775                 Pl_hud_subsys_info[i].last_str = 1000.0f;
1776                 Pl_hud_subsys_info[i].flash_duration_timestamp = 1;
1777                 Pl_hud_next_flash_timestamp = 1;
1778                 Pl_hud_is_bright = 0;
1779         }
1780 }
1781
1782 // ---------------------------------------------------------
1783 // show player damage status via a popup window
1784
1785 void hud_show_damage_popup()
1786 {
1787         model_subsystem *psub;
1788         ship_subsys                     *pss;
1789         int                                     sx, sy, bx, by, w, h, screen_integrity, num, best_str, best_index;
1790         float                                   strength, shield, integrity;
1791         char                                    buf[128];
1792         hud_subsys_damage       hud_subsys_list[SUBSYSTEM_MAX]; 
1793
1794         if ( Damage_gauges[0].first_frame == -1 ) {
1795                 return;
1796         }
1797
1798         if ( (The_mission.game_type & MISSION_TYPE_TRAINING) && Training_msg_visible ){
1799                 return;
1800         }
1801                 
1802         hud_get_target_strength(Player_obj, &shield, &integrity);
1803         screen_integrity = fl2i(integrity*100);
1804
1805         if ( hud_gauge_is_popup(HUD_DAMAGE_GAUGE) ) {
1806                 if ( screen_integrity >= 100 ) {
1807                         return;
1808                 }
1809         }
1810
1811         if ( timestamp_elapsed(Damage_flash_timer) ) {
1812                 Damage_flash_timer = timestamp(DAMAGE_FLASH_TIME);
1813                 Damage_flash_bright ^= 1;
1814         }
1815
1816         hud_set_gauge_color(HUD_DAMAGE_GAUGE);
1817
1818         // draw the top of the damage pop-up
1819         GR_AABITMAP(Damage_gauges[0].first_frame, Damage_gauge_coords[gr_screen.res][0][0], Damage_gauge_coords[gr_screen.res][0][1]);  
1820         gr_string(Damage_text_coords[gr_screen.res][0], Damage_text_coords[gr_screen.res][1], XSTR( "damage", 218));
1821
1822         // show hull integrity
1823         if ( screen_integrity < 100 ) {         
1824                 if ( screen_integrity == 0 ) {
1825                         screen_integrity = 1;
1826                 }
1827                 SDL_snprintf(buf, SDL_arraysize(buf), XSTR( "%d%%", 219), screen_integrity);
1828                 hud_num_make_mono(buf);
1829                 gr_get_string_size(&w, &h, buf);
1830                 if ( screen_integrity < 30 ) {
1831                         gr_set_color_fast(&Color_red);
1832                 }
1833                 gr_string(Hull_integ_coords[gr_screen.res][0], Hull_integ_coords[gr_screen.res][1], XSTR( "Hull Integrity", 220));
1834                 gr_string(Hull_integ_val_coords[gr_screen.res][0] - w, Hull_integ_val_coords[gr_screen.res][1], buf);
1835         } 
1836
1837         // show damaged subsystems
1838         sx = Damage_subsys_text_coords[gr_screen.res][0];
1839         sy = Damage_subsys_text_coords[gr_screen.res][1];
1840         bx = Damage_gauge_coords[gr_screen.res][1][0];
1841         by = Damage_gauge_coords[gr_screen.res][1][1];
1842
1843         num = 0;
1844         for ( pss = GET_FIRST(&Player_ship->subsys_list); pss !=END_OF_LIST(&Player_ship->subsys_list); pss = GET_NEXT(pss) ) {
1845                 psub = pss->system_info;
1846                 strength = ship_get_subsystem_strength(Player_ship, psub->type);
1847                 if ( strength < 1 ) {
1848                         screen_integrity = fl2i(strength*100);
1849                         if ( screen_integrity == 0 ) {
1850                                 if ( strength > 0 ) {
1851                                         screen_integrity = 1;
1852                                 }
1853                         }
1854                         hud_subsys_list[num].name = psub->name;
1855                         hud_subsys_list[num].str  = screen_integrity;
1856                         hud_subsys_list[num].type = psub->type;
1857                         num++;
1858
1859                         if ( strength < Pl_hud_subsys_info[psub->type].last_str ) {
1860                                 Pl_hud_subsys_info[psub->type].flash_duration_timestamp = timestamp(SUBSYS_DAMAGE_FLASH_DURATION);
1861                         }
1862                         Pl_hud_subsys_info[psub->type].last_str = strength;
1863                 }
1864         }
1865
1866         int type;
1867         for ( int i = 0; i < num; i++ ) {
1868                 best_str = 1000;
1869                 best_index = -1;
1870                 for ( int j = 0; j < num-i; j++ ) {
1871                         if ( hud_subsys_list[j].str < best_str ) {
1872                                 best_str = hud_subsys_list[j].str;
1873                                 best_index = j;
1874                         }
1875                 }
1876
1877                 SDL_assert(best_index >= 0);
1878                 SDL_assert(best_str >= 0);
1879
1880                 // display strongest subsystem left in list
1881                 // draw the bitmap
1882                 // hud_set_default_color();
1883                 hud_set_gauge_color(HUD_DAMAGE_GAUGE);
1884
1885                 GR_AABITMAP(Damage_gauges[1].first_frame, bx, by);
1886                 by += Damage_gauge_line_h[gr_screen.res];
1887
1888                 type = hud_subsys_list[best_index].type;
1889                 if ( !timestamp_elapsed( Pl_hud_subsys_info[type].flash_duration_timestamp ) ) {
1890                         if ( timestamp_elapsed( Pl_hud_next_flash_timestamp ) ) {
1891                                 Pl_hud_is_bright ^= 1;
1892                                 Pl_hud_next_flash_timestamp = timestamp(SUBSYS_DAMAGE_FLASH_INTERVAL);
1893                         }
1894                         
1895                         if ( Pl_hud_is_bright ) {
1896                                 int alpha_color;
1897                                 alpha_color = SDL_min(HUD_COLOR_ALPHA_MAX,HUD_color_alpha+HUD_BRIGHT_DELTA);
1898                                 // gr_set_color_fast(&HUD_color_defaults[alpha_color]);
1899
1900                                 hud_set_gauge_color(HUD_DAMAGE_GAUGE, alpha_color);
1901                         } else {                                
1902                                 hud_set_gauge_color(HUD_DAMAGE_GAUGE);
1903                         }
1904                 }
1905
1906                 // draw the text
1907                 if ( best_str < 30 ) {
1908                         if ( best_str <= 0 ) {
1909                                 if ( Damage_flash_bright ) {
1910                                         gr_set_color_fast(&Color_bright_red);
1911                                 } else {
1912                                         gr_set_color_fast(&Color_red);
1913                                 }
1914
1915                         } else {
1916                                 gr_set_color_fast(&Color_red);
1917                         }
1918                 } else {
1919                         hud_set_gauge_color(HUD_DAMAGE_GAUGE);
1920                 }               
1921
1922                 gr_string(sx, sy, hud_targetbox_truncate_subsys_name(hud_subsys_list[best_index].name, MAX_NAME_LEN));
1923                 SDL_snprintf(buf, SDL_arraysize(buf), XSTR( "%d%%", 219), best_str);
1924                 hud_num_make_mono(buf);
1925                 gr_get_string_size(&w, &h, buf);
1926                 gr_string(Hull_integ_val_coords[gr_screen.res][0] - w, sy, buf);
1927                 sy += Damage_gauge_line_h[gr_screen.res];
1928
1929                 // remove it from hud_subsys_list
1930                 if ( best_index < (num-i-1) ) {
1931                         hud_subsys_list[best_index] = hud_subsys_list[num-i-1];
1932                 }
1933         }
1934
1935         // draw the bottom of the gauge
1936         // hud_set_default_color();
1937         hud_set_gauge_color(HUD_DAMAGE_GAUGE);
1938
1939         GR_AABITMAP(Damage_gauges[2].first_frame, bx, by);              
1940 }
1941
1942 // init the members of the hud_anim struct to default values
1943 void hud_anim_init(hud_anim *ha, int sx, int sy, const char *filename)
1944 {
1945         ha->first_frame = -1;
1946         ha->num_frames          = 0;
1947         ha->total_time          = 0.0f;
1948         ha->time_elapsed        = 0.0f;
1949         ha->sx                          = sx;
1950         ha->sy                          = sy;
1951         SDL_strlcpy(ha->name, filename, SDL_arraysize(ha->name));
1952 }
1953
1954 // call to unload the targetbox static animation
1955 void hud_anim_release(hud_anim *ha)
1956 {
1957         int i;
1958
1959         if (ha->first_frame < 0)
1960                 return;
1961
1962         for ( i = 0; i < ha->num_frames; i++ ) {
1963                 bm_unload(ha->first_frame + i);
1964         }
1965 }
1966
1967 // load a hud_anim
1968 // return 0 is successful, otherwise return -1
1969 int hud_anim_load(hud_anim *ha)
1970 {
1971         int             fps;
1972
1973         ha->first_frame = bm_load_animation(ha->name, &ha->num_frames, &fps);
1974         if ( ha->first_frame == -1 ) {
1975                 Int3(); // couldn't load animation file in
1976                 return -1;
1977         }
1978         SDL_assert(fps != 0);
1979         ha->total_time = i2fl(ha->num_frames)/fps;
1980         return 0;
1981 }
1982
1983 // render out a frame of the targetbox static animation, based on how much time has
1984 // elapsed
1985 // input:       ha                              =>      pointer to hud anim info
1986 //                              frametime       =>      seconds elapsed since last frame
1987 //                              draw_alpha      =>      draw bitmap as alpha-bitmap (default 0)
1988 //                              loop                    =>      anim should loop (default 1)
1989 //                              hold_last       =>      should last frame be held (default 0)
1990 //                              reverse         =>      play animation in reverse (default 0)
1991 int hud_anim_render(hud_anim *ha, float frametime, int draw_alpha, int loop, int hold_last, int reverse)
1992 {
1993         int framenum;
1994
1995         if ( ha->num_frames <= 0 ) {
1996                 if ( hud_anim_load(ha) == -1 )
1997                         return 0;
1998         }
1999
2000         ha->time_elapsed += frametime;
2001         if ( ha->time_elapsed > ha->total_time ) {
2002                 if ( loop ) {
2003                         ha->time_elapsed = 0.0f;
2004                 } else {
2005                         if ( !hold_last ) {
2006                                 return 0;
2007                         }
2008                 }
2009         }
2010
2011         // draw the correct frame of animation
2012         framenum = fl2i( (ha->time_elapsed * ha->num_frames) / ha->total_time );
2013         if (reverse) {
2014                 framenum = (ha->num_frames-1) - framenum;
2015         }
2016
2017         if ( framenum < 0 )
2018                 framenum = 0;
2019         if ( framenum >= ha->num_frames )
2020                 framenum = ha->num_frames-1;
2021
2022         // Blit the bitmap for this frame
2023         if(emp_should_blit_gauge()){
2024                 gr_set_bitmap(ha->first_frame + framenum, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2025                 if ( draw_alpha ){
2026                         gr_aabitmap(ha->sx, ha->sy);
2027                 } else {
2028                         gr_bitmap(ha->sx, ha->sy);
2029                 }
2030         }
2031
2032         return 1;
2033 }
2034
2035 // convert a number string to use mono-spaced 1 character
2036 void hud_num_make_mono(char *num_str)
2037 {
2038         int len, i, sc;
2039         len = strlen(num_str);
2040
2041         sc = Lcl_special_chars;
2042         for ( i = 0; i < len; i++ ) {
2043                 if ( num_str[i] == '1' ) {
2044                         num_str[i] = (char)(sc + 1);
2045                 }
2046         }
2047 }
2048
2049 // flashing text gauge
2050 void hud_init_text_flash_gauge()
2051 {       
2052 }
2053
2054 void hud_start_text_flash(const char *txt, int t)
2055 {
2056         // bogus
2057         if(txt == NULL){
2058                 SDL_strlcpy(Hud_text_flash, "", SDL_arraysize(Hud_text_flash));
2059                 return;
2060         }
2061
2062         // HACK. don't override EMP if its still going    :)
2063         if(!strcmp(Hud_text_flash, NOX("Emp")) && !hud_targetbox_flash_expired(TBOX_FLASH_CMEASURE)){
2064                 return;
2065         }
2066
2067         SDL_strlcpy(Hud_text_flash, txt, SDL_arraysize(Hud_text_flash));
2068         hud_targetbox_start_flash(TBOX_FLASH_CMEASURE, t);      
2069 }
2070
2071 void hud_maybe_show_text_flash_icon()
2072 {               
2073         int bright;
2074
2075         if ( hud_targetbox_flash_expired(TBOX_FLASH_CMEASURE) ) {
2076                 return;
2077         }
2078
2079         hud_targetbox_maybe_flash(TBOX_FLASH_CMEASURE);         
2080
2081         // bright?
2082         bright = hud_targetbox_is_bright(TBOX_FLASH_CMEASURE);
2083
2084         // draw
2085         hud_show_text_flash_icon(Hud_text_flash, Hud_text_flash_coords[gr_screen.res][1], bright);
2086 }
2087
2088 void hud_show_text_flash_icon(const char *txt, int y, int bright)
2089 {
2090         int w, h;
2091
2092 #ifndef MAKE_FS1
2093         // different font size in hi-res
2094         if(gr_screen.res != GR_640){
2095                 gr_set_font(FONT3);
2096         }
2097 #endif
2098
2099         // set color
2100         if(bright){
2101                 hud_set_gauge_color(HUD_TEXT_FLASH, HUD_C_DIM);
2102         } else {
2103                 gr_set_color_fast(&Color_black);
2104         }
2105
2106         // string size
2107         gr_get_string_size(&w, &h, txt);
2108
2109         // draw the box 
2110         gr_rect( (int)((((float)gr_screen.max_w / 2.0f) - ((float)w / 2.0f)) - 1.0f), (int)((float)y - 1.0f), w + 2, h + 1);
2111
2112         // string
2113         hud_set_gauge_color(HUD_TEXT_FLASH, HUD_C_BRIGHT);      
2114         gr_string(0x8000, y, txt);
2115
2116         // go back to normal font
2117         gr_set_font(FONT1);
2118 }
2119
2120 // maybe display the kills gauge on the HUD
2121 void hud_show_kills_gauge()
2122 {
2123         if ( Kills_gauge.first_frame < 0 ) {
2124                 return;
2125         }
2126
2127         // hud_set_default_color();
2128         hud_set_gauge_color(HUD_KILLS_GAUGE);
2129
2130         // draw background
2131         GR_AABITMAP(Kills_gauge.first_frame, Kills_gauge_coords[gr_screen.res][0], Kills_gauge_coords[gr_screen.res][1]);       
2132
2133         gr_string(Kills_text_coords[gr_screen.res][0], Kills_text_coords[gr_screen.res][1], XSTR( "kills:", 223));
2134
2135         // display how many kills the player has so far
2136         char    num_kills_string[32];
2137         int     w,h;
2138
2139         if ( !Player ) {
2140                 Int3();
2141                 return;
2142         }
2143
2144         SDL_snprintf(num_kills_string, SDL_arraysize(num_kills_string), "%d", Player->stats.m_kill_count_ok);
2145
2146         gr_get_string_size(&w, &h, num_kills_string);
2147         if (Lcl_gr) {
2148                 gr_string(Kills_text_val_coords_gr[gr_screen.res][0]-w, Kills_text_val_coords_gr[gr_screen.res][1], num_kills_string);
2149         } else {
2150                 gr_string(Kills_text_val_coords[gr_screen.res][0]-w, Kills_text_val_coords[gr_screen.res][1], num_kills_string);
2151         }
2152 }
2153
2154 // maybe show the netlag icon on the hud
2155 void hud_maybe_show_netlag_icon()
2156 {
2157         int lag_status;
2158
2159         if ( Netlag_icon.first_frame == -1 ) {
2160                 Int3();
2161                 return;
2162         }
2163
2164         lag_status = multi_query_lag_status();  
2165
2166         switch(lag_status) {
2167         case 0:
2168                 // draw the net lag icon flashing
2169                 hud_targetbox_start_flash(TBOX_FLASH_NETLAG);
2170                 if(hud_targetbox_maybe_flash(TBOX_FLASH_NETLAG)){
2171 #ifdef FS2_DEMO
2172                         hud_set_gauge_color(HUD_RADAR, HUD_C_BRIGHT);
2173 #else
2174                         hud_set_gauge_color(HUD_LAG_GAUGE, HUD_C_BRIGHT);
2175 #endif
2176                 } else {
2177 #ifdef FS2_DEMO
2178                         hud_set_gauge_color(HUD_RADAR);
2179 #else
2180                         hud_set_gauge_color(HUD_LAG_GAUGE);
2181 #endif
2182                 }
2183                 gr_set_bitmap(Netlag_icon.first_frame, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2184                 break;
2185         case 1:
2186                 // draw the disconnected icon flashing fast
2187                 if(hud_targetbox_maybe_flash(TBOX_FLASH_NETLAG,1)){
2188 #ifdef FS2_DEMO
2189                         hud_set_gauge_color(HUD_RADAR, HUD_C_BRIGHT);
2190 #else
2191                         hud_set_gauge_color(HUD_LAG_GAUGE, HUD_C_BRIGHT);
2192 #endif
2193                 } else {
2194 #ifdef FS2_DEMO
2195                         hud_set_gauge_color(HUD_RADAR);
2196 #else
2197                         hud_set_gauge_color(HUD_LAG_GAUGE);
2198 #endif
2199                 }
2200                 gr_set_bitmap(Netlag_icon.first_frame+1, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2201                 break;
2202         default:
2203                 // nothing to draw
2204                 return;
2205         }
2206         
2207         if(emp_should_blit_gauge()){
2208                 gr_aabitmap(Netlag_coords[gr_screen.res][0], Netlag_coords[gr_screen.res][1]);
2209         }
2210 }
2211
2212 // load in kills gauge if required
2213 void hud_init_kills_gauge()
2214 {
2215         if ( !Kills_gauge_loaded ) {
2216                 Kills_gauge.first_frame = bm_load_animation(Kills_fname[gr_screen.res], &Kills_gauge.num_frames);
2217                 if ( Kills_gauge.first_frame == -1 ) {
2218                         Warning(LOCATION, "Could not load in the kills ani: Kills_fname[gr_screen.res]\n");
2219                         return;
2220                 }
2221                 Kills_gauge_loaded = 1;
2222         }
2223 }
2224
2225 // load in netlag icon if required
2226 void hud_init_netlag_icon()
2227 {
2228         if ( !Netlag_icon_loaded ) {
2229                 Netlag_icon.first_frame = bm_load_animation(Netlag_fname[gr_screen.res], &Netlag_icon.num_frames);
2230                 if ( Netlag_icon.first_frame == -1 ) {
2231                         Warning(LOCATION, "Could not load in the netlag ani: Netlag_fname[gr_screen.res]\n");
2232                         return;
2233                 }
2234                 Netlag_icon_loaded = 1;
2235         }
2236 }
2237
2238 // called at mission start to init data, and load support view bitmap if required
2239 void hud_support_view_init()
2240 {
2241         Hud_support_view_fade = 1;
2242         Hud_support_obj_sig = -1;
2243         Hud_support_target_sig = -1;
2244         Hud_support_objnum = -1;
2245         Hud_support_view_active = 0;
2246         Hud_support_view_abort = 0;
2247
2248         // ensure the talking head border is loaded
2249         if ( !Support_view_gauge_loaded ) {
2250                 Support_view_gauge.first_frame = bm_load_animation(Support_fname[gr_screen.res], &Support_view_gauge.num_frames);
2251                 if ( Support_view_gauge.first_frame == -1 ) {
2252                         Warning(LOCATION, "Could not load in ani: Support_fname[gr_screen.res]\n");
2253                 }
2254                 Support_view_gauge_loaded = 1;
2255         }
2256 }
2257
2258 // start displaying the support view pop-up.  This will remain up until hud_support_view_stop is called.
2259 // input:       objnum  =>              object number for the support ship
2260 void hud_support_view_start()
2261 {
2262         Hud_support_view_active = 1;
2263         Hud_support_view_fade = 1;
2264 }
2265
2266 // stop displaying the support view pop-up
2267 void hud_support_view_stop(int stop_now)
2268 {
2269         if ( stop_now ) {
2270                 Hud_support_view_active = 0;
2271                 Hud_support_view_fade = 1;
2272                 Hud_support_view_abort = 0;
2273         } else {
2274                 Hud_support_view_fade = timestamp(2000);
2275         }
2276
2277         Hud_support_obj_sig = -1;
2278         Hud_support_target_sig = -1;
2279         Hud_support_objnum = -1;
2280 }
2281
2282 void hud_support_view_abort()
2283 {
2284         hud_support_view_stop(0);
2285         Hud_support_view_abort = 1;
2286 }
2287
2288 // return the number of seconds until repair ship will dock with player, return -1 if error
2289 // 
2290 // mwa made this function more general purpose
2291 //
2292 // NOTE: This function is pretty stupid now.  It just assumes the player is sitting still, and
2293 //                 the support ship is moving directly to the player.
2294 int hud_support_get_dock_time( int objnum )
2295 {
2296         ai_info *aip;
2297         object  *support_objp, *other_objp;
2298         float           dist, rel_speed, support_speed;
2299         vector  rel_vel;
2300
2301         support_objp = &Objects[objnum];
2302         aip = &Ai_info[Ships[support_objp->instance].ai_index];
2303
2304         // if the ship is docked, return 0
2305         if ( aip->ai_flags & AIF_DOCKED )
2306                 return 0;
2307
2308         // get the dockee object pointer
2309         if (aip->goal_objnum == -1) {
2310                 Int3(); //      Shouldn't happen, but let's recover gracefully.
2311                 return 0;
2312         }
2313
2314         other_objp = &Objects[aip->goal_objnum];
2315
2316         vm_vec_sub(&rel_vel, &support_objp->phys_info.vel, &other_objp->phys_info.vel);
2317         rel_speed = vm_vec_mag_quick(&rel_vel);
2318
2319         dist = vm_vec_dist_quick(&other_objp->pos, &support_objp->pos);
2320
2321         support_speed = support_objp->phys_info.speed;
2322
2323         if ( rel_speed <= support_speed/2.0f) { //      This means the player is moving away fast from the support ship.
2324                 return (int) (dist/support_speed);
2325         } else {
2326                 float   d1;
2327                 float   d = dist;
2328                 float   time = 0.0f;
2329                 
2330                 if (rel_speed < 20.0f)
2331                         rel_speed = 20.0f;
2332
2333                 //      When faraway, use max speed, not current speed.  Might not have sped up yet.
2334                 if (d > 100.0f) {
2335                         time += (d - 100.0f)/support_objp->phys_info.max_vel.xyz.z;
2336                 }
2337
2338                 //      For mid-range, use current speed.
2339                 if (d > 60.0f) {
2340                         d1 = SDL_min(d, 100.0f);
2341
2342                         time += (d1 - 60.0f)/rel_speed;
2343                 }
2344
2345                 //      For nearby, ship will have to slow down a bit for docking maneuver.
2346                 if (d > 30.0f) {
2347                         d1 = SDL_min(d, 60.0f);
2348
2349                         time += (d1 - 30.0f)/5.0f;
2350                 }
2351
2352                 //      For very nearby, ship moves quite slowly.
2353                 d1 = SDL_min(d, 30.0f);
2354                 time += d1/7.5f;
2355
2356                 return fl2i(time);
2357         }
2358 }
2359
2360 // Locate the closest support ship which is trying to dock with player, return -1 if there is no support
2361 // ship currently trying to dock with the player
2362 // MA:  4/22/98 -- pass in objp to find support ship trying to dock with objp
2363 int hud_support_find_closest( int objnum )
2364 {
2365         ship_obj                *sop;
2366         ai_info         *aip;
2367         object          *objp;
2368         int i;
2369
2370         objp = &Objects[objnum];
2371
2372         sop = GET_FIRST(&Ship_obj_list);
2373         while(sop != END_OF_LIST(&Ship_obj_list)){
2374                 if ( Ship_info[Ships[Objects[sop->objnum].instance].ship_info_index].flags & SIF_SUPPORT ) {
2375                         int pship_index, sindex;
2376
2377                         // make sure support ship is not dying
2378                         if ( !(Ships[Objects[sop->objnum].instance].flags & (SF_DYING|SF_EXPLODED)) ) {
2379
2380                                 SDL_assert( objp->type == OBJ_SHIP );
2381                                 aip = &Ai_info[Ships[Objects[sop->objnum].instance].ai_index];
2382                                 pship_index = objp->instance;
2383
2384                                 // we must check all goals for this support ship -- not just the first one
2385                                 for ( i = 0; i < MAX_AI_GOALS; i++ ) {
2386
2387                                         // we can use == in the next statement (and should) since a ship will only ever be
2388                                         // following one order at a time.
2389                                         if ( aip->goals[i].ai_mode == AI_GOAL_REARM_REPAIR ) {
2390                                                 SDL_assert( aip->goals[i].ship_name );
2391                                                 sindex = ship_name_lookup( aip->goals[i].ship_name );
2392                                                 if ( sindex == pship_index )
2393                                                         return sop->objnum;
2394                                         }
2395                                 }
2396                         }
2397                 }
2398                 sop = GET_NEXT(sop);
2399         }
2400
2401         return -1;
2402 }
2403
2404 // dipaly the hud_support view popup
2405 void hud_support_view_blit()
2406 {
2407         int     show_time;
2408         char    outstr[64];
2409         
2410         if ( !Hud_support_view_active ) {
2411                 return;
2412         }
2413
2414         // don't render this gauge for multiplayer observers
2415         if((Game_mode & GM_MULTIPLAYER) && ((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER))){
2416                 return;
2417         }
2418
2419         // If we haven't determined yet who the rearm ship is, try to!
2420         if (Hud_support_objnum == -1) {
2421                 Hud_support_objnum = hud_support_find_closest( OBJ_INDEX(Player_obj) );
2422                 if ( Hud_support_objnum >= 0 ) {
2423                         Hud_support_obj_sig = Objects[Hud_support_objnum].signature;
2424                         Hud_support_target_sig = Player_obj->signature;
2425                 }
2426         } else {
2427                 // check to see if support ship is still alive
2428                 if ( (Objects[Hud_support_objnum].signature != Hud_support_obj_sig) || (Hud_support_target_sig != Player_obj->signature) ) {
2429                         hud_support_view_stop(1);
2430                         return;
2431                 }
2432         }
2433
2434         // set hud color
2435 #ifdef FS2_DEMO
2436         hud_set_gauge_color(HUD_RADAR);
2437 #else
2438         hud_set_gauge_color(HUD_SUPPORT_GAUGE);
2439 #endif
2440
2441         GR_AABITMAP(Support_view_gauge.first_frame, Support_view_coords[gr_screen.res][0], Support_view_coords[gr_screen.res][1]);      
2442
2443         gr_string(Support_text_coords[gr_screen.res][0], Support_text_coords[gr_screen.res][1], XSTR( "support", 224));
2444
2445         if ( Hud_support_view_fade > 1 ) {
2446                 if ( !timestamp_elapsed(Hud_support_view_fade) ) {
2447                         if ( Hud_support_view_abort){
2448                                 gr_string(0x8000, Support_text_val_coords[gr_screen.res][1], XSTR( "aborted", 225));
2449                         } else {
2450                                 gr_string(0x8000, Support_text_val_coords[gr_screen.res][1], XSTR( "complete", 1407));
2451                         }
2452                         return;
2453                 } else {
2454                         Hud_support_view_abort = 0;
2455                         Hud_support_view_active = 0;
2456                         Hud_support_view_fade = 1;
2457                         Hud_support_objnum = -1;
2458                         return;
2459                 }
2460         }
2461
2462         show_time = 0;
2463         if ( Player_ai->ai_flags & AIF_BEING_REPAIRED ) {
2464                 SDL_assert(Ship_info[Player_ship->ship_info_index].initial_hull_strength > 0);
2465                 if (  (ship_get_subsystem_strength(Player_ship, SUBSYSTEM_ENGINE) < 1.0 ) ||
2466                                 (ship_get_subsystem_strength(Player_ship, SUBSYSTEM_SENSORS) < 1.0 ) ||
2467                                 (ship_get_subsystem_strength(Player_ship, SUBSYSTEM_WEAPONS) < 1.0 ) ||
2468                                 (ship_get_subsystem_strength(Player_ship, SUBSYSTEM_COMMUNICATION) < 1.0 ) ) {
2469                         SDL_strlcpy(outstr, XSTR( "repairing", 227), SDL_arraysize(outstr));
2470                 } else {
2471                         SDL_strlcpy(outstr, XSTR( "rearming", 228), SDL_arraysize(outstr));
2472                 }
2473                 gr_string(0x8000, Support_text_val_coords[gr_screen.res][1], outstr);
2474         } else if (Player_ai->ai_flags & AIF_REPAIR_OBSTRUCTED) {
2475                 SDL_strlcpy(outstr, XSTR( "obstructed", 229), SDL_arraysize(outstr));
2476                 gr_string(0x8000, Support_text_val_coords[gr_screen.res][1], outstr);
2477         } else {
2478                 if ( Hud_support_objnum == -1 ) {
2479                         SDL_strlcpy(outstr, XSTR( "warping in", 230), SDL_arraysize(outstr));
2480                         gr_string(0x8000, Support_text_val_coords[gr_screen.res][1], outstr);
2481                 } else {
2482                         ai_info *aip;
2483
2484                         // display "busy" when support ship isn't actually enroute to me
2485                         aip = &Ai_info[Ships[Objects[Hud_support_objnum].instance].ai_index];
2486                         if ( aip->goal_objnum != OBJ_INDEX(Player_obj) ) {
2487                                 SDL_strlcpy(outstr, XSTR( "busy", 231), SDL_arraysize(outstr));
2488                                 show_time = 0;
2489
2490                         } else {
2491                                 SDL_strlcpy(outstr, XSTR( "dock in:", 232), SDL_arraysize(outstr));
2492                                 show_time = 1;
2493                         }               
2494
2495                         if (!show_time) {
2496                                 gr_string(Support_text_dock_coords[gr_screen.res][0], Support_text_val_coords[gr_screen.res][1], outstr);
2497                         } else {                        
2498                                 gr_string(Support_text_dock_coords[gr_screen.res][0], Support_text_val_coords[gr_screen.res][1], outstr);
2499                         }
2500                 }
2501         }
2502
2503         if ( show_time ) {
2504                 int seconds, minutes;
2505
2506                 SDL_assert( Hud_support_objnum != -1 );
2507
2508                 // ensure support ship is still alive
2509                 if ( (Objects[Hud_support_objnum].signature != Hud_support_obj_sig) || (Hud_support_target_sig != Player_obj->signature) ) {
2510                         hud_support_view_stop(1);
2511                         seconds = 0;
2512                 } else {
2513                         seconds = hud_support_get_dock_time( Hud_support_objnum );
2514                 }
2515
2516                 if ( seconds >= 0 ) {
2517                         minutes = seconds/60;
2518                         seconds = seconds%60;
2519                         if ( minutes > 99 ) {
2520                                 minutes = 99;
2521                                 seconds = 99;
2522                         }
2523                 } else {
2524                         minutes = 99;
2525                         seconds = 99;
2526                 }
2527                 gr_printf(Support_text_dock_val_coords[gr_screen.res][0], Support_text_val_coords[gr_screen.res][1], NOX("%02d:%02d"), minutes, seconds);
2528         }
2529 }
2530
2531 // Set the current color to the default HUD color (with default alpha)
2532 void hud_set_default_color()
2533 {
2534         SDL_assert(HUD_color_alpha >= 0 && HUD_color_alpha < HUD_NUM_COLOR_LEVELS);
2535         gr_set_color_fast(&HUD_color_defaults[HUD_color_alpha]);
2536 }
2537
2538 // Set the current color to a bright HUD color (ie high alpha)
2539 void hud_set_bright_color()
2540 {
2541         int alpha_color;
2542         alpha_color = SDL_min(HUD_COLOR_ALPHA_MAX,HUD_color_alpha+HUD_BRIGHT_DELTA);
2543         gr_set_color_fast(&HUD_color_defaults[alpha_color]);
2544 }
2545
2546 // Set the current color to a dim HUD color (ie low alpha)
2547 void hud_set_dim_color()
2548 {
2549         if ( HUD_color_alpha > 2 ) {
2550                 gr_set_color_fast(&HUD_color_defaults[2]);
2551         }
2552 }
2553
2554 // hud_set_iff_color() will set the color to the IFF color based on the team
2555 //
2556 // input:       team                    =>              team to base color on
2557 //                              is_bright       =>              default parameter (value 0) which uses bright version of IFF color
2558 void hud_set_iff_color(object *objp, int is_bright)
2559 {
2560         // AL 12-26-97: it seems IFF color needs to be set relative to the player team.  If
2561         //                                              the team in question is the same as the player, then it should be 
2562         //                                              drawn friendly.  If the team is different than the players, then draw the
2563         //                                              appropriate IFF.          
2564         int team;
2565         team = obj_team(objp);
2566
2567         if ( ship_is_tagged(objp) ) {
2568                 gr_set_color_fast(&IFF_colors[IFF_COLOR_TAGGED][is_bright]);
2569         } else if ( (team == Player_ship->team) && (Player_ship->team != TEAM_TRAITOR) ) {
2570                 gr_set_color_fast(&IFF_colors[IFF_COLOR_FRIENDLY][is_bright]);
2571         } else {
2572                 switch (team) {
2573                 case TEAM_NEUTRAL:
2574                         gr_set_color_fast(&IFF_colors[IFF_COLOR_NEUTRAL][is_bright]);
2575                         break;
2576                 case TEAM_UNKNOWN:
2577                         gr_set_color_fast(&IFF_colors[IFF_COLOR_UNKNOWN][is_bright]);
2578                         break;
2579                 case TEAM_HOSTILE:
2580                 case TEAM_FRIENDLY:
2581                 case TEAM_TRAITOR:
2582                         gr_set_color_fast(&IFF_colors[IFF_COLOR_HOSTILE][is_bright]);
2583                         break;
2584                 default:
2585                         Int3();
2586                         gr_set_color_fast(&IFF_colors[IFF_COLOR_UNKNOWN][is_bright]);
2587                         break;
2588                 }
2589         }
2590 }
2591
2592 // Determine if ship team should be ignored, based on
2593 // team filter
2594 // input:       team_filter     =>      team mask used to select friendly or hostile ships
2595 //                              ship_team       =>      team of the ship in question
2596 // exit:                1                               =>      ship_team matches filter from player perspective
2597 //                              0                               =>      ship_team does match team filter
2598 int hud_team_matches_filter(int team_filter, int ship_team)
2599 {
2600         return team_filter & ship_team;
2601 }
2602
2603
2604 // reset gauge flashing data
2605 void hud_gauge_flash_init()
2606 {
2607         int i;
2608         for ( i=0; i<NUM_HUD_GAUGES; i++ ) {
2609                 HUD_gauge_flash_duration[i]=timestamp(0);
2610                 HUD_gauge_flash_next[i]=timestamp(0);
2611         }
2612         HUD_gauge_bright=0;
2613 }
2614
2615 #define NUM_VM_OTHER_SHIP_GAUGES 5
2616 static int Vm_other_ship_gauges[NUM_VM_OTHER_SHIP_GAUGES] = 
2617 {
2618         HUD_CENTER_RETICLE,
2619         HUD_TARGET_MONITOR,
2620         HUD_TARGET_MONITOR_EXTRA_DATA,
2621         HUD_MESSAGE_LINES,
2622         HUD_TALKING_HEAD
2623 };
2624
2625 // determine if the specified HUD gauge should be displayed
2626 int hud_gauge_active(int gauge_index)
2627 {
2628         SDL_assert(gauge_index >=0 && gauge_index < NUM_HUD_GAUGES);
2629
2630         // AL: Special code: Only show two gauges when not viewing from own ship
2631         if ( Viewer_mode & VM_OTHER_SHIP ) {
2632                 for ( int i = 0; i < NUM_VM_OTHER_SHIP_GAUGES; i++ ) {
2633                         if ( gauge_index == Vm_other_ship_gauges[i] ) {
2634                                 return 1;
2635                         }
2636                 }
2637                 return 0;
2638         }
2639
2640         return hud_config_show_flag_is_set(gauge_index);
2641 }
2642
2643 // determine if gauge is in pop-up mode or not
2644 int hud_gauge_is_popup(int gauge_index)
2645 {
2646         SDL_assert(gauge_index >=0 && gauge_index < NUM_HUD_GAUGES);
2647         return hud_config_popup_flag_is_set(gauge_index);
2648 }
2649
2650 // determine if a popup gauge should be drawn
2651 int hud_gauge_popup_active(int gauge_index)
2652 {
2653         SDL_assert(gauge_index >=0 && gauge_index < NUM_HUD_GAUGES);
2654         if ( !hud_gauge_is_popup(gauge_index) ) {
2655                 return 0;
2656         }
2657
2658         if ( !timestamp_elapsed(HUD_popup_timers[gauge_index]) ) {
2659                 return 1;
2660         } else {
2661                 return 0;
2662         }
2663 }
2664
2665 // start a gauge to popup
2666 void hud_gauge_popup_start(int gauge_index, int time) 
2667 {
2668         SDL_assert(gauge_index >=0 && gauge_index < NUM_HUD_GAUGES);
2669         if ( !hud_gauge_is_popup(gauge_index) ) {
2670                 return;
2671         }
2672
2673         HUD_popup_timers[gauge_index] = timestamp(time);
2674
2675 }
2676
2677 // call HUD function to flash gauge
2678 void hud_gauge_start_flash(int gauge_index)
2679 {
2680         SDL_assert(gauge_index >=0 && gauge_index < NUM_HUD_GAUGES);
2681         HUD_gauge_flash_duration[gauge_index] = timestamp(HUD_GAUGE_FLASH_DURATION);
2682         HUD_gauge_flash_next[gauge_index] = 1;
2683 }
2684
2685 // Set the HUD color for the gauge, based on whether it is flashing or not
2686 void hud_set_gauge_color(int gauge_index, int bright_index)
2687 {
2688         color use_color;
2689         int flash_status = hud_gauge_maybe_flash(gauge_index);
2690         use_color = HUD_config.clr[gauge_index];
2691         int alpha;
2692
2693         // if we're drawing it as bright
2694         if(bright_index != HUD_C_NONE){
2695                 switch(bright_index){
2696                 case HUD_C_DIM:
2697                         alpha = HUD_contrast ? HUD_NEW_ALPHA_DIM_HI : HUD_NEW_ALPHA_DIM;
2698                         gr_init_alphacolor(&use_color, use_color.red, use_color.green, use_color.blue, alpha, AC_TYPE_HUD);
2699                         break;
2700
2701                 case HUD_C_NORMAL:
2702                         alpha = HUD_contrast ? HUD_NEW_ALPHA_NORMAL_HI : HUD_NEW_ALPHA_NORMAL;
2703                         gr_init_alphacolor(&use_color, use_color.red, use_color.green, use_color.blue, alpha, AC_TYPE_HUD);
2704                         break;
2705
2706                 case HUD_C_BRIGHT:
2707                         alpha = HUD_contrast ? HUD_NEW_ALPHA_BRIGHT_HI : HUD_NEW_ALPHA_BRIGHT;
2708                         gr_init_alphacolor(&use_color, use_color.red, use_color.green, use_color.blue, alpha, AC_TYPE_HUD);
2709                         break;
2710
2711                 // intensity
2712                 default: 
2713                         SDL_assert((bright_index >= 0) && (bright_index < HUD_NUM_COLOR_LEVELS));
2714                         if(bright_index < 0){
2715                                 bright_index = 0;
2716                         }
2717                         if(bright_index >= HUD_NUM_COLOR_LEVELS){
2718                                 bright_index = HUD_NUM_COLOR_LEVELS - 1;
2719                         }
2720
2721                         // alpha = 255 - (255 / (bright_index + 1));
2722                         // alpha = (int)((float)alpha * 1.5f);
2723                         int level = 255 / (HUD_NUM_COLOR_LEVELS);
2724                         alpha = level * bright_index;
2725                         if(alpha > 255){
2726                                 alpha = 255;
2727                         }
2728                         if(alpha < 0){
2729                                 alpha = 0;
2730                         }
2731                         gr_init_alphacolor(&use_color, use_color.red, use_color.green, use_color.blue, alpha, AC_TYPE_HUD);
2732                         break;
2733                 }
2734         } else {
2735                 switch(flash_status) {
2736                 case 0:
2737                         alpha = HUD_contrast ? HUD_NEW_ALPHA_DIM_HI : HUD_NEW_ALPHA_DIM;
2738                         gr_init_alphacolor(&use_color, use_color.red, use_color.green, use_color.blue, alpha, AC_TYPE_HUD);
2739                         break;
2740                 case 1:                 
2741                         alpha = HUD_contrast ? HUD_NEW_ALPHA_BRIGHT_HI : HUD_NEW_ALPHA_BRIGHT;
2742                         gr_init_alphacolor(&use_color, use_color.red, use_color.green, use_color.blue, alpha, AC_TYPE_HUD);
2743                         break;
2744                 default:                        
2745                         alpha = HUD_contrast ? HUD_NEW_ALPHA_NORMAL_HI : HUD_NEW_ALPHA_NORMAL;  
2746                         gr_init_alphacolor(&use_color, use_color.red, use_color.green, use_color.blue, alpha, AC_TYPE_HUD);
2747                         break;
2748                 }
2749         }
2750
2751         gr_set_color_fast(&use_color);  
2752 }
2753
2754 // set the color for a gauge that may be flashing
2755 // exit:        -1      =>      gauge is not flashing
2756 //                      0       =>      gauge is flashing, draw dim
2757 //                      1       =>      gauge is flashing, draw bright
2758 int hud_gauge_maybe_flash(int gauge_index)
2759 {
2760         SDL_assert(gauge_index >=0 && gauge_index < NUM_HUD_GAUGES);
2761         int flash_status=-1;
2762         if ( !timestamp_elapsed(HUD_gauge_flash_duration[gauge_index]) ) {
2763                 if ( timestamp_elapsed(HUD_gauge_flash_next[gauge_index]) ) {
2764                         HUD_gauge_flash_next[gauge_index] = timestamp(HUD_GAUGE_FLASH_INTERVAL);
2765                         HUD_gauge_bright ^= (1<<gauge_index);   // toggle between default and bright frames
2766                 }
2767
2768                 if ( HUD_gauge_bright & (1<<gauge_index) ) {
2769                         flash_status=1;
2770                 } else {
2771                         flash_status=0;
2772                 }
2773         }
2774         return flash_status;
2775 }
2776
2777 // Init the objective message display data
2778 void hud_objective_message_init()
2779 {
2780         // ensure the talking head border is loaded
2781         if ( !Objective_display_gauge_inited ) {
2782                 Objective_display_gauge.first_frame = bm_load_animation(Objective_fname[gr_screen.res], &Objective_display_gauge.num_frames);
2783                 if ( Objective_display_gauge.first_frame == -1 ) {
2784                         Warning(LOCATION, "Could not load in ani: Objective_fname[gr_screen.res]\n");
2785                 }
2786                 Objective_display_gauge_inited = 1;
2787         }
2788
2789         Objective_display.display_timer=timestamp(0);
2790 }
2791
2792 // Display objective status on the HUD
2793 // input:       type                    =>      type of goal, one of:   PRIMARY_GOAL
2794 //                                                                                                                                      SECONDARY_GOAL
2795 //                                                                                                                                      BONUS_GOAL
2796 //
2797 //                              status          => status of goal, one of:      GOAL_FAILED
2798 //                                                                                                                                      GOAL_COMPLETE
2799 //                                                                                                                                      GOAL_INCOMPLETE
2800 //
2801 void hud_add_objective_messsage(int type, int status)
2802 {
2803         Objective_display.display_timer=timestamp(7000);
2804         Objective_display.goal_type=type;
2805         Objective_display.goal_status=status;
2806
2807         // if this is a multiplayer tvt game
2808         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM) && (Net_player != NULL)){
2809                 mission_goal_fetch_num_resolved(type, &Objective_display.goal_nresolved, &Objective_display.goal_ntotal, Net_player->p_info.team);
2810         } else {
2811                 mission_goal_fetch_num_resolved(type, &Objective_display.goal_nresolved, &Objective_display.goal_ntotal);
2812         }
2813
2814         // TODO: play a sound?
2815 }
2816
2817 // maybe display the 'subspace drive engaged' message
2818 void hud_maybe_display_subspace_notify()
2819 {
2820         int warp_aborted = 0;
2821         // maybe make gauge active
2822         if ( (Player->control_mode == PCM_WARPOUT_STAGE1) || (Player->control_mode == PCM_WARPOUT_STAGE2) || (Player->control_mode == PCM_WARPOUT_STAGE3) ) {
2823                 if (!hud_subspace_notify_active()) {
2824                         // keep sound from being played 1e06 times
2825                         hud_start_subspace_notify();
2826                 }
2827         } else {
2828                 if ( !timestamp_elapsed(HUD_abort_subspace_timer) ) {
2829                         warp_aborted = 1;
2830                 } else {
2831                         hud_stop_subspace_notify();
2832                 }
2833         }
2834
2835         if ( !hud_subspace_notify_active() ) {
2836                 return;
2837         }
2838
2839         if ( Objective_display_gauge.first_frame < 0 ) {
2840                 return;
2841         }
2842
2843         // blit the background  
2844         hud_set_gauge_color(HUD_OBJECTIVES_NOTIFY_GAUGE);
2845         GR_AABITMAP(Objective_display_gauge.first_frame, Objective_display_coords[gr_screen.res][0], Objective_display_coords[gr_screen.res][1]);       
2846
2847         hud_targetbox_start_flash(TBOX_FLASH_OBJECTIVE);
2848         if(hud_targetbox_maybe_flash(TBOX_FLASH_OBJECTIVE)){
2849                 hud_set_gauge_color(HUD_OBJECTIVES_NOTIFY_GAUGE, HUD_C_BRIGHT);
2850         } else {
2851                 hud_set_gauge_color(HUD_OBJECTIVES_NOTIFY_GAUGE);
2852         }
2853
2854
2855         gr_string(0x8000, Subspace_text_coords[gr_screen.res][1],XSTR( "subspace drive", 233));
2856         if ( warp_aborted ) {
2857                 gr_string(0x8000, Subspace_text_val_coords[gr_screen.res][1],XSTR( "aborted", 225));
2858         } else {
2859                 gr_string(0x8000, Subspace_text_val_coords[gr_screen.res][1],XSTR( "engaged", 234));
2860         }
2861 }
2862
2863 // maybe display the 'Downloading new orders' message
2864 void hud_maybe_display_red_alert()
2865 {
2866         if ( !red_alert_check_status() ) {
2867                 return;
2868         }
2869
2870         if ( Objective_display_gauge.first_frame < 0 ) {
2871                 return;
2872         }
2873
2874         if ( hud_subspace_notify_active() ) {
2875                 return;
2876         }
2877
2878         if ( hud_objective_notify_active() ) {
2879                 return;
2880         }
2881
2882         // blit the background
2883         gr_set_color_fast(&Color_red);          // color box red, cuz its an emergency for cryin out loud
2884
2885         GR_AABITMAP(Objective_display_gauge.first_frame, Objective_display_coords[gr_screen.res][0], Objective_display_coords[gr_screen.res][1]);       
2886
2887         hud_targetbox_start_flash(TBOX_FLASH_OBJECTIVE);
2888         if(hud_targetbox_maybe_flash(TBOX_FLASH_OBJECTIVE)) {
2889                 gr_set_color_fast(&Color_red);
2890         } else {
2891                 gr_set_color_fast(&Color_bright_red);
2892         }
2893
2894         gr_string(0x8000, Red_text_coords[gr_screen.res][1], XSTR( "downloading new", 235));
2895         gr_string(0x8000, Red_text_val_coords[gr_screen.res][1], XSTR( "orders...", 236));
2896
2897         // TODO: play a sound?
2898 }
2899
2900 // Maybe show an objective status update on the HUD
2901 void hud_maybe_display_objective_message()
2902 {
2903         char buf[128];
2904
2905         if ( timestamp_elapsed(Objective_display.display_timer) ) {
2906                 hud_stop_objective_notify();
2907                 return;
2908         }
2909
2910         if ( Objective_display_gauge.first_frame < 0 ) {
2911                 return;
2912         }
2913
2914         if ( hud_subspace_notify_active() ) {
2915                 return;
2916         }
2917
2918         if (!hud_objective_notify_active()) {
2919                 hud_start_objective_notify();
2920         }
2921         
2922         // blit the background
2923         hud_set_gauge_color(HUD_OBJECTIVES_NOTIFY_GAUGE);
2924         GR_AABITMAP(Objective_display_gauge.first_frame, Objective_display_coords[gr_screen.res][0], Objective_display_coords[gr_screen.res][1]);       
2925
2926         hud_targetbox_start_flash(TBOX_FLASH_OBJECTIVE);
2927         if(hud_targetbox_maybe_flash(TBOX_FLASH_OBJECTIVE)){
2928                 hud_set_gauge_color(HUD_OBJECTIVES_NOTIFY_GAUGE, HUD_C_BRIGHT);
2929         } else {
2930                 hud_set_gauge_color(HUD_OBJECTIVES_NOTIFY_GAUGE);
2931         }
2932
2933         // draw the correct goal type
2934         switch(Objective_display.goal_type) {
2935         case PRIMARY_GOAL:
2936                 gr_string(0x8000, Objective_text_coords[gr_screen.res][1],XSTR( "primary objective", 237));
2937                 break;
2938         case SECONDARY_GOAL:
2939                 gr_string(0x8000, Objective_text_coords[gr_screen.res][1],XSTR( "secondary objective", 238));
2940                 break;
2941         case BONUS_GOAL:
2942                 gr_string(0x8000, Objective_text_coords[gr_screen.res][1],XSTR( "bonus objective", 239));
2943                 break;
2944         }
2945
2946         // show the status
2947         switch(Objective_display.goal_type) {
2948         case PRIMARY_GOAL:
2949         case SECONDARY_GOAL:
2950                 switch(Objective_display.goal_status) {
2951                 case GOAL_FAILED:
2952                         SDL_snprintf(buf, SDL_arraysize(buf), XSTR( "failed (%d/%d)", 240), Objective_display.goal_nresolved, Objective_display.goal_ntotal);
2953                         gr_string(0x8000, Objective_text_val_coords[gr_screen.res][1], buf);
2954                         break;
2955                 default:
2956                         SDL_snprintf(buf, SDL_arraysize(buf), XSTR( "complete (%d/%d)", 241), Objective_display.goal_nresolved, Objective_display.goal_ntotal);
2957                         gr_string(0x8000, Objective_text_val_coords[gr_screen.res][1], buf);
2958                         break;
2959                 }               
2960                 break;
2961         case BONUS_GOAL:
2962                 switch(Objective_display.goal_status) {
2963                 case GOAL_FAILED:
2964                         gr_string(0x8000, Objective_text_val_coords[gr_screen.res][1], XSTR( "failed", 242));
2965                         break;
2966                 default:
2967                         gr_string(0x8000, Objective_text_val_coords[gr_screen.res][1], XSTR( "complete", 226));
2968                         break;
2969                 }               
2970                 break;
2971         }
2972 }
2973
2974 // return wing slot (0->3) based on name of ship.  Assumes ship is from Alpha,Beta, or 
2975 // Gamma wings
2976 int hud_wing_slot_from_name(const char *name)
2977 {
2978         int     rval;
2979         char    num[2];
2980
2981         num[0]=name[strlen(name)-1];
2982         num[1]=0;
2983
2984         rval = num[0] - '1';
2985         SDL_assert(rval >= 0 && rval < 4);
2986         return rval;
2987 }
2988
2989 // return index in starting wings (0->11) for specified ship.
2990 int hud_wing_index_from_ship(int shipnum)
2991 {
2992         int     i;
2993         ship    *shipp;
2994
2995         shipp = &Ships[shipnum];
2996
2997         int wing_slot = 0;
2998
2999         for (i=0; i<3; i++) {
3000                 if ( Starting_wings[i] < 0 ) {
3001                         continue;
3002                 }
3003
3004                 if (shipp->wingnum == Starting_wings[i]) {
3005                         break;
3006                 }
3007         }
3008
3009         if ( i==3 ) {
3010                 Int3();
3011         }
3012
3013         wing_slot = hud_wing_slot_from_name(shipp->ship_name);
3014         return (i*4+wing_slot);
3015 }
3016
3017 void hud_show_voice_status()
3018 {
3019         char play_callsign[CALLSIGN_LEN+5];
3020         
3021         // if we are currently playing a rtvoice sound stream from another player back
3022         memset(play_callsign,0,CALLSIGN_LEN+5);
3023         switch(multi_voice_status()){
3024         // the player has been denied the voice token
3025         case MULTI_VOICE_STATUS_DENIED:
3026                 // show a red indicator or something
3027                 gr_string(Voice_coords[gr_screen.res][0], Voice_coords[gr_screen.res][1], XSTR( "[voice denied]", 243));
3028                 break;
3029
3030         // the player is currently recording
3031         case MULTI_VOICE_STATUS_RECORDING:
3032                 gr_string(Voice_coords[gr_screen.res][0], Voice_coords[gr_screen.res][1], XSTR( "[recording voice]", 244));
3033                 break;
3034                 
3035         // the player is current playing back voice from someone
3036         case MULTI_VOICE_STATUS_PLAYING:
3037                 gr_string(Voice_coords[gr_screen.res][0], Voice_coords[gr_screen.res][1], XSTR( "[playing voice]", 245));
3038                 break;
3039
3040         // nothing voice related is happening on my machine
3041         case MULTI_VOICE_STATUS_IDLE:
3042                 // probably shouldn't be displaying anything
3043                 break;
3044         }       
3045 }
3046
3047 void hud_subspace_notify_abort()
3048 {
3049         HUD_abort_subspace_timer = timestamp(1500);
3050 }
3051
3052 void hud_stop_subspace_notify()
3053 {
3054         Subspace_notify_active=0;
3055 }
3056
3057 void hud_start_subspace_notify()
3058 {
3059
3060         Subspace_notify_active=1;
3061 }
3062
3063 int hud_subspace_notify_active()
3064 {
3065         return Subspace_notify_active;
3066 }
3067
3068 void hud_stop_objective_notify()
3069 {
3070         Objective_notify_active = 0;
3071 }
3072
3073 void hud_start_objective_notify()
3074 {
3075         snd_play(&(Snds[SND_DIRECTIVE_COMPLETE]));
3076         Objective_notify_active = 1;
3077 }
3078
3079 int hud_objective_notify_active()
3080 {
3081         return Objective_notify_active;
3082 }
3083
3084 // render multiplayer text message currently being entered if any
3085 void hud_maybe_render_multi_text()
3086 {
3087         char txt[MULTI_MSG_MAX_TEXT_LEN+20];
3088
3089         // clear the text
3090         memset(txt,0,MULTI_MSG_MAX_TEXT_LEN+1);
3091
3092         // if there is valid multiplayer message text to be displayed
3093         if(multi_msg_message_text(txt, SDL_arraysize(txt))){
3094                 gr_set_color_fast(&Color_normal);
3095                 gr_string(Multi_msg_coords[gr_screen.res][0], Multi_msg_coords[gr_screen.res][1], txt);
3096         }
3097 }
3098
3099 // cut any text off after (and including) '#' char
3100 void hud_end_string_at_first_hash_symbol(char *src)
3101 {
3102         char *pointer_to_last_char;
3103
3104         pointer_to_last_char = strstr(src, NOX("#"));
3105
3106         if ( pointer_to_last_char ) {
3107                 *pointer_to_last_char = 0;
3108         }
3109 }
3110
3111 // set the offset values for this render frame
3112 void HUD_set_offsets(object *viewer_obj, int wiggedy_wack)
3113 {
3114         if ( (viewer_obj == Player_obj) && wiggedy_wack ){              
3115                 vector tmp;
3116                 vertex pt;
3117                 ubyte flags;            
3118
3119                 HUD_offset_x = 0.0f;
3120                 HUD_offset_y = 0.0f;
3121
3122                 vm_vec_scale_add( &tmp, &Viewer_obj->pos, &Viewer_obj->orient.v.fvec, 100.0f );
3123                 
3124                 flags = g3_rotate_vertex(&pt,&tmp);
3125
3126                 if (flags == 0) {
3127
3128                         g3_project_vertex(&pt);
3129
3130                         if (!(pt.flags & PF_OVERFLOW))  {
3131                                 HUD_offset_x -= 0.45f * (i2fl(gr_screen.clip_width)*0.5f - pt.sx);
3132                                 HUD_offset_y -= 0.45f * (i2fl(gr_screen.clip_height)*0.5f - pt.sy);
3133                         }
3134                 }
3135
3136                 if ( HUD_offset_x > 100.0f )    {
3137                         HUD_offset_x = 100.0f;
3138                 } else if ( HUD_offset_x < -100.0f )    {
3139                         HUD_offset_x += 100.0f;
3140                 }
3141
3142                 if ( HUD_offset_y > 100.0f )    {
3143                         HUD_offset_y = 100.0f;
3144                 } else if ( HUD_offset_y < -100.0f )    {
3145                         HUD_offset_y += 100.0f;
3146                 }
3147
3148         } else {
3149                 HUD_offset_x = 0.0f;
3150                 HUD_offset_y = 0.0f;
3151         }
3152 }
3153
3154 // Basically like gr_reset_clip only it accounts for hud jittering
3155 void HUD_reset_clip()
3156 {
3157         int hx = fl2i(HUD_offset_x);
3158         int hy = fl2i(HUD_offset_y);
3159
3160         gr_set_clip(hx, hy, gr_screen.max_w, gr_screen.max_h );
3161 }
3162
3163 // Basically like gr_set_clip only it accounts for hud jittering
3164 void HUD_set_clip(int x, int y, int w, int h)
3165 {
3166         int hx = fl2i(HUD_offset_x);
3167         int hy = fl2i(HUD_offset_y);
3168
3169         gr_set_clip(hx+x, hy+y, w, h );
3170 }
3171
3172 void hud_toggle_contrast()
3173 {
3174         HUD_contrast = !HUD_contrast;
3175 }
3176
3177 void hud_set_contrast(int high)
3178 {
3179         HUD_contrast = high;
3180 }
3181
3182 // Paging functions for the rest of the hud code
3183 extern void hudwingmanstatus_page_in();
3184 extern void hudescort_page_in();
3185 extern void hudets_page_in();
3186 extern void hudlock_page_in();
3187 extern void hudreticle_page_in();
3188 extern void hudshield_page_in();
3189 extern void hudsquadmsg_page_in();
3190 extern void hudtarget_page_in();
3191 extern void hudtargetbox_page_in();
3192
3193 // Page in all hud bitmaps
3194 void hud_page_in()
3195 {
3196         int i;
3197
3198         bm_page_in_aabitmap( Kills_gauge.first_frame, Kills_gauge.num_frames );
3199         bm_page_in_aabitmap( Head_frame_gauge.first_frame, Head_frame_gauge.num_frames );
3200         bm_page_in_aabitmap( Mission_time_gauge.first_frame, Mission_time_gauge.num_frames );
3201         for ( i = 0; i < NUM_DAMAGE_GAUGES; i++ ) {
3202                 bm_page_in_aabitmap( Damage_gauges[i].first_frame, Damage_gauges[i].num_frames);
3203         }
3204
3205         bm_page_in_aabitmap( Netlag_icon.first_frame, Netlag_icon.num_frames);                  
3206         bm_page_in_aabitmap( Support_view_gauge.first_frame, Support_view_gauge.num_frames);
3207         bm_page_in_aabitmap( Objective_display_gauge.first_frame, Objective_display_gauge.num_frames);          
3208
3209         // Paging functions for the rest of the hud code
3210         hudwingmanstatus_page_in();
3211         hudescort_page_in();
3212         hudets_page_in();
3213         hudlock_page_in();
3214         hudreticle_page_in();
3215         hudshield_page_in();
3216         hudsquadmsg_page_in();
3217         hudtarget_page_in();
3218         hudtargetbox_page_in();
3219 }
3220