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