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