]> icculus.org git repositories - taylor/freespace2.git/blob - src/hud/hudescort.cpp
disable popups for now
[taylor/freespace2.git] / src / hud / hudescort.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/HUDescort.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C module for managing and displaying ships that are in an escort
16  *
17  * $Log$
18  * Revision 1.3  2002/06/09 04:41:21  relnev
19  * added copyright header
20  *
21  * Revision 1.2  2002/05/07 03:16:45  theoddone33
22  * The Great Newline Fix
23  *
24  * Revision 1.1.1.1  2002/05/03 03:28:09  root
25  * Initial import.
26  *
27  * 
28  * 22    8/04/99 2:24a Dave
29  * Fixed escort gauge ordering for dogfight.
30  * 
31  * 21    7/30/99 7:01p Dave
32  * Dogfight escort gauge. Fixed up laser rendering in Glide.
33  * 
34  * 20    7/29/99 1:57p Jefff
35  * Fixed location of "D" for disabled ships in hi-res
36  * 
37  * 19    7/22/99 7:49p Dave
38  * Show enemy ships on the escort list in red.
39  * 
40  * 18    6/23/99 10:13p Andsager
41  * Fix Baranec hud escort default color bug!
42  * 
43  * 17    6/10/99 3:43p Dave
44  * Do a better job of syncing text colors to HUD gauges.
45  * 
46  * 16    5/24/99 11:28a Dave
47  * Sexpression for adding/removing ships from the hud escort list.
48  * 
49  * 15    3/30/99 5:40p Dave
50  * Fixed reinforcements for TvT in multiplayer.
51  * 
52  * 14    3/19/99 9:51a Dave
53  * Checkin to repair massive source safe crash. Also added support for
54  * pof-style nebulae, and some new weapons code.
55  * 
56  * 14    3/12/99 4:24p Andsager
57  * Fix bug where two or more ships are culled from escort list same frame
58  * 
59  * 13    3/04/99 9:22a Andsager
60  * Make escort list work with ship-is-visible.  When not visible, dump,
61  * when becoming visible, maybe add.
62  * 
63  * 12    3/02/99 12:27p Andsager
64  * Fixed bug in hud_add_ship_to_escort -- multiple entries and
65  * uninitialized entries.
66  * 
67  * 11    3/02/99 11:45a Anoop
68  * put in assert for escort list
69  * 
70  * 10    3/01/99 12:00p Andsager
71  * Fix escort priority to look at newly added ships.
72  * 
73  * 9     2/03/99 6:13p Andsager
74  * Added priorities to escort list.  Folded escort hit info into
75  * escort_info struct.
76  * 
77  * 8     2/01/99 9:47a Jasen
78  * Tweaked coords for the monitoring window in hi res. 
79  * 
80  * 7     1/30/99 7:48p Jasen
81  * 
82  * 6     1/07/99 9:07a Jasen
83  * HUD coords
84  * 
85  * 5     12/28/98 3:17p Dave
86  * Support for multiple hud bitmap filenames for hi-res mode.
87  * 
88  *
89  * $NoKeywords: $
90  */
91
92
93 #include "object.h"
94 #include "ship.h"
95 #include "linklist.h"
96 #include "2d.h"
97 #include "hud.h"
98 #include "hudtarget.h"
99 #include "hudtargetbox.h"
100 #include "gamesnd.h"
101 #include "freespace.h"
102 #include "bmpman.h"
103 #include "font.h"
104 #include "hudshield.h"
105 #include "timer.h"
106 #include "hudescort.h"
107 #include "emp.h"
108 #include "alphacolors.h"
109 #include "multi.h"
110 #include "multiutil.h"
111
112 int Show_escort_view;
113
114 typedef struct escort_info
115 {
116         int                                     objnum;
117         int                                     obj_signature;  // so we are sure we have a valid objnum
118         int                                     priority;               // higher priority is higher in the list
119         short                                   np_id;                  // netplayer id (for multiplayer dogfight mode)
120         shield_hit_info hit_info;
121 } escort_info;
122
123 escort_info             Escort_ships[MAX_ESCORT_SHIPS];
124 int                             Num_escort_ships;
125
126
127 // size of complete escort list, including all those wanting to get onto list but without space
128 #define MAX_COMPLETE_ESCORT_LIST        20
129
130
131 #define NUM_ESCORT_FRAMES 3
132 hud_frames Escort_gauges[NUM_ESCORT_FRAMES];
133 int Escort_gauges_loaded = 0;
134
135 int Escort_gauge_y[MAX_ESCORT_SHIPS] = { 219, 230, 241 };
136
137
138 int Escort_gauge_text_coords[GR_NUM_RESOLUTIONS][MAX_ESCORT_SHIPS][4][2] =
139 {
140         { // GR_640
141                 {
142                         {489,219}, 
143                         {599,212}, 
144                         {604,219}, 
145                         {474,219}
146                 },
147                 {
148                         {489,230}, 
149                         {599,223},
150                         {604,230},
151                         {474,230}
152                 },
153                 {
154                         {489,241}, 
155                         {599,234}, 
156                         {604,241},
157                         {474,241} 
158                 },
159         }, 
160         { // GR_1024
161                 {
162                         {869,343},
163                         {973,338}, 
164                         {981,343}, 
165                         {854,343} 
166                 },
167                 {
168                         {869,354}, 
169                         {973,349},
170                         {981,354},
171                         {854,354}
172                 },
173                 {
174                         {869,365}, 
175                         {973,360},
176                         {981,365},
177                         {854,365}
178                 },
179         }
180 };
181
182 // escort gauge coords
183 int Escort_coords[GR_NUM_RESOLUTIONS][4][2] = {
184         { // GR_640
185                 {486, 206},
186                 {486, 219},
187                 {486, 230},
188                 {486, 241}
189         },
190         { // GR_1024
191                 {865, 330},
192                 {865, 343},
193                 {865, 354},
194                 {865, 365}
195         }
196 };
197
198 // monitoring text coords
199 int Monitoring_coords[GR_NUM_RESOLUTIONS][2] = {
200         { // GR_640
201                 489, 208
202         },
203         { // GR_1024
204                 869, 331
205         }
206 };
207         
208 const char *Escort_gauge_filenames[GR_NUM_RESOLUTIONS][MAX_ESCORT_SHIPS] = 
209 {
210 //XSTR:OFF
211         { // GR_640
212                 "escort1",
213                 "escort2",
214                 "escort3"
215         }, 
216         { // GR_1024
217                 "escort1",
218                 "escort2",
219                 "escort3"
220         }
221 //XSTR:ON
222 };
223
224 static int Last_target_index;   // index into Escort_gauges for last targeted via 'Next Escort Target' key
225
226 // data needed from HUDshield.cpp
227 extern hud_frames Shield_mini_gauge;
228
229 // called from HUD init, loads the bitmap data in once, and resets any data for each level
230 void hud_escort_init()
231 {
232         int i;
233
234         if ( !Escort_gauges_loaded ) {
235                 for ( i = 0; i < MAX_ESCORT_SHIPS; i++ ) {
236                         Escort_gauges[i].first_frame = bm_load_animation(Escort_gauge_filenames[gr_screen.res][i], &Escort_gauges[i].num_frames);
237                         if ( Escort_gauges[i].first_frame == -1 ) {
238                                 Warning(LOCATION, "Could not load in ani: %s\n", Escort_gauge_filenames[gr_screen.res][i]);
239                                 return;
240                         }
241                 }
242                 Escort_gauges_loaded = 1;
243         }
244
245         Last_target_index = -1;
246 }
247
248 // ----------------------------------------------------------------------
249 // hud_escort_clear_all()
250 //
251 void hud_escort_clear_all()
252 {
253         int i;
254
255         Num_escort_ships = 0;
256         for ( i = 0; i < MAX_ESCORT_SHIPS; i++ ) {
257                 Escort_ships[i].obj_signature = -99;
258                 Escort_ships[i].np_id = -1;
259                 shield_info_reset(&Escort_ships[i].hit_info);
260         }
261 }
262
263 // internal helper function for sort.
264 // sorts first by priority number and then alphabetically
265 int escort_compare_func(const void *e1, const void *e2)
266 {
267         escort_info *escort1, *escort2;
268         int diff;
269         int ret;
270
271         escort1 = (escort_info*) e1;
272         escort2 = (escort_info*) e2;
273
274         // multiplayer dogfight
275         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT)){
276                 int n1, n2;
277
278                 n1 = find_player_id(escort1->np_id);
279                 n2 = find_player_id(escort2->np_id);
280                 if((n1 < 0) || (n2 < 0) || (Net_players[n1].player == NULL) || (Net_players[n2].player == NULL)){
281                         ret = 0;
282                 } else {
283                         // player 1 is higher than player 2
284                         if(Net_players[n1].player->stats.m_kill_count_ok >= Net_players[n2].player->stats.m_kill_count_ok){
285                                 ret = -1;
286                         } else {
287                                 ret = 1;
288                         }
289                 }
290         } else {
291                 diff = escort2->priority - escort1->priority;
292
293                 if (diff != 0) {
294                         ret = diff;
295                 } else {
296                         char *name1, *name2;
297                         name1 = Ships[Objects[escort1->objnum].instance].ship_name;
298                         name2 = Ships[Objects[escort2->objnum].instance].ship_name;
299
300                         ret = SDL_strcasecmp(name1, name2);
301                 }
302         }
303
304         return ret;
305 }
306
307 // create complete priority sorted escort list for all active ships
308 // escorts - array of escort info
309 // num_escorts - number of escorts requests in field of active ships
310 //        This will be culled to MAX_ESCORTS, selecting the top set from escorts
311 void hud_create_complete_escort_list(escort_info *escorts, int *num_escorts)
312 {
313         ship_obj *so;
314         object *objp;   
315         int idx;
316
317         // start with none on list
318         *num_escorts = 0;
319
320         // multiplayer dogfight
321         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT)){
322                 for(idx=0; idx<MAX_PLAYERS; idx++){
323                         // break out of the loop when we have reached our max
324                         if ( *num_escorts == MAX_COMPLETE_ESCORT_LIST ) {
325                                 mprintf(("exceeded max ships in big escort list"));
326                                 break;
327                         }               
328
329                         // is this a valid player                       
330                         if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
331                                 // add the ship
332                                 escorts[*num_escorts].objnum = -1;
333                                 escorts[*num_escorts].obj_signature = -1;
334                                 escorts[*num_escorts].priority = -1;
335                                 escorts[*num_escorts].np_id = Net_players[idx].player_id;
336                                 (*num_escorts)++;
337                         }
338                 }
339         }
340         // all others 
341         else {
342                 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
343                         SDL_assert( so->objnum >= 0 && so->objnum < MAX_OBJECTS);
344                         if((so->objnum < 0) || (so->objnum >= MAX_OBJECTS)){
345                                 continue;
346                         }
347                         objp = &Objects[so->objnum];
348                         SDL_assert( objp->type == OBJ_SHIP );
349                         if(objp->type != OBJ_SHIP){
350                                 continue;
351                         }
352
353                         // break out of the loop when we have reached our max
354                         if ( *num_escorts == MAX_COMPLETE_ESCORT_LIST ) {
355                                 mprintf(("exceeded max ships in big escort list"));
356                                 break;
357                         }               
358                         
359                         // only process ships that might be on the list
360                         if ( !(Ships[objp->instance].flags & SF_ESCORT) ){
361                                 continue;
362                         }
363
364                         // only process ships that can be seen by sensors
365                         if ( (Ships[objp->instance].flags & SF_HIDDEN_FROM_SENSORS) ){
366                                 continue;
367                         }
368
369                         // don't process ships that are dying, or objects that should be dead
370                         if ( (Ships[objp->instance].flags & (SF_DYING|SF_DEPARTING)) || (objp->flags & OF_SHOULD_BE_DEAD) ){
371                                 continue;
372                         }
373
374                         // add the ship
375                         escorts[*num_escorts].objnum = so->objnum;
376                         escorts[*num_escorts].obj_signature = objp->signature;
377                         escorts[*num_escorts].priority = Ships[objp->instance].escort_priority;
378                         escorts[*num_escorts].np_id = -1;
379                         (*num_escorts)++;                       
380                 }
381         }
382 }
383
384
385 // ----------------------------------------------------------------------
386 // hud_init_escort_info()
387 //
388 // Set up the escort list
389 //
390 void hud_setup_escort_list(int level)
391 {
392         int num_escorts, num_complete_escorts;
393         escort_info complete_escorts[MAX_COMPLETE_ESCORT_LIST];
394
395         hud_escort_clear_all();
396
397         // get complete escort list
398         hud_create_complete_escort_list(complete_escorts, &num_complete_escorts);
399
400         // sort escort list by priority
401         qsort(complete_escorts, num_complete_escorts, sizeof(escort_info), escort_compare_func);
402
403         // set number in escort list
404         num_escorts = num_complete_escorts;
405         if (num_escorts > MAX_ESCORT_SHIPS) {
406                 num_escorts = MAX_ESCORT_SHIPS;
407         }
408
409         // add ships to escort list
410         for (Num_escort_ships=0; Num_escort_ships<num_escorts; Num_escort_ships++) {
411                 Escort_ships[Num_escort_ships].obj_signature = complete_escorts[Num_escort_ships].obj_signature;
412                 Escort_ships[Num_escort_ships].priority = complete_escorts[Num_escort_ships].priority;
413                 Escort_ships[Num_escort_ships].objnum = complete_escorts[Num_escort_ships].objnum;
414                 Escort_ships[Num_escort_ships].np_id = complete_escorts[Num_escort_ships].np_id;
415         }
416
417         if(level){
418                 Show_escort_view = 1;
419         }
420 }
421
422
423 // combine complete escort list with Escort_ships, keeping valid hit info
424 void merge_escort_lists(escort_info *complete_escorts, int num_complete_escorts)
425 {
426         int i, j, top_complete_escorts;
427         int valid_hit_info[MAX_ESCORT_SHIPS];
428
429         // may be > 1 ship change to list (ie, 2 or 3 culled during same frame)
430         // set Num_escort_ships and cap
431         Num_escort_ships = num_complete_escorts;
432         if (Num_escort_ships > MAX_ESCORT_SHIPS) {
433                 Num_escort_ships = MAX_ESCORT_SHIPS;
434         }
435
436         // nothing to do
437         if (Num_escort_ships == 0) {
438                 return;
439         }
440
441         // check used as a flag whether top slots in complete_escorts were copied
442         // this is important re. hit info
443         for (i=0; i<MAX_ESCORT_SHIPS; i++) {
444                 valid_hit_info[i] = 0;
445         }
446
447         // get the top slots in complete escort list that will be copied onto Escort_ships
448         top_complete_escorts = num_complete_escorts;
449         if (top_complete_escorts > MAX_ESCORT_SHIPS) {
450                 top_complete_escorts = MAX_ESCORT_SHIPS;
451         }
452
453         // copy for Escort_ships to complete_escorts to retain hit_info
454         if(!((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT))){
455                 for (i=0; i<top_complete_escorts; i++) {
456                         for (j=0; j<Num_escort_ships; j++) {
457                                 if (Escort_ships[j].obj_signature == complete_escorts[i].obj_signature) {
458                                         complete_escorts[i] = Escort_ships[j];
459                                         valid_hit_info[i] = 1;
460                                         break;
461                                 }
462                         }
463                 }
464
465                 // copy top slots to Escort_ships
466                 for (i=0; i<top_complete_escorts; i++) {
467                         Escort_ships[i] = complete_escorts[i];
468                         // check all ships are valid
469                         int objnum = Escort_ships[i].objnum;
470                         SDL_assert( objnum >=0 && objnum < MAX_OBJECTS );
471                         if((objnum < 0) || (objnum >= MAX_OBJECTS)){
472                                 continue;
473                         }
474                         if ( !valid_hit_info[i] ) {
475                                 shield_info_reset(&Escort_ships[i].hit_info);
476                         }       
477                 }
478         }
479
480         // reset Num_escort_ships
481         Num_escort_ships = top_complete_escorts;
482 }
483
484
485 // ----------------------------------------------------------------------
486 // hud_remove_ship_from_escort_index()
487 //
488 // Take a ship out of the escort list
489 void hud_remove_ship_from_escort_index(int dead_index, int objnum)
490 {
491         int                     i, count, num_complete_escorts;
492         escort_info bakup_arr[MAX_ESCORT_SHIPS], complete_escorts[MAX_COMPLETE_ESCORT_LIST];
493
494         // remove him from escort list
495         if((objnum >= 0) && (Objects[objnum].type == OBJ_SHIP) && (Objects[objnum].instance >= 0)){
496                 Ships[Objects[objnum].instance].flags &= ~SF_ESCORT;
497         }
498
499         count = 0;
500         for ( i = 0; i < Num_escort_ships; i++ ) {
501                 if ( i != dead_index ) {
502                         bakup_arr[count++] = Escort_ships[i];
503                 }
504         }
505
506         for ( i = 0; i < count; i++ ) {
507                 Escort_ships[i] = bakup_arr[i];
508         }
509
510         Num_escort_ships--;
511         SDL_assert(Num_escort_ships >= 0);      
512
513         // get complete escort list
514         hud_create_complete_escort_list(complete_escorts, &num_complete_escorts);
515
516         // sort escort list by priority
517         qsort(complete_escorts, num_complete_escorts, sizeof(escort_info), escort_compare_func);
518
519         // merge list
520         merge_escort_lists(complete_escorts, num_complete_escorts);
521
522         hud_gauge_popup_start(HUD_ESCORT_VIEW);
523
524 }
525
526 // called once per frame to remove dead or departed ships from the escort list
527 void hud_escort_cull_list()
528 {
529         int i, objnum, np_index;
530
531         // multiplayer dogfight
532         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT)){
533                 for ( i = 0; i < Num_escort_ships; i++ ) {
534                         np_index = find_player_id(Escort_ships[i].np_id);
535                         
536                         // maybe remove him if he left
537                         if ( np_index < 0 ) {
538                                 hud_remove_ship_from_escort_index(i, -1);
539                                 i--;
540                         }
541                 }
542         } 
543         // everything else
544         else {
545                 for ( i = 0; i < Num_escort_ships; i++ ) {
546                         objnum = Escort_ships[i].objnum;
547                         SDL_assert( objnum >=0 && objnum < MAX_OBJECTS );
548                         if ( Objects[objnum].flags & OF_SHOULD_BE_DEAD || Ships[Objects[objnum].instance].flags & SF_HIDDEN_FROM_SENSORS ) {
549                                 hud_remove_ship_from_escort_index(i, objnum);
550                                 i--;
551                         }
552                 }
553         }
554 }
555
556 // Set the color for the text to be displayed
557 int hud_escort_set_gauge_color(int index, int friendly)
558 {
559         int is_flashing=0;
560         shield_hit_info *shi;
561
562         shi = &Escort_ships[index].hit_info;
563
564         // multiplayer dogfight
565         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT)){
566                 hud_set_gauge_color(HUD_ESCORT_VIEW);
567                 return 0;
568         }
569         
570         if(friendly){
571                 hud_set_gauge_color(HUD_ESCORT_VIEW, HUD_C_DIM);
572         } else {
573                 gr_set_color_fast(&Color_red);
574         }
575
576         // set flashing color
577         if ( !timestamp_elapsed(shi->shield_hit_timers[HULL_HIT_OFFSET]) ) {
578                 if ( timestamp_elapsed(shi->shield_hit_next_flash[HULL_HIT_OFFSET]) ) {
579                         shi->shield_hit_next_flash[HULL_HIT_OFFSET] = timestamp(SHIELD_FLASH_INTERVAL);
580                         shi->shield_show_bright ^= (1<<HULL_HIT_OFFSET);        // toggle between default and bright frames
581                 }
582
583                 is_flashing=1;
584                 if ( shi->shield_show_bright & (1<<HULL_HIT_OFFSET) ) {
585                         if(friendly){
586                                 hud_set_gauge_color(HUD_ESCORT_VIEW, HUD_C_BRIGHT);
587                         } else {
588                                 gr_set_color_fast(&Color_bright_red);
589                         }
590                 } else {                        
591                         if(friendly){
592                                 hud_set_gauge_color(HUD_ESCORT_VIEW, HUD_C_DIM);
593                         } else {
594                                 gr_set_color_fast(&Color_dim_red);
595                         }                       
596                 }
597         }
598
599         return is_flashing;
600 }
601
602 // draw the shield icon and integrity for the escort ship
603 void hud_escort_show_icon(int index, object *objp)
604 {
605         float                   shields, integrity;
606         int                     screen_integrity, offset;
607         char                    buf[255];
608         ship                    *sp;
609
610         // multiplayer dogfight code should never get into here
611         SDL_assert(!((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT)));
612         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT)){
613                 return;
614         }
615
616         sp = &Ships[objp->instance];
617
618         // determine if its "friendly" or not   
619         if(Player_ship != NULL){
620                 hud_escort_set_gauge_color(index, (sp->team == Player_ship->team) ? 1 : 0);
621         } else {
622                 hud_escort_set_gauge_color(index, 1);
623         }
624
625         // draw a 'D' if a ship is disabled
626         if ( (sp->flags & SF_DISABLED) || (ship_subsys_disrupted(sp, SUBSYSTEM_ENGINE)) ) {             
627                 emp_hud_string( Escort_gauge_text_coords[gr_screen.res][index][3][0], Escort_gauge_text_coords[gr_screen.res][index][3][1], EG_NULL, XSTR( "D", 284));                          
628         }
629
630         // print out ship name
631         SDL_strlcpy(buf, sp->ship_name, SDL_arraysize(buf));
632         gr_force_fit_string(buf, 255, 100);     
633         
634         emp_hud_string( Escort_gauge_text_coords[gr_screen.res][index][0][0], Escort_gauge_text_coords[gr_screen.res][index][0][1], EG_ESCORT1 + index, buf);   
635
636         // show ship integrity
637         hud_get_target_strength(objp, &shields, &integrity);
638         screen_integrity = fl2i(integrity*100 + 0.5f);
639         offset = 0;
640         if ( screen_integrity < 100 ) {
641                 offset = 2;
642                 if ( screen_integrity == 0 ) {
643                         if ( integrity > 0 ) {
644                                 screen_integrity = 1;
645                         }
646                 }
647         }
648         emp_hud_printf( Escort_gauge_text_coords[gr_screen.res][index][2][0]+offset, Escort_gauge_text_coords[gr_screen.res][index][2][1], EG_NULL, "%d", screen_integrity);    
649 }
650
651 // multiplayer dogfight
652 void hud_escort_show_icon_dogfight(int index)
653 {
654         int                     hull_integrity = 100;
655         char                    buf[255];       
656         int                     np_index;
657         object          *objp;
658         ship_info       *sip;
659
660         int stat_shift = 40;
661
662         // always use the standard color to avoid confusion
663         hud_set_gauge_color(HUD_ESCORT_VIEW);   
664
665         // netplayer index
666         np_index = find_player_id(Escort_ships[index].np_id);
667         if((np_index < 0) || (np_index >= MAX_PLAYERS) || (Net_players[np_index].player == NULL)){
668                 return;
669         }
670         
671         // print out player name
672         SDL_strlcpy(buf, Net_players[np_index].player->callsign, SDL_arraysize(buf));
673         gr_force_fit_string(buf, 255, 100 - stat_shift);
674         emp_hud_string( Escort_gauge_text_coords[gr_screen.res][index][0][0], Escort_gauge_text_coords[gr_screen.res][index][0][1], EG_ESCORT1 + index, buf);   
675
676         // can we get the player object?
677         objp = NULL;
678         if((Net_players[np_index].player->objnum >= 0) && (Net_players[np_index].player->objnum < MAX_OBJECTS) && (Objects[Net_players[np_index].player->objnum].type == OBJ_SHIP)){
679                 objp = &Objects[Net_players[np_index].player->objnum];
680                 if((objp->instance >= 0) && (objp->instance < MAX_SHIPS) && (Ships[objp->instance].ship_info_index >= 0) && (Ships[objp->instance].ship_info_index < MAX_SHIPS)){
681                         sip = &Ship_info[Ships[objp->instance].ship_info_index];
682                 } else {
683                         return;
684                 }
685
686                 hull_integrity = (int)(((float)objp->hull_strength / (float)sip->initial_hull_strength) * 100.0f);
687                 if(hull_integrity < 0){
688                         hull_integrity = 0;
689                 }
690         }
691
692         // show ship integrity
693         if(objp == NULL){       
694                 emp_hud_printf( Escort_gauge_text_coords[gr_screen.res][index][2][0] - stat_shift, Escort_gauge_text_coords[gr_screen.res][index][2][1], EG_NULL, "%d", Net_players[np_index].player->stats.m_kill_count_ok);   
695         } else {
696                 emp_hud_printf( Escort_gauge_text_coords[gr_screen.res][index][2][0] - stat_shift, Escort_gauge_text_coords[gr_screen.res][index][2][1], EG_NULL, "(%d%%) %d", hull_integrity, Net_players[np_index].player->stats.m_kill_count_ok);    
697         }
698 }
699
700
701 // ----------------------------------------------------------------------
702 // hud_display_escort()
703 //
704 // Display the data on ships in the escort list
705 void hud_display_escort()
706 {
707         int                     i;
708         object          *objp;  
709
710         if ( !Show_escort_view ) {
711                 return;
712         }
713
714         if ( !Num_escort_ships ) {
715                 return;
716         }
717
718         // hud_set_default_color();
719         hud_set_gauge_color(HUD_ESCORT_VIEW);
720
721         // draw the top of the escort view
722         GR_AABITMAP(Escort_gauges[0].first_frame, Escort_coords[gr_screen.res][0][0], Escort_coords[gr_screen.res][0][1]);      
723         gr_string(Monitoring_coords[gr_screen.res][0], Monitoring_coords[gr_screen.res][1], XSTR( "monitoring", 285));
724
725         if ( Num_escort_ships >= 2 ) {
726                 GR_AABITMAP(Escort_gauges[1].first_frame, Escort_coords[gr_screen.res][1][0], Escort_coords[gr_screen.res][1][1]);              
727         }
728
729         if ( Num_escort_ships >= 3 ) {
730                 GR_AABITMAP(Escort_gauges[1].first_frame, Escort_coords[gr_screen.res][2][0], Escort_coords[gr_screen.res][2][1]);              
731         }
732         
733         // draw bottom of box
734         GR_AABITMAP(Escort_gauges[2].first_frame, Escort_coords[gr_screen.res][3][0], Escort_coords[gr_screen.res][Num_escort_ships][1]);       
735
736         // multiplayer dogfight
737         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT)){
738                 // draw the escort ship data
739                 for ( i = 0; i < Num_escort_ships; i++ ) {
740                         // oops. only show top 3
741                         if(i > 2){
742                                 break;
743                         }
744
745                         // draw
746                         hud_escort_show_icon_dogfight(i);
747                 }
748         }
749         // everything else
750         else {
751                 // draw the escort ship data
752                 for ( i = 0; i < Num_escort_ships; i++ ) {
753                         objp = &Objects[Escort_ships[i].objnum];
754                         hud_escort_show_icon(i, objp);
755                 }
756         }
757 }
758
759 // ----------------------------------------------------------------------
760 // hud_escort_view_toggle()
761 //
762 void hud_escort_view_toggle()
763 {
764         Show_escort_view ^= 1;
765         if ( Show_escort_view ) {
766                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Escort view enabled", 286));
767         } else {
768                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Escort view disabled", 287));
769         }
770 }
771
772 // try to add a ship to the escort list, if slot available
773 void hud_add_ship_to_escort(int objnum, int supress_feedback)
774 {
775         escort_info complete_escorts[MAX_COMPLETE_ESCORT_LIST];
776         int num_complete_escorts, idx, found;
777
778         // get complete escort list
779         hud_create_complete_escort_list(complete_escorts, &num_complete_escorts);
780
781         // check if ship is already on complete escort list
782         found = 0;
783         for (idx=0; idx<num_complete_escorts; idx++) {
784                 if (complete_escorts[idx].obj_signature == Objects[objnum].signature) {
785                         found = 1;
786                         break;
787                 }
788         }
789
790         // add new ship into complete list
791         if ( !found ) {
792                 complete_escorts[num_complete_escorts].objnum = objnum;
793                 complete_escorts[num_complete_escorts].obj_signature = Objects[objnum].signature;
794                 complete_escorts[num_complete_escorts].priority = Ships[Objects[objnum].instance].escort_priority;
795
796                 // remove him from escort list
797                 Ships[Objects[objnum].instance].flags |= SF_ESCORT;
798
799                 num_complete_escorts++;
800         }
801
802         // sort escort list by priority
803         qsort(complete_escorts, num_complete_escorts, sizeof(escort_info), escort_compare_func);
804
805         // merge list
806         merge_escort_lists(complete_escorts, num_complete_escorts);
807
808         // maybe do feedback
809         if ( (Num_escort_ships == MAX_ESCORT_SHIPS) && !supress_feedback) {
810                 found = 0;
811                 // search thru list for objnum
812                 for (idx=0; idx<Num_escort_ships; idx++) {
813                         if (Escort_ships[idx].objnum == objnum) {
814                                 found = 1;
815                                 break;
816                         }
817                 }
818
819                 if (!found) {
820                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Escort list is full with %d ships", 288), Num_escort_ships);
821                         snd_play( &Snds[SND_TARGET_FAIL]);
822                 }
823         }
824
825         hud_gauge_popup_start(HUD_ESCORT_VIEW);
826 }
827
828
829 // ----------------------------------------------------------------------
830 // hud_add_remove_ship_escort()
831 //
832 void hud_add_remove_ship_escort(int objnum, int supress_feedback)
833 {
834         int in_escort, i;
835
836         // no ships on the escort list in multiplayer dogfight
837         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT)){
838                 return;
839         }
840
841         if ( objnum < 0 ) {
842                 Int3();
843                 return;
844         }
845
846         if ( Objects[objnum].type != OBJ_SHIP ) {
847                 if ( !supress_feedback ) {
848                         snd_play( &Snds[SND_TARGET_FAIL]);
849                 }
850                 return;
851         }
852
853         in_escort = 0;
854         for ( i = 0; i < Num_escort_ships; i++ ) {
855                 if ( Escort_ships[i].obj_signature == Objects[objnum].signature ) {
856                         in_escort = 1;
857                         break;
858                 }
859         }
860
861         if ( in_escort ) {                              
862                 hud_remove_ship_from_escort_index(i, objnum);
863                 return;
864         }
865
866         hud_add_ship_to_escort(objnum, supress_feedback);
867 }
868
869 void hud_remove_ship_from_escort(int objnum)
870 {
871         int in_escort, i;
872
873         // no ships on the escort list in multiplayer dogfight
874         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT)){
875                 return;
876         }
877
878         if ( objnum < 0 ) {
879                 Int3();
880                 return;
881         }       
882
883         in_escort = 0;
884         for ( i = 0; i < Num_escort_ships; i++ ) {
885                 if ( Escort_ships[i].obj_signature == Objects[objnum].signature ) {
886                         in_escort = 1;
887                         break;
888                 }
889         }
890
891         if ( in_escort ) {
892                 hud_remove_ship_from_escort_index(i, objnum);
893                 return;
894         }       
895 }
896
897 // Called whenever a ship is hit to determine if that ship is in the escort list.  If it
898 // is, then start timers to flash the name hull/shield icon for that ship.
899 void hud_escort_ship_hit(object *objp, int quadrant)
900 {
901         int                                     num, i;
902         shield_hit_info *shi;
903
904         // no ships on the escort list in multiplayer dogfight
905         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT)){
906                 return;
907         }
908
909         for ( i = 0; i < Num_escort_ships; i++ ) {
910                 if ( Escort_ships[i].objnum == OBJ_INDEX(objp) ) {
911                         shi = &Escort_ships[i].hit_info;
912                         num = Quadrant_xlate[quadrant];
913                         hud_gauge_popup_start(HUD_ESCORT_VIEW);
914                         if ( quadrant >= 0 ) {
915                                 shi->shield_hit_timers[num] = timestamp(SHIELD_HIT_DURATION);
916                         } else {
917                                 shi->shield_hit_timers[HULL_HIT_OFFSET] = timestamp(SHIELD_HIT_DURATION);
918                         }
919                 }
920         }
921 }
922
923 // target the next ship in the escort list
924 void hud_escort_target_next()
925 {
926         int objnum;
927
928         if ( Num_escort_ships == 0 ) {
929                 snd_play( &Snds[SND_TARGET_FAIL], 0.0f );
930                 return;
931         }
932
933         Last_target_index++;
934         if ( Last_target_index >= Num_escort_ships ) {
935                 Last_target_index = 0;
936         }
937
938         objnum = Escort_ships[Last_target_index].objnum;
939         set_target_objnum( Player_ai,  objnum);
940         hud_restore_subsystem_target(&Ships[Objects[objnum].instance]);
941 }
942
943 // return the number of ships currently on the escort list
944 int hud_escort_num_ships_on_list()
945 {
946         return Num_escort_ships;
947 }
948
949 // Return the object number for the ship at index position in the escort list
950 int hud_escort_return_objnum(int index)
951 {
952         int escort_objnum, escort_sig;
953         if ( index >= Num_escort_ships ) {
954                 return -1;
955         }
956
957         escort_objnum = Escort_ships[index].objnum;
958         escort_sig = Escort_ships[index].obj_signature;
959
960         if ( escort_objnum < 0 ) {
961                 return -1;
962         }
963
964         // ensure this is still a valid index
965         if ( Objects[escort_objnum].signature != escort_sig ) {
966                 return -1;
967         }
968
969         return Escort_ships[index].objnum;
970 }
971
972
973 void hudescort_page_in()
974 {
975         int i;
976
977         for ( i = 0; i < MAX_ESCORT_SHIPS; i++ ) {
978                 bm_page_in_aabitmap( Escort_gauges[i].first_frame, Escort_gauges[i].num_frames);
979         }
980 }
981
982 void hud_escort_add_player(short id)
983 {
984         SDL_assert(Game_mode & GM_MULTIPLAYER);
985         if(!(Game_mode & GM_MULTIPLAYER)){
986                 return;
987         }       
988
989         int idx;
990
991         // just go through and add as long as its not a duplicate
992         for(idx=0; idx<Num_escort_ships; idx++){
993                 if(Escort_ships[idx].np_id == id){
994                         return;
995                 }
996         }
997
998         // re-setup the escort list
999         hud_setup_escort_list(0);
1000 }
1001
1002 void hud_escort_remove_player(short id)
1003 {       
1004         SDL_assert(Game_mode & GM_MULTIPLAYER);
1005         if(!(Game_mode & GM_MULTIPLAYER)){
1006                 return;
1007         }
1008
1009         int idx;
1010
1011         // find the instance and remove it if possible
1012         for(idx=0; idx<Num_escort_ships; idx++){
1013                 if(Escort_ships[idx].np_id == id){
1014                         hud_remove_ship_from_escort_index(idx, -1);
1015                         return;
1016                 }
1017         }
1018 }