2 * $Logfile: /Freespace2/code/Stats/Medals.cpp $
8 * Revision 1.5 2002/05/28 08:52:03 relnev
9 * implemented two assembly stubs.
11 * cleaned up a few warnings.
13 * added a little demo hackery to make it progress a little farther.
15 * Revision 1.4 2002/05/28 04:56:51 theoddone33
16 * runs a little bit now
18 * Revision 1.3 2002/05/26 20:22:48 theoddone33
19 * Most of network/ works
21 * Revision 1.2 2002/05/04 04:36:56 theoddone33
22 * More changes, took out a lot of the sound stuff which will bite later but
25 * Revision 1.1.1.1 2002/05/03 03:28:11 root
29 * 12 10/29/99 10:40p Jefff
30 * hack to make german medal names display without actually changing them
32 * 11 9/02/99 3:41p Jefff
33 * changed badge voice handling to be similar to promotion voice handling
35 * 10 8/26/99 8:49p Jefff
36 * Updated medals screen and about everything that ever touches medals in
37 * one way or another. Sheesh.
39 * 9 7/16/99 1:50p Dave
40 * 8 bit aabitmaps. yay.
42 * 8 3/19/99 9:51a Dave
43 * Checkin to repair massive source safe crash. Also added support for
44 * pof-style nebulae, and some new weapons code.
46 * 8 3/15/99 10:29a Neilk
48 * 7 1/30/99 5:08p Dave
49 * More new hi-res stuff.Support for nice D3D textures.
51 * 6 12/18/98 1:13a Dave
52 * Rough 1024x768 support for Direct3D. Proper detection and usage through
55 * 5 11/30/98 1:07p Dave
56 * 16 bit conversion, first run.
58 * 4 10/23/98 3:51p Dave
59 * Full support for tstrings.tbl and foreign languages. All that remains
60 * is to make it active in Fred.
62 * 3 10/13/98 9:29a Dave
63 * Started neatening up freespace.h. Many variables renamed and
64 * reorganized. Added AlphaColors.[h,cpp]
66 * 2 10/07/98 10:54a Dave
69 * 1 10/07/98 10:51a Dave
71 * 26 6/13/98 3:18p Hoffoss
72 * NOX()ed out a bunch of strings that shouldn't be translated.
74 * 25 6/01/98 11:43a John
75 * JAS & MK: Classified all strings for localization.
77 * 24 5/01/98 12:34p John
78 * Added code to force FreeSpace to run in the same dir as exe and made
79 * all the parse error messages a little nicer.
81 * 23 4/27/98 3:13p Allender
82 * make ctrl-enter work on medals screen
84 * 22 4/23/98 8:27p Allender
85 * basic support for cutscene playback. Into movie code in place. Tech
86 * room can view cutscenes stored in CDROM_dir variable
88 * 21 4/12/98 8:30p Allender
89 * minor medal changes to show number of medals if > 1
91 * 20 4/10/98 4:51p Hoffoss
92 * Made several changes related to tooltips.
94 * 19 3/18/98 12:03p John
95 * Marked all the new strings as externalized or not.
97 * 18 3/11/98 5:02p Dave
98 * Put in code to support new medals artwork. Assorted multiplayer bug
101 * 17 3/07/98 5:44p Dave
102 * Finished player info popup. Ironed out a few todo bugs.
104 * 16 3/05/98 5:11p Allender
105 * fix up medals screen (again). Don't do state transition when viewing
106 * medals from debriefing screen.
108 * 15 3/05/98 2:32p Hoffoss
109 * Renamed Rank_bitmap to Rank_bm so it isn't named the same as the
110 * variable in the debrief screen which confuses the debugger.
112 * 14 2/22/98 2:48p John
113 * More String Externalization Classification
115 * 13 2/09/98 5:21p Hoffoss
116 * Made exit from medals screen to previous screen (instead of assuming
117 * it's the barracks) work.
119 * 12 1/27/98 4:23p Allender
120 * enhanced internal scoring mechanisms.
122 * 11 11/12/97 4:40p Dave
123 * Put in multiplayer campaign support parsing, loading and saving. Made
124 * command-line variables better named. Changed some things on the initial
125 * pilot select screen.
127 * 10 11/12/97 9:30a Dave
128 * Fixed rank insignia tooltip not showing up.
130 * 9 11/06/97 4:39p Allender
131 * a ton of medal work. Removed an uneeded elemen in the scoring
132 * structure. Fix up medals screen to apprioriate display medals (after
133 * mask was changed). Fix Fred to only display medals which may actually
134 * be granted. Added image_filename to player struct for Jason Hoffoss
136 * 8 11/05/97 4:43p Allender
137 * reworked medal/rank system to read all data from tables. Made Fred
138 * read medals.tbl. Changed ai-warp to ai-warp-out which doesn't require
139 * waypoint for activation
147 #include "snazzyui.h"
149 #include "gamesequence.h"
150 #include "animplay.h"
152 #include "freespace.h"
160 #include "alphacolors.h"
161 #include "localize.h"
163 //#define MAX_MEDAL_TYPES 63 // the # of medals which exist so far
166 #define CALLSIGN_X 198
167 #define CALLSIGN_Y 80
168 #define CALLSIGN_W (439-CALLSIGN_X)
169 #define CALLSIGN_H (116-CALLSIGN_Y)
172 // define for the medal information
173 medal_stuff Medals[NUM_MEDALS];
174 badge_stuff Badge_info[MAX_BADGES];
176 // holds indices into Medals array of the badges for # kills
177 int Badge_index[MAX_BADGES];
179 // the rank section of the screen
180 #define RANK_MEDAL_REGION 12 // region number of the rank medal
182 #warning Find real FS2_DEMO spot for medals
183 // coords for indiv medal bitmaps
184 int Medal_coords[GR_NUM_RESOLUTIONS][NUM_MEDALS][2] = {
186 { 89, 47 }, // eps. peg. lib
187 { 486, 47 }, // imp. order o' vasuda
188 { 129, 130 }, // dist flying cross
189 { 208, 132 }, // soc service
190 { 361, 131 }, // dist intel cross
191 { 439, 130 }, // order of galatea
192 { 64, 234 }, // meritorious unit comm.
193 { 153, 234 }, // medal of valor
194 { 239, 241 }, // gtva leg of honor
195 { 326, 240 }, // allied defense citation
196 { 411, 234 }, // neb campaign victory
197 { 494, 234 }, // ntf campaign victory
199 { 283, 91 }, // wings
200 { 372, 76 }, // bronze kills badge
201 { 403, 76 }, // silver kills badge
203 { 435, 76 }, // gold kills badge
204 { 300, 152 }, // SOC unit crest
208 { 143, 75 }, // eps. peg. lib
209 { 777, 75 }, // imp. order o' vasuda
210 { 206, 208 }, // dist flying cross
211 { 333, 212 }, // soc service
212 { 578, 210 }, // dist intel cross
213 { 703, 208 }, // order of galatea
214 { 103, 374 }, // meritorious unit comm.
215 { 245, 374 }, // medal of valor
216 { 383, 386 }, // gtva leg of honor
217 { 522, 384 }, // allied defense citation
218 { 658, 374 }, // neb campaign victory
219 { 790, 374 }, // ntf campaign victory
220 { 302, 128 }, // rank
221 { 453, 146 }, // wings
222 { 595, 121 }, // bronze kills badge
223 { 646, 121 }, // silver kills badge
225 { 696, 121 }, // gold kills badge
226 { 480, 244 }, // SOC unit crest
231 // coords for the medal title
232 static int Medals_label_coords[GR_NUM_RESOLUTIONS][3] = {
233 { 241, 458, 300 }, // GR_640 x, y, w
234 { 386, 734, 480 } // GR_1024 x, y, w
237 #define MEDALS_NUM_BUTTONS 1
238 #define MEDALS_EXIT 0
239 ui_button_info Medals_buttons[GR_NUM_RESOLUTIONS][MEDALS_NUM_BUTTONS] = {
241 ui_button_info("MEB_18", 574, 432, -1, -1, 18),
244 ui_button_info("2_MEB_18", 919, 691, -1, -1, 18),
248 #define MEDALS_NUM_TEXT 1
249 UI_XSTR Medals_text[GR_NUM_RESOLUTIONS][MEDALS_NUM_TEXT] = {
251 {"Exit", 1466, 587, 416, UI_XSTR_COLOR_PINK, -1, &Medals_buttons[GR_640][MEDALS_EXIT].button },
254 {"Exit", 1466, 943, 673, UI_XSTR_COLOR_PINK, -1, &Medals_buttons[GR_1024][MEDALS_EXIT].button },
258 static char* Medals_background_filename[GR_NUM_RESOLUTIONS] = {
259 "MedalsDisplayEmpty",
260 "2_MedalsDisplayEmpty"
263 static char* Medals_mask_filename[GR_NUM_RESOLUTIONS] = {
268 static int Medals_callsign_y[GR_NUM_RESOLUTIONS] = {
272 scoring_struct *Player_score=NULL;
275 player *Medals_player;
277 // -----------------------------------------------------------------------------
278 // Main medals screen state
280 #define NUM_MEDAL_REGIONS NUM_MEDALS + 1 // the extra one is for the rank medal
282 static bitmap *Medals_mask;
283 int Medals_mask_w, Medals_mask_h;
284 static int Medal_palette; // Medal palette bitmap
285 static int Medals_bitmap_mask; // the mask for the medal case
286 static int Medals_bitmap; // the medal case itself
287 static int Medal_bitmaps[NUM_MEDALS]; // bitmaps for the individual medals
288 static int Rank_bm; // bitmap for the rank medal
290 static MENU_REGION Medal_regions[NUM_MEDAL_REGIONS]; // a semi-hack for now because we only have 4 medals, but we also include the close button
292 static UI_WINDOW Medals_window;
294 //#define MAX_MEDALS_BUTTONS 1
295 //#define MEDAL_BUTTON_EXIT 0
296 //static UI_BUTTON Medal_buttons[MAX_MEDALS_BUTTONS];
298 /*static char *Medal_button_names[MAX_MEDALS_BUTTONS] = {
305 static int Medal_button_coords[MAX_MEDALS_BUTTONS][2] = {
308 static int Medal_button_masks[MAX_MEDALS_BUTTONS] = {
314 #define MEDAL_BITMAP_INIT (1<<0)
315 #define MASK_BITMAP_INIT (1<<1)
318 void parse_medal_tbl()
320 int rval, num_medals, i, bi;
322 if ((rval = setjmp(parse_abort)) != 0) {
323 Error(LOCATION, "Error parsing 'medals.tbl'\r\nError code = %i.\r\n", rval);
329 read_file_text("medals.tbl");
333 // parse in all the rank names
336 required_string("#Medals");
337 while ( required_string_either("#End", "$Name:") ) {
338 Assert ( num_medals < NUM_MEDALS);
339 required_string("$Name:");
340 stuff_string( Medals[num_medals].name, F_NAME, NULL );
341 required_string("$Bitmap:");
342 stuff_string( Medals[num_medals].bitmap, F_NAME, NULL );
343 required_string("$Num mods:");
344 stuff_int( &Medals[num_medals].num_versions);
346 // some medals are based on kill counts. When string +Num Kills: is present, we know that
347 // this medal is a badge and should be treated specially
348 Medals[num_medals].kills_needed = 0;
349 if ( optional_string("+Num Kills:") ) {
350 char buf[MULTITEXT_LENGTH + 1];
352 Assert( bi < MAX_BADGES );
353 stuff_int( &Medals[num_medals].kills_needed );
354 Badge_index[bi] = num_medals;
356 #warning FS2_DEMO HACK: Wavefile 1/2: wave1? wave2?
357 required_string("$Wavefile 1:");
358 stuff_string(Badge_info[bi].voice_base, F_NAME, NULL, MAX_FILENAME_LEN);
359 required_string("$Wavefile 2:");
360 stuff_string(Badge_info[bi].voice_base, F_NAME, NULL, MAX_FILENAME_LEN);
361 //stuff_string(Badge_info[bi].wave2, F_NAME, NULL, MAX_FILENAME_LEN);
363 required_string("$Wavefile Base:");
364 stuff_string(Badge_info[bi].voice_base, F_NAME, NULL, MAX_FILENAME_LEN);
367 required_string("$Promotion Text:");
368 stuff_string(buf, F_MULTITEXT, NULL);
369 Badge_info[bi].promotion_text = strdup(buf);
377 required_string("#End");
378 Assert( num_medals == NUM_MEDALS );
380 // be sure that the badges kill numbers show up in order
381 for (i = 0; i < MAX_BADGES-1; i++ ) {
382 if ( Medals[Badge_index[i]].kills_needed >= Medals[Badge_index[i+1]].kills_needed ){
383 Error(LOCATION, "Badges must appear sorted by lowest kill # first in medals.tbl\nFind Allender for most information.");
387 // close localization
391 void medal_main_init(player *pl, int mode)
398 Player_score = &Medals_player->stats;
401 if(Cmdline_gimme_all_medals){
403 for(idx=0; idx < NUM_MEDALS; idx++){
404 Medals_player->stats.medals[idx] = 1;
412 Medals_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
414 // create the interface buttons
415 for (idx=0; idx<MEDALS_NUM_BUTTONS; idx++) {
417 Medals_buttons[gr_screen.res][idx].button.create(&Medals_window, "", Medals_buttons[gr_screen.res][idx].x, Medals_buttons[gr_screen.res][idx].y, 1, 1, 0, 1);
419 // set the sound to play when highlighted
420 Medals_buttons[gr_screen.res][idx].button.set_highlight_action(common_play_highlight_sound);
422 // set the ani for the button
423 Medals_buttons[gr_screen.res][idx].button.set_bmaps(Medals_buttons[gr_screen.res][idx].filename);
426 Medals_buttons[gr_screen.res][idx].button.link_hotspot(Medals_buttons[gr_screen.res][idx].hotspot);
430 for (idx=0; idx<MEDALS_NUM_TEXT; idx++) {
431 Medals_window.add_XSTR(&Medals_text[gr_screen.res][idx]);
437 //init_medal_palette();
439 Medals_bitmap = bm_load(Medals_background_filename[gr_screen.res]);
440 if (Medals_bitmap < 0) {
441 Error(LOCATION, "Error loading medal background bitmap %s", Medals_background_filename[gr_screen.res]);
443 Init_flags |= MEDAL_BITMAP_INIT;
449 Medals_bitmap_mask = bm_load(Medals_mask_filename[gr_screen.res]);
450 if(Medals_bitmap_mask < 0){
451 Error(LOCATION, "Error loading medal mask file %s", Medals_mask_filename[gr_screen.res]);
453 Init_flags |= MASK_BITMAP_INIT;
454 Medals_mask = bm_lock(Medals_bitmap_mask, 8, BMP_AABITMAP);
455 bm_get_info(Medals_bitmap_mask, &Medals_mask_w, &Medals_mask_h);
457 init_medal_bitmaps();
458 init_snazzy_regions();
460 gr_set_color_fast(&Color_normal);
462 Medals_window.set_mask_bmap(Medals_mask_filename[gr_screen.res]);
465 // this is just a hack to display translated names without actually changing the names,
466 // which would break stuff
467 void medals_translate_name(char *name, int max_len)
469 if (!strcmp(name, "Epsilon Pegasi Liberation")) {
470 strncpy(name, "Epsilon Pegasi Befreiungsmedaille", max_len);
472 } else if (!strcmp(name, "Imperial Order of Vasuda")) {
473 strncpy(name, "Imperialer Orden von Vasuda ", max_len);
475 } else if (!strcmp(name, "Distinguished Flying Cross")) {
476 strncpy(name, "Fliegerkreuz Erster Klasse", max_len);
478 } else if (!strcmp(name, "SOC Service Medallion")) {
479 strncpy(name, "SEK-Dienstmedaille ", max_len);
481 } else if (!strcmp(name, "Intelligence Cross")) {
482 strncpy(name, "Geheimdienstkreuz am Bande", max_len);
484 } else if (!strcmp(name, "Order of Galatea")) {
485 strncpy(name, "Orden von Galatea ", max_len);
487 } else if (!strcmp(name, "Meritorious Unit Commendation")) {
488 strncpy(name, "Ehrenspange der Allianz", max_len);
490 } else if (!strcmp(name, "Medal of Valor")) {
491 strncpy(name, "Tapferkeitsmedaille ", max_len);
493 } else if (!strcmp(name, "GTVA Legion of Honor")) {
494 strncpy(name, "Orden der GTVA-Ehrenlegion", max_len);
496 } else if (!strcmp(name, "Allied Defense Citation")) {
497 strncpy(name, "Alliierte Abwehrspange ", max_len);
499 } else if (!strcmp(name, "Nebula Campaign Victory Star")) {
500 strncpy(name, "Nebel-Siegesstern", max_len);
502 } else if (!strcmp(name, "NTF Campaign Victory Star")) {
503 strncpy(name, "NTF-Siegesstern ", max_len);
505 } else if (!strcmp(name, "Rank")) {
506 strncpy(name, "Dienstgrad", max_len);
508 } else if (!strcmp(name, "Wings")) {
509 strncpy(name, "Fliegerspange", max_len);
511 } else if (!strcmp(name, "Ace")) {
512 strncpy(name, "Flieger-As", max_len);
514 } else if (!strcmp(name, "Double Ace")) {
515 strncpy(name, "Doppel-As ", max_len);
517 } else if (!strcmp(name, "Triple Ace")) {
518 strncpy(name, "Dreifach-As ", max_len);
520 } else if (!strcmp(name, "SOC Unit Crest")) {
521 strncpy(name, "SEK-Abzeichen ", max_len);
525 void blit_label(char *label, int *coords, int num)
530 gr_set_color_fast(&Color_bright);
532 // translate medal names before displaying
533 // cant translate in table cuz the names are used in comparisons
535 char translated_label[256];
536 strncpy(translated_label, label, 256);
537 medals_translate_name(translated_label, 256);
539 // set correct string
541 sprintf( text, NOX("%s (%d)"), translated_label, num );
543 sprintf( text, "%s", translated_label );
546 // set correct string
548 sprintf( text, NOX("%s (%d)"), label, num );
550 sprintf( text, "%s", label );
554 // find correct coords
555 gr_get_string_size(&sw, NULL, text);
556 x = Medals_label_coords[gr_screen.res][0] + (Medals_label_coords[gr_screen.res][2] - sw) / 2;
557 y = Medals_label_coords[gr_screen.res][1];
560 gr_string(x, y, text);
565 gr_set_color_fast(&Color_normal);
567 // nothing special, just do it.
568 gr_string(0x8000, Medals_callsign_y[gr_screen.res], Medals_player->callsign);
573 int region,selected, k;
575 k = Medals_window.process();
577 // process an exit command
578 if ((k == KEY_ESC) && (Medals_mode == MM_NORMAL)) {
579 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
582 // draw the background medal display case
584 GR_MAYBE_CLEAR_RES(Medals_bitmap);
585 if(Medals_bitmap != -1){
586 gr_set_bitmap(Medals_bitmap);
590 // check to see if a button was pressed
591 if( (k == (KEY_CTRLED|KEY_ENTER)) || (Medals_buttons[gr_screen.res][MEDALS_EXIT].button.pressed()) ) {
592 gamesnd_play_iface(SND_COMMIT_PRESSED);
593 if(Medals_mode == MM_NORMAL){
594 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
596 // any calling popup function will know to close the screen down
601 // blit medals also takes care of blitting the rank insignia
605 region = snazzy_menu_do((ubyte*)Medals_mask->data, Medals_mask_w, Medals_mask_h, NUM_MEDAL_REGIONS, Medal_regions, &selected);
608 if (Medals_mode == MM_NORMAL) {
609 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
611 // any calling popup function will know to close the screen down
616 case RANK_MEDAL_REGION :
617 blit_label(Ranks[Player_score->rank].name, &Medal_coords[gr_screen.res][region][0], 1);
624 if (Player_score->medals[region] > 0){
625 blit_label(Medals[region].name, &Medal_coords[gr_screen.res][region][0], Player_score->medals[region] );
630 Medals_window.draw();
637 void medal_main_close()
640 if (Init_flags & MEDAL_BITMAP_INIT)
641 bm_unload(Medals_bitmap);
643 if (Init_flags & MASK_BITMAP_INIT) {
644 bm_unlock(Medals_bitmap_mask);
645 bm_unload(Medals_bitmap_mask);
648 for (idx=0; idx < NUM_MEDALS; idx++) {
649 if (Medal_bitmaps[idx] > -1){
650 bm_unload(Medal_bitmaps[idx]);
655 Medals_window.destroy();
657 palette_restore_palette();
661 void init_medal_palette()
663 Medal_palette = bm_load("MedalsPalette.pcx");
664 if(Medal_palette > -1){
665 #ifndef HARDWARE_ONLY
666 palette_use_bm_palette(Medal_palette);
672 // function to load in the medals for this player. It loads medals that the player has (known
673 // by whether or not a non-zero number is present in the player's medal array), then loads the
676 void init_medal_bitmaps()
679 Assert(Player_score);
681 for (idx=0; idx<NUM_MEDALS; idx++) {
682 Medal_bitmaps[idx] = -1;
683 if (Player_score->medals[idx] > 0) {
685 char filename[NAME_LENGTH], base[NAME_LENGTH];
687 // possibly load a different filename that is specified by the bitmap filename
688 // for this medal. if the player has > 1 of these types of medals, then determien
689 // which of the possible version to use based on the player's count of this medal
690 strcpy( filename, Medals[idx].bitmap );
694 _splitpath( filename, NULL, NULL, base, NULL );
697 num_medals = Player_score->medals[idx];
699 // can't display more than the maximum number of version for this medal
700 if ( num_medals > Medals[idx].num_versions )
701 num_medals = Medals[idx].num_versions;
703 if ( num_medals > 1 ) {
704 // append the proper character onto the end of the medal filename. Base version
705 // has no character. next version is a, then b, etc.
706 sprintf( base, "%s%c", base, (num_medals-2)+'a');
710 if (gr_screen.res == GR_1024) {
711 sprintf( filename, "2_%s", base );
714 // base now contains the actual medal bitmap filename needed to load
715 // we don't need to pass extension to bm_load anymore, so just use the basename
717 Medal_bitmaps[idx] = bm_load( filename );
718 Assert( Medal_bitmaps[idx] != -1 );
722 // load up rank insignia
723 if (gr_screen.res == GR_1024) {
724 char filename[NAME_LENGTH];
725 sprintf(filename, "2_%s", Ranks[Player_score->rank].bitmap);
726 Rank_bm = bm_load(filename);
728 Rank_bm = bm_load(Ranks[Player_score->rank].bitmap);
732 void init_snazzy_regions()
736 // snazzy regions for the medals/ranks, etc.
737 for (idx=0; idx<NUM_MEDALS; idx++) {
738 if (idx == RANK_MEDAL_REGION)
741 snazzy_menu_add_region(&Medal_regions[idx], "", idx, 0);
744 // add the rank medal region
745 snazzy_menu_add_region(&Medal_regions[RANK_MEDAL_REGION], "", RANK_MEDAL_REGION,0);
749 // blit the medals -- this includes the rank insignia
754 for (idx=0; idx<NUM_MEDALS; idx++) {
755 if (Player_score->medals[idx] > 0) {
756 gr_set_bitmap(Medal_bitmaps[idx]);
757 gr_bitmap(Medal_coords[gr_screen.res][idx][0], Medal_coords[gr_screen.res][idx][1]);
761 // now blit rank, since that "medal" doesnt get loaded (or drawn) the normal way
762 gr_set_bitmap(Rank_bm);
763 gr_bitmap(Medal_coords[gr_screen.res][RANK_MEDAL_REGION][0], Medal_coords[gr_screen.res][RANK_MEDAL_REGION][1]);