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