]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multi_pinfo.cpp
The Great Newline Fix
[taylor/freespace2.git] / src / network / multi_pinfo.cpp
1 /*
2  * $Logfile: /Freespace2/code/Network/multi_pinfo.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * $Log$
8  * Revision 1.2  2002/05/07 03:16:47  theoddone33
9  * The Great Newline Fix
10  *
11  * Revision 1.1.1.1  2002/05/03 03:28:10  root
12  * Initial import.
13  *  
14  * 
15  * 15    9/10/99 9:44p Dave
16  * Bumped version # up. Make server reliable connects not have such a huge
17  * timeout. 
18  * 
19  * 14    8/30/99 5:01p Dave
20  * Made d3d do less state changing in the nebula. Use new chat server for
21  * PXO.
22  * 
23  * 13    8/22/99 5:53p Dave
24  * Scoring fixes. Added self destruct key. Put callsigns in the logfile
25  * instead of ship designations for multiplayer players.
26  * 
27  * 12    8/03/99 11:43a Dave
28  * Don't allow medals button in demo.
29  * 
30  * 11    7/26/99 11:14a Andsager
31  * Disable medals in demo multiplayer
32  * 
33  * 10    6/16/99 4:06p Dave
34  * New pilot info popup. Added new draw-bitmap-as-poly function.
35  * 
36  * 9     1/30/99 1:29a Dave
37  * Fixed nebula thumbnail problem. Full support for 1024x768 choose pilot
38  * screen.  Fixed beam weapon death messages.
39  * 
40  * 8     1/14/99 6:06p Dave
41  * 100% full squad logo support for single player and multiplayer.
42  * 
43  * 7     1/12/99 4:07a Dave
44  * Put in barracks code support for selecting squad logos. Properly
45  * distribute squad logos in a multiplayer game.
46  * 
47  * 6     12/14/98 12:13p Dave
48  * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
49  * Need to test now.
50  * 
51  * 5     11/30/98 1:07p Dave
52  * 16 bit conversion, first run.
53  * 
54  * 4     11/05/98 4:18p Dave
55  * First run nebula support. Beefed up localization a bit. Removed all
56  * conditional compiles for foreign versions. Modified mission file
57  * format.
58  * 
59  * 3     10/13/98 9:29a Dave
60  * Started neatening up freespace.h. Many variables renamed and
61  * reorganized. Added AlphaColors.[h,cpp]
62  * 
63  * 2     10/07/98 10:53a Dave
64  * Initial checkin.
65  * 
66  * 1     10/07/98 10:50a Dave
67  * 
68  * 
69  * $NoKeywords: $
70  */
71
72 #include "ui.h"
73 #include "bmpman.h"
74 #include "gamesnd.h"
75 #include "freespace.h"
76 #include "gamesequence.h"
77 #include "key.h"
78 #include "medals.h"
79 #include "palman.h"
80 #include "mouse.h"
81 #include "multi.h"
82 #include "multi_xfer.h"
83 #include "multi_pinfo.h"
84 #include "alphacolors.h"
85 #include "localize.h"
86 #include "3d.h"
87
88 // ---------------------------------------------------------------------------------------
89 // MULTI PLAYER INFO DEFINES/VARS
90 //
91
92 //XSTR:OFF
93
94 #define MULTI_PINFO_NUM_BUTTONS         4
95
96 // bitmaps defs
97 char *Multi_pinfo_bitmap_name[GR_NUM_RESOLUTIONS] = {
98         "PilotInfo",
99         "2_PilotInfo"
100 };
101 char *Multi_pinfo_bitmap_mask[GR_NUM_RESOLUTIONS] = {
102         "PilotInfo-M",
103         "2_PilotInfo-M"
104 };
105
106 // button defs
107 #define MPI_SCROLL_STATS_UP                     0
108 #define MPI_SCROLL_STATS_DOWN                   1
109 #define MPI_MEDALS                                              2
110 #define MPI_EXIT                                                        3
111
112 // pilot image area defs
113 int Multi_pinfo_pilot_coords[GR_NUM_RESOLUTIONS][4] = {
114         { // GR_640
115                 22, 159, 160, 120
116         },
117         { // GR_1024
118                 35, 254, 256, 192
119         }
120 };
121 int Multi_pinfo_squad_coords[GR_NUM_RESOLUTIONS][4] = {
122         { // GR_640
123                 22, 299, 128, 128
124         },
125         { // GR_1024
126                 35, 479, 205, 205
127         }
128 };
129
130 // pilot bitmaps
131 typedef struct np_bitmap {
132         int bitmap;                                                                     // bitmap id
133         char filename[MAX_FILENAME_LEN];                // filename
134 } np_bitmap;
135 np_bitmap Mp_pilot;                     // pilot pic
136 np_bitmap Mp_squad;                     // squad logo
137
138 UI_WINDOW Multi_pinfo_window;                                                                                   // the window object for the join screen
139 UI_BUTTON Multi_pinfo_select_button;                                                            // for selecting list items
140 int Multi_pinfo_bitmap;                                                                                                 // the background bitmap
141 ui_button_info Multi_pinfo_buttons[GR_NUM_RESOLUTIONS][MULTI_PINFO_NUM_BUTTONS] = {
142         { // GR_640
143                 ui_button_info("PIB_00",        617,    256,    -1,     -1,     0),
144                 ui_button_info("PIB_01",        617,    298,    -1,     -1,     1),
145                 ui_button_info("PIB_02",        172,    322,    -1,     -1,     2),
146                 ui_button_info("PIB_03",        219,    332,    217,    318,    3)
147         },
148         { // GR_1024
149                 ui_button_info("2_PIB_00",      988,    410,    -1,     -1,     0),
150                 ui_button_info("2_PIB_01",      988,    477,    -1,     -1,     1),
151                 ui_button_info("2_PIB_02",      276,    516,    -1,     -1,     2),
152                 ui_button_info("2_PIB_03",      350,    532,    348,    510,    3)
153         }
154 };
155
156 #define MULTI_PINFO_NUM_TEXT                    1
157 UI_XSTR Multi_pinfo_text[GR_NUM_RESOLUTIONS][MULTI_PINFO_NUM_TEXT] = {
158         { // GR_640
159                 { "Close",              428,    217,    318,    UI_XSTR_COLOR_PINK, -1, &Multi_pinfo_buttons[0][MPI_EXIT].button },             
160         },
161         { // GR_1024
162                 { "Close",              428,    348,    510,    UI_XSTR_COLOR_PINK, -1, &Multi_pinfo_buttons[1][MPI_EXIT].button },             
163         }
164 };
165
166 //XSTR:ON
167
168 // stats labels
169 #define MULTI_PINFO_NUM_STATS_LABELS            9
170 #define MPI_RANK                                                                        0
171 #define MPI_MISSIONS_FLOWN                                              1
172 #define MPI_FLIGHT_TIME                                                 2
173 #define MPI_LAST_FLOWN                                                  3
174 #define MPI_FIGHTER_KILLS                                               4
175 // #define MPI_OTHER_KILLS                                                      5
176 #define MPI_PSHOTS_FIRED                                                5
177 //#define MPI_PSHOTS_HIT                                                        6
178  #define MPI_PSHOTS_PCT                                                 6
179 #define MPI_SSHOTS_FIRED                                                7
180 // #define MPI_SSHOTS_HIT                                                       10
181 #define MPI_SSHOTS_PCT                                                  8
182
183 char *Multi_pinfo_stats_labels[MULTI_PINFO_NUM_STATS_LABELS]; 
184
185 #define MAX_LABEL_TEXT          50
186 char Multi_pinfo_stats_vals[MULTI_PINFO_NUM_STATS_LABELS][MAX_LABEL_TEXT];
187 int Multi_pinfo_stats_label_offsets[MULTI_PINFO_NUM_STATS_LABELS] = {
188         20,10,10,20,20,10,20,10,10,
189 };
190
191 // stats area defs
192 int Multi_pinfo_stats_area_coords[GR_NUM_RESOLUTIONS][4] = {
193         { // GR_640
194                 215, 163, 414, 155
195         },
196         { // GR_1024
197                 335, 261, 662, 248
198         }
199 };
200 int Multi_pinfo_stats_x[GR_NUM_RESOLUTIONS] = {
201         460,            // GR_640
202         650             // GR_1024
203 };
204
205 // is the popup already running
206 int Multi_pinfo_popup_running = 0;
207
208 // background bitmap to be blitted
209 int Multi_pinfo_screen_save = -1;
210
211 // flag indicating if the popup has gotten messed up somewhere and should bail
212 int Multi_pinfo_popup_error = 0;
213
214 // flag indicating if the popup should be done
215 int Multi_pinfo_popup_done = 0;
216
217 // player this popup is being used for
218 net_player *Multi_pinfo_popup_player = NULL;
219
220 // screen shader
221 extern shader Grey_shader;
222
223 // hardware textures backup
224 int Multi_pinfo_hardware_texture_backup;
225
226
227 // ---------------------------------------------------------------------------------------
228 // MULTI PLAYER INFO FORWARD DECLARATIONS
229 //
230
231 // initialize all popup details (graphics, etc)
232 void multi_pinfo_popup_init(net_player *pl);
233
234 // run the popup in a tight loop (no states)
235 void multi_pinfo_popup_do();
236
237 // close the popup
238 void multi_pinfo_popup_close();
239
240 // blit the pilot image
241 void multi_pinfo_blit_pilot_image();
242
243 // blit the pilot squadron logo
244 void multi_pinfo_blit_squadron_logo();
245
246 // blit the player statistics
247 void multi_pinfo_blit_player_stats();
248
249 // check for button presses
250 void multi_pinfo_popup_check_buttons();
251
252 // act on a button press
253 void multi_pinfo_popup_button_pressed(int n);
254
255 // display the medals screen for this player
256 void multi_pinfo_do_medals();
257
258 // load up and use the proper palette
259 void multi_pinfo_set_palette();
260
261 // build the stats value strings for this player
262 void multi_pinfo_build_stats();
263
264 // if the pilot's image was currently loading when we started the popup, load it up now if its finished
265 void multi_pinfo_maybe_reload_pic(np_bitmap *b);
266
267 // reset the player infomation for this popup
268 void multi_pinfo_reset_player(net_player *np);
269
270 // lookup the "previous" player in the netplayer list, return null if not found
271 net_player *multi_pinfo_get_prev_player(net_player *np);
272
273 // lookup the "next" player in the netplayer list, return null if not found
274 net_player *multi_pinfo_get_next_player(net_player *np);
275
276
277 // ---------------------------------------------------------------------------------------
278 // MULTI PLAYER INFO FUNCTIONS
279 //
280
281 // fire up the player info popup, select first available pilot if np == NULL
282 void multi_pinfo_popup(net_player *np)
283 {
284         // if the popup is already running, don't do anything
285         if(Multi_pinfo_popup_running){
286                 return;
287         }
288
289         // set the player for informational purposes
290         Assert(np != NULL);     
291
292         // play the popup appear sound
293         gamesnd_play_iface(SND_POPUP_APPEAR);
294
295         // initialize the popup
296         multi_pinfo_popup_init(np);
297
298         // mark the popup as running
299         Multi_pinfo_popup_running = 1;
300
301         // run the popup
302         multi_pinfo_popup_do();
303
304         // close the popup
305         multi_pinfo_popup_close();
306
307         // play the popup disappear sound
308         gamesnd_play_iface(SND_POPUP_DISAPPEAR);
309 }
310
311 // notify the popup that a player has left
312 void multi_pinfo_notify_drop(net_player *np)
313 {
314         net_player *reset;
315
316         // if we're no active, bail
317         if(!Multi_pinfo_popup_running){
318                 return;
319         }
320
321         // if this is not the player we're currently displaying, bail
322         if(np != Multi_pinfo_popup_player){
323                 return;
324         }
325
326         // otherwise we need to switch to someone else
327         reset = multi_pinfo_get_prev_player(np);
328         if(reset != NULL){
329                 multi_pinfo_reset_player(reset);
330                 return;
331         }
332         reset = multi_pinfo_get_next_player(np);
333         if(reset != NULL){
334                 multi_pinfo_reset_player(reset);
335                 return;
336         }
337
338         // bail, since there's no one else
339         Int3();
340         Multi_pinfo_popup_done = 1;
341 }
342
343
344 // ---------------------------------------------------------------------------------------
345 // MULTI PLAYER INFO FORWARD DEFINITIONS
346 //
347
348 // initialize all popup details (graphics, etc)
349 void multi_pinfo_popup_init(net_player *np)
350 {
351         int idx;
352         
353         // no errors to start with
354         Multi_pinfo_popup_error = 0;
355
356         // shouldn't be done
357         Multi_pinfo_popup_done = 0;
358
359         // store the background as it currently is
360         Multi_pinfo_screen_save = gr_save_screen();
361         if(Multi_pinfo_screen_save == -1){
362                 Multi_pinfo_popup_error = 1;
363                 return;
364         }
365
366         // create the interface window
367         Multi_pinfo_window.create(0,0,gr_screen.max_w,gr_screen.max_h,0);
368         Multi_pinfo_window.set_mask_bmap(Multi_pinfo_bitmap_mask[gr_screen.res]);
369
370         // load the background bitmap
371         Multi_pinfo_bitmap = bm_load(Multi_pinfo_bitmap_name[gr_screen.res]);
372         if(Multi_pinfo_bitmap < 0){
373                 Multi_pinfo_popup_error = 1;
374                 return; 
375         }
376
377         // backup hardware textures setting and bash to max
378         Multi_pinfo_hardware_texture_backup = Detail.hardware_textures;
379         Detail.hardware_textures = MAX_DETAIL_LEVEL;
380
381         // zero bitmap info
382         Mp_pilot.bitmap = -1;
383         strcpy(Mp_pilot.filename, "");
384         Mp_squad.bitmap = -1;
385         strcpy(Mp_squad.filename, "");
386
387         // set the player status
388         multi_pinfo_reset_player(np);   
389         
390         // create the interface buttons
391         for(idx=0;idx<MULTI_PINFO_NUM_BUTTONS;idx++){
392                 // create the object
393                 Multi_pinfo_buttons[gr_screen.res][idx].button.create(&Multi_pinfo_window, "", Multi_pinfo_buttons[gr_screen.res][idx].x, Multi_pinfo_buttons[gr_screen.res][idx].y, 1, 1, 0, 1);
394
395                 // set the sound to play when highlighted
396                 Multi_pinfo_buttons[gr_screen.res][idx].button.set_highlight_action(common_play_highlight_sound);
397
398                 // set the ani for the button
399                 Multi_pinfo_buttons[gr_screen.res][idx].button.set_bmaps(Multi_pinfo_buttons[gr_screen.res][idx].filename);
400
401                 // set the hotspot
402                 Multi_pinfo_buttons[gr_screen.res][idx].button.link_hotspot(Multi_pinfo_buttons[gr_screen.res][idx].hotspot);
403         }                       
404
405         // add xstrs
406         for(idx=0; idx<MULTI_PINFO_NUM_TEXT; idx++){
407                 Multi_pinfo_window.add_XSTR(&Multi_pinfo_text[gr_screen.res][idx]);
408         }
409
410         // disable medals button for the demo
411 #ifdef FS2_DEMO
412         Multi_pinfo_buttons[gr_screen.res][MPI_MEDALS].button.hide();
413         Multi_pinfo_buttons[gr_screen.res][MPI_MEDALS].button.disable();
414 #endif
415
416         // initialize strings   
417         Multi_pinfo_stats_labels[0] = strdup(XSTR("Rank", 1007));
418         Multi_pinfo_stats_labels[1] = strdup(XSTR("Missions Flown", 1008));
419         Multi_pinfo_stats_labels[2] = strdup(XSTR("Flight Time", 1009));
420         Multi_pinfo_stats_labels[3] = strdup(XSTR("Last Flown",1010));
421         Multi_pinfo_stats_labels[4] = strdup(XSTR("Total Kills", 115));
422         Multi_pinfo_stats_labels[5] = strdup(XSTR("Primary Shots Fired", 1012));
423         Multi_pinfo_stats_labels[6] = strdup(XSTR("Primary Hit %", 1013));
424         Multi_pinfo_stats_labels[7] = strdup(XSTR("Secondary Shots Fired",      1014));
425         Multi_pinfo_stats_labels[8] = strdup(XSTR("Secondary Hit %", 1015));                            
426 }
427
428 // run the popup in a tight loop (no states)
429 void multi_pinfo_popup_do()
430 {
431         int k;
432         
433         // if there was an error in initialization, return immediately
434         if(Multi_pinfo_popup_error){
435                 return;
436         }
437
438         // tight loop
439         while(!Multi_pinfo_popup_done){         
440                 multi_pinfo_maybe_reload_pic(&Mp_pilot);                
441                 multi_pinfo_maybe_reload_pic(&Mp_squad);                
442
443                 // process the window
444                 k = Multi_pinfo_window.process();
445                 switch(k){
446                 case KEY_ESC :
447                         Multi_pinfo_popup_done = 1;
448                         break;
449                 }
450
451                 // check button presses
452                 multi_pinfo_popup_check_buttons();
453
454                 // set frametime and run background stuff
455                 game_set_frametime(-1);
456                 game_do_state_common(gameseq_get_state());
457                 
458                 // draw the background bitmap and the ui window over it
459                 Assert(Multi_pinfo_screen_save != -1);
460                 gr_reset_clip();
461                 gr_restore_screen(Multi_pinfo_screen_save);             
462
463                 // grey the screen
464                 gr_set_shader(&Grey_shader);
465                 gr_shade(0,0,gr_screen.clip_width, gr_screen.clip_height);
466                 
467                 // draw the background bitmap
468                 gr_set_bitmap(Multi_pinfo_bitmap);
469                 gr_bitmap(0,0);         
470
471                 // blit the selected pilot image
472                 multi_pinfo_blit_pilot_image();
473
474                 // blit the squadron logo
475                 multi_pinfo_blit_squadron_logo();
476
477                 // blit the player statistics
478                 multi_pinfo_blit_player_stats();                
479
480                 // draw the ui window and flip
481                 Multi_pinfo_window.draw();              
482                 gr_flip();
483         }
484 }
485
486 // close the popup
487 void multi_pinfo_popup_close()
488 {
489         int idx;
490         
491         // unload any bitmaps
492         if(Multi_pinfo_bitmap != -1){
493                 bm_release(Multi_pinfo_bitmap);         
494         }       
495
496         // free the background screen if possible
497         if(Multi_pinfo_screen_save >= 0){
498                 gr_free_screen(Multi_pinfo_screen_save);        
499         }
500
501         // release the pilot/squad images
502         if(Mp_pilot.bitmap != -1){
503                 bm_release(Mp_pilot.bitmap);
504         }
505         if(Mp_squad.bitmap != -1){
506                 bm_release(Mp_squad.bitmap);
507         }
508
509         // free up strings
510         for(idx=0; idx<MULTI_PINFO_NUM_STATS_LABELS; idx++){
511                 if(Multi_pinfo_stats_labels[idx] != NULL){
512                         free(Multi_pinfo_stats_labels[idx]);
513                         Multi_pinfo_stats_labels[idx] = NULL;
514                 }
515         }       
516
517         // unset the player handle
518         Multi_pinfo_popup_player = NULL;
519
520         // mark the popup as not running
521         Multi_pinfo_popup_running = 0;
522         
523         // destroy the UI_WINDOW
524         Multi_pinfo_window.destroy();
525
526         // restore hardware textures detail level
527         Detail.hardware_textures = Multi_pinfo_hardware_texture_backup;
528 }
529
530 // blit the pilot image
531 void multi_pinfo_blit_pilot_image()
532 {
533         char place_text[100];   
534         int w;
535
536         // if we don't have a bitmap handle, blit a placeholder
537         if(Mp_pilot.bitmap == -1){
538                 gr_set_color_fast(&Color_normal);               
539
540                 // if there is no image
541                 if(strlen(Mp_pilot.filename) <= 0){
542                         strcpy(place_text,XSTR("No/Invalid Image", 1053));
543                 } 
544                 // if the image is xferring
545                 else if(multi_xfer_lookup(Mp_pilot.filename)){
546                         strcpy(place_text,XSTR("Image Transferring", 691));
547                 }
548                 // if we're not accepting images
549                 else if(!(Net_player->p_info.options.flags & MLO_FLAG_ACCEPT_PIX) || !(Netgame.options.flags & MSO_FLAG_ACCEPT_PIX)){
550                         strcpy(place_text,XSTR("No Image", 692));
551                 }
552                 // otherwise we wait
553                 else {
554                         strcpy(place_text,XSTR("Waiting", 690));
555                 }               
556
557                 // center the text
558                 gr_get_string_size(&w,NULL,place_text);
559                 gr_string(Multi_pinfo_pilot_coords[gr_screen.res][0] + ((Multi_pinfo_pilot_coords[gr_screen.res][2] - w)/2), Multi_pinfo_pilot_coords[gr_screen.res][1], place_text);
560         } 
561         // otherwise blit the bitmap
562         else {
563                 gr_set_bitmap(Mp_pilot.bitmap);
564
565                 // get width and heigh
566                 int w, h;
567                 bm_get_info(Mp_pilot.bitmap, &w, &h, NULL, NULL, NULL, NULL);
568
569                 gr_bitmap(Multi_pinfo_pilot_coords[gr_screen.res][0] + ((Multi_pinfo_pilot_coords[gr_screen.res][2] - w)/2), 
570                                          Multi_pinfo_pilot_coords[gr_screen.res][1] + ((Multi_pinfo_pilot_coords[gr_screen.res][3] - h)/2));
571                 // g3_draw_2d_poly_bitmap(Multi_pinfo_pilot_coords[gr_screen.res][0], Multi_pinfo_pilot_coords[gr_screen.res][1], Multi_pinfo_pilot_coords[gr_screen.res][2], Multi_pinfo_pilot_coords[gr_screen.res][3]);
572         }
573 }
574
575 // blit the pilot squadron logo
576 void multi_pinfo_blit_squadron_logo()
577 {
578         char place_text[100];   
579         int w;
580         player *p = Multi_pinfo_popup_player->player;
581
582         // if we don't have a bitmap handle, blit a placeholder
583         if(Mp_squad.bitmap == -1){
584                 gr_set_color_fast(&Color_normal);               
585
586                 // if there is no image
587                 if(strlen(p->squad_filename) <= 0){
588                         strcpy(place_text,XSTR("No/Invalid Image", 1053));
589                 } 
590                 // if the image is xferring
591                 else if(multi_xfer_lookup(p->squad_filename)){
592                         strcpy(place_text,XSTR("Image Transferring", 691));
593                 }
594                 // if we're not accepting images
595                 else if(!(Net_player->p_info.options.flags & MLO_FLAG_ACCEPT_PIX) || !(Netgame.options.flags & MSO_FLAG_ACCEPT_PIX)){
596                         strcpy(place_text,XSTR("No Image", 692));
597                 }
598                 // otherwise we wait
599                 else {
600                         strcpy(place_text,XSTR("Waiting", 690));
601                 }                               
602
603                 // center the text
604                 gr_get_string_size(&w, NULL, place_text);
605                 gr_string(Multi_pinfo_squad_coords[gr_screen.res][0] + ((Multi_pinfo_squad_coords[gr_screen.res][2] - w)/2), Multi_pinfo_squad_coords[gr_screen.res][1], place_text);
606         } 
607         // otherwise blit the bitmap
608         else {
609                 gr_set_bitmap(Mp_squad.bitmap);
610                 // gr_bitmap(MPI_SQUAD_X, MPI_SQUAD_Y);
611
612                 // get width and heigh
613                 int w, h;
614                 bm_get_info(Mp_squad.bitmap, &w, &h, NULL, NULL, NULL, NULL);
615
616                 gr_bitmap(Multi_pinfo_squad_coords[gr_screen.res][0] + ((Multi_pinfo_squad_coords[gr_screen.res][2] - w)/2), 
617                                          Multi_pinfo_squad_coords[gr_screen.res][1] + ((Multi_pinfo_squad_coords[gr_screen.res][3] - h)/2));
618                 // g3_draw_2d_poly_bitmap(Multi_pinfo_squad_coords[gr_screen.res][0], Multi_pinfo_squad_coords[gr_screen.res][1], Multi_pinfo_squad_coords[gr_screen.res][2], Multi_pinfo_squad_coords[gr_screen.res][3]);
619         }
620 }
621
622 // blit the player statistics
623 void multi_pinfo_blit_player_stats()
624 {
625         int idx,y_start;        
626
627         // blit the player's callsign and "all time stats"
628         gr_set_color_fast(&Color_bright);
629         gr_string(Multi_pinfo_stats_area_coords[gr_screen.res][0], Multi_pinfo_stats_area_coords[gr_screen.res][1], Multi_pinfo_popup_player->player->callsign);
630         gr_string(Multi_pinfo_stats_x[gr_screen.res], Multi_pinfo_stats_area_coords[gr_screen.res][1], XSTR("All Time Stats", 128));
631         
632         gr_set_color_fast(&Color_normal);
633
634         // blit all the labels
635         y_start = Multi_pinfo_stats_area_coords[gr_screen.res][1] + 15;
636         for(idx=0;idx<MULTI_PINFO_NUM_STATS_LABELS;idx++){
637                 gr_string(Multi_pinfo_stats_area_coords[gr_screen.res][0], y_start, Multi_pinfo_stats_labels[idx]);
638                 y_start += Multi_pinfo_stats_label_offsets[idx];
639         }       
640
641         // blit all the stats values themselves
642         y_start = Multi_pinfo_stats_area_coords[gr_screen.res][1] + 15;
643         for(idx=0;idx<MULTI_PINFO_NUM_STATS_LABELS;idx++){
644                 gr_string(Multi_pinfo_stats_x[gr_screen.res], y_start, Multi_pinfo_stats_vals[idx]);
645                 y_start += Multi_pinfo_stats_label_offsets[idx];
646         }       
647 }
648
649 // check for button presses
650 void multi_pinfo_popup_check_buttons()
651 {
652         int idx;
653
654         // check for all buttons
655         for(idx=0;idx<MULTI_PINFO_NUM_BUTTONS;idx++){
656                 if(Multi_pinfo_buttons[gr_screen.res][idx].button.pressed()){
657                         multi_pinfo_popup_button_pressed(idx);
658                         break;
659                 }
660         }
661 }
662
663 // act on a button press
664 void multi_pinfo_popup_button_pressed(int n)
665 {
666         net_player *swap;
667
668         switch(n){
669         case MPI_EXIT:
670                 Multi_pinfo_popup_done = 1;             
671                 break;
672
673         case MPI_MEDALS:
674                 gamesnd_play_iface(SND_USER_SELECT);
675                 multi_pinfo_do_medals();
676                 break;
677
678         case MPI_SCROLL_STATS_UP:
679                 swap = multi_pinfo_get_prev_player(Multi_pinfo_popup_player);
680                 if(swap != NULL){
681                         gamesnd_play_iface(SND_USER_SELECT);
682                         multi_pinfo_reset_player(swap);
683                 } else {
684                         gamesnd_play_iface(SND_GENERAL_FAIL);
685                 }
686                 break;
687
688         case MPI_SCROLL_STATS_DOWN:
689                 swap = multi_pinfo_get_next_player(Multi_pinfo_popup_player);
690                 if(swap != NULL){
691                         gamesnd_play_iface(SND_USER_SELECT);
692                         multi_pinfo_reset_player(swap);
693                 } else {
694                         gamesnd_play_iface(SND_GENERAL_FAIL);
695                 }
696                 break;
697
698         default :
699                 gamesnd_play_iface(SND_GENERAL_FAIL);
700                 break;
701         }
702 }
703
704 // display the medals screen for this player
705 void multi_pinfo_do_medals()
706 {
707 #ifdef FS2DEMO
708         game_feature_not_in_demo_popup();
709 #else
710         int ret_code;
711
712         // initialize the medals screen
713         medal_main_init(Multi_pinfo_popup_player->player,MM_POPUP);
714
715         // run the medals screen until it says that it should be closed
716         do {
717                 // set frametime and run common functions
718                 game_set_frametime(-1);
719                 game_do_state_common(gameseq_get_state());
720
721                 // run the medals screen
722                 ret_code = medal_main_do();             
723         } while(ret_code && !Multi_pinfo_popup_done);
724
725         // close the medals screen down
726         medal_main_close();
727
728         // restore the proper palette
729         multi_pinfo_set_palette();
730 #endif
731 }
732
733 // load up and use the proper palette
734 void multi_pinfo_set_palette()
735 {
736 #ifndef HARDWARE_ONLY
737         palette_use_bm_palette(Multi_pinfo_bitmap);
738 #endif
739 }
740
741 // build the stats value strings for this player
742 void multi_pinfo_build_stats()
743 {
744         // int idx;
745         // int fighter_kills,other_kills;
746         scoring_struct *sc = &Multi_pinfo_popup_player->player->stats;
747
748         // build alltime fighter and non-fighter kills
749         /*
750         fighter_kills = 0;
751         other_kills = 0;
752         for(idx=0;idx<MAX_SHIP_TYPES;idx++){
753                 if(sc->kills[idx] > 0){
754                         if(Ship_info[idx].flags & SIF_FIGHTER){
755                                 fighter_kills += sc->kills[idx];
756                         } else {
757                                 other_kills += sc->kills[idx];
758                         }
759                 }
760         }       
761         */
762         sprintf(Multi_pinfo_stats_vals[MPI_FIGHTER_KILLS], "%d", sc->kill_count);
763         
764         // sprintf(Multi_pinfo_stats_vals[MPI_OTHER_KILLS],"%d",other_kills);
765
766         // missions flown
767         sprintf(Multi_pinfo_stats_vals[MPI_MISSIONS_FLOWN],"%d",(int)sc->missions_flown);
768
769         // flight time          
770         game_format_time(fl2f((float)sc->flight_time),Multi_pinfo_stats_vals[MPI_FLIGHT_TIME]);         
771
772         // last flown   
773         if(sc->last_flown == 0){
774                 strcpy(Multi_pinfo_stats_vals[MPI_LAST_FLOWN],XSTR("No missions flown",693));
775         } else {
776                 tm *tmr = gmtime(&sc->last_flown);
777                 if(tmr != NULL){
778                         strftime(Multi_pinfo_stats_vals[MPI_LAST_FLOWN],MAX_LABEL_TEXT,"%m/%d/%y %H:%M",tmr);
779                 } else {
780                         strcpy(Multi_pinfo_stats_vals[MPI_LAST_FLOWN], "");                     
781                 }
782         }       
783
784         // rank
785         strcpy(Multi_pinfo_stats_vals[MPI_RANK],Ranks[sc->rank].name);
786
787         // primary shots fired
788         sprintf(Multi_pinfo_stats_vals[MPI_PSHOTS_FIRED],"%d",sc->p_shots_fired);
789
790         // primary shots hit
791         // sprintf(Multi_pinfo_stats_vals[MPI_PSHOTS_HIT],"%d",sc->p_shots_hit);
792         
793         // primary hit pct
794         sprintf(Multi_pinfo_stats_vals[MPI_PSHOTS_PCT],"%d%%",(int)(100.0f * ((float)sc->p_shots_hit / (float)sc->p_shots_fired)));
795         // primary shots fired
796         sprintf(Multi_pinfo_stats_vals[MPI_SSHOTS_FIRED],"%d",sc->s_shots_fired);
797
798         // primary shots hit
799         // sprintf(Multi_pinfo_stats_vals[MPI_SSHOTS_HIT],"%d",sc->s_shots_hit);
800         
801         // primary hit pct
802         sprintf(Multi_pinfo_stats_vals[MPI_SSHOTS_PCT],"%d%%",(int)(100.0f * ((float)sc->s_shots_hit / (float)sc->s_shots_fired)));
803 }
804
805 // if the pilot's image was currently loading when we started the popup, load it up now if its finished
806 void multi_pinfo_maybe_reload_pic(np_bitmap *b)
807 {       
808         // if the bitmap is valid, do nothing
809         if(b->bitmap >= 0){
810                 return;
811         }       
812
813         // if the local player is not accepting pix or the netgame is not accepting pix, bail here
814         if(!(Net_player->p_info.options.flags & MLO_FLAG_ACCEPT_PIX) || !(Netgame.options.flags & MSO_FLAG_ACCEPT_PIX)){                
815                 return;
816         }                       
817
818         // if the bitmap filename is bogus
819         if(strlen(b->filename) <= 0){
820                 return;
821         }       
822
823         // try again
824         b->bitmap = bm_load_duplicate(b->filename);     
825 }
826
827 // attempt to validate a bitmap (ie, return whether its displayable or not)
828 /*
829 int multi_pinfo_validate_bitmap(int bitmap)
830 {
831         int w,h;
832         
833         // if the bitmap handle is invalid false
834         if(bitmap == -1){
835                 return 0;
836         }
837         
838         // get the bitmap info
839         w = -1;
840         h = -1;
841         bm_get_info(bitmap,&w,&h);      
842
843         // return fail
844         if((w != MPI_IMAGE_W) || (h != MPI_IMAGE_H)){
845                 return 0;
846         }
847
848         // return success
849         return 1;
850 }
851 */
852
853 // is the pilot info popup currently active?
854 int multi_pinfo_popup_active()
855 {
856         return Multi_pinfo_popup_running;
857 }
858
859 // kill the currently active popup (if any)
860 void multi_pinfo_popup_kill()
861 {
862         // we're done, byatch
863         Multi_pinfo_popup_done = 1;
864 }
865
866 // reset the player infomation for this popup
867 void multi_pinfo_reset_player(net_player *np)
868 {       
869         // assign the player
870         Multi_pinfo_popup_player = np;
871
872         // unload any old image data if necessary
873         strcpy(Mp_pilot.filename, "");
874         if(Mp_pilot.bitmap != -1){
875                 bm_release(Mp_pilot.bitmap);
876                 Mp_pilot.bitmap = -1;
877         }
878         strcpy(Mp_squad.filename, "");
879         if(Mp_squad.bitmap != -1){
880                 bm_release(Mp_squad.bitmap);
881                 Mp_squad.bitmap = -1;
882         }       
883         
884         // try and load pilot pic/squad logo
885         if(strlen(np->player->image_filename) >= 0){
886                 strcpy(Mp_pilot.filename, np->player->image_filename);
887                 Mp_pilot.bitmap = bm_load_duplicate(Mp_pilot.filename);
888         }
889         if(strlen(np->player->squad_filename) >= 0){
890                 strcpy(Mp_squad.filename, np->player->squad_filename);
891                 Mp_squad.bitmap = bm_load_duplicate(Mp_squad.filename);
892         }
893
894         // build the stats value strings for this player
895         multi_pinfo_build_stats();
896 }
897
898 // lookup the "previous" player in the netplayer list, return null if not found
899 net_player *multi_pinfo_get_prev_player(net_player *np)
900 {
901         int start_index;
902         int idx;
903
904         // get the starting index to look from
905         start_index = NET_PLAYER_INDEX(np);
906         if(start_index > 0){            
907                 // look backwards
908                 for(idx=start_index-1; idx>=0; idx--){
909                         if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
910                                 return &Net_players[idx];
911                         }
912                 }
913         }
914         
915         return NULL;
916 }
917
918 // lookup the "next" player in the netplayer list, return null if not found
919 net_player *multi_pinfo_get_next_player(net_player *np)
920 {
921         int start_index;
922         int idx;
923
924         // get the starting index to look from
925         start_index = NET_PLAYER_INDEX(np);     
926         if(start_index < (MAX_PLAYERS - 1)){            
927                 // look forwards
928                 for(idx=start_index+1; idx<MAX_PLAYERS; idx++){
929                         if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
930                                 return &Net_players[idx];
931                         }
932                 }
933         }
934         
935         return NULL;
936 }