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