1 /***************************************************************************
2                           menu.c  -  description
3                              -------------------
4     begin                : Sat Jan 15 2000
5     copyright            : (C) 2000 by Perdig
6     email                : perdig@linuxbr.com.br
7 
8     $Id: menu.c,v 1.23 2001/01/11 15:28:03 perdig Exp $
9  ***************************************************************************/
10 
11 /***************************************************************************
12  *                                                                         *
13  *   This program is free software; you can redistribute it and/or modify  *
14  *   it under the terms of the GNU General Public License as published by  *
15  *   the Free Software Foundation; either version 2 of the License, or     *
16  *   (at your option) any later version.                                   *
17  *                                                                         *
18  ***************************************************************************/
19 
20 #include "config.h"
21 #include "menu.h"
22 #include "graphics.h"
23 #include "effects.h"
24 #include "game.h"
25 #include "level.h"
26 #include "score.h"
27 #include "dirent.h"
28 #ifdef USE_SOUND
29 #include "sound.h"
30 #endif
31 #include "limits.h"
32 #include <stdio.h>
33 #include <string.h>
34 
35 #define MENU_WINDOW_WIDTH (480 + 128)
36 #define MENU_WINDOW_HEIGHT (480)
37 
38 //#include "images/logo.xpm"
39 //#include "images/logocar.xpm"
40 //
41 /* Menu screen geometry
42  *  <---------- 614 --------->
43  * |-------------------------| /\
44  * ||-----|         |------| | ||
45  * ||     |         |      | | ||
46  * ||menu |         |      | | ||
47  * ||-----|         | help | |
48  * |                |      | | 482
49  * |                |------| |
50  * |                         | ||
51  * |                         | ||
52  * |                         | ||
53  * |                         | ||
54  * |                         | ||
55  * |                         | \/
56  * ---------------------------
57  * menu_window -> x = 10
58  *                y = 10
59  *                w = max textwidth + 32 + 8 + 2
60  *                h = (textheight+pad)*len + 8
61  *
62  * menu_text   -> x = 10 + 4 + 32 + 2
63  *                y = 10 + 4
64  *                w = max textwidth
65  *                h = max textheight
66  *
67  * help_window -> x = 614 - w - 10
68  *                y = 10
69  *                w = max textwidth + 8
70  *                h = max textheight + 8
71  *
72  * help_text   -> x = 614 - w - 10 + 4
73  *                y = 10 + 4
74  *                w = textwidth
75  *                h = textheight
76  *
77  * cursor      -> x = 10
78  *                y = 10 + (textheight+pad)*(pos+0.5) - CAROFF
79  *                w = 32
80  *                h = 32
81  *
82  * Splash Screen geometry
83  *
84  *  <---------- 614 --------->
85  * |-------------------------| /\
86  * ||------------|  |-------|| ||
87  * || info win   |  |       || ||
88  * ||------------|  | level || ||
89  * |                |       ||
90  * |                | desc  || 482
91  * |                |       ||
92  * ||----------|    |       || ||
93  * || help win |    |       || ||
94  * ||----------|    |-------|| ||
95  * |                         | ||
96  * ||----  progress bar  ---|| ||
97  * |                         | \/
98  * ---------------------------
99  *
100  * progress bar: x = 10
101  *               y = 482 - 10 - h
102  *               h = 32
103  *               w = 614 - 10 - 10
104  *
105  * level desc:   x = 614 - w - 10
106  *               y = 10
107  *               w = textwidth + 8
108  *               h = textheight + 8
109  *
110  * level desc text: x = 614 - w - 10 + 4
111  *                  y = 10 + 4
112  *                  w = textwidth
113  *                  h = textheight
114  *
115  * info win: x = 10
116  *           y = 10
117  *           w = textwidth + 8
118  *           h = textheight + 8
119  *
120  * info win text: x = 10 + 4
121  *                y = 10 + 4
122  *                w = textwidth
123  *                h = textheight
124  *
125  * help win: x = 10
126  *           y = level desc y + level desc h - h
127  *           w = textwidth + 8
128  *           h = textheight + 8
129  *
130  * help win text: x = help win x + 4
131  *                y = help win y + 4
132  *                w = textwidth
133  *                h = textheight
134  */
135 
136 #define splText(TEXT) do { \
137   draw_window(40, 179, 365, 12 + text_height(FONT_BIG) + 12); \
138   text(dbuffer(), 52, 191, TEXT, get_color(COLOR_TEXT), FONT_BIG); } while (0)
139 
140 #define splText2(TEXT) do { \
141   draw_window(95, 25 + 144 + 5 + 30, 430, 100); \
142   text(dbuffer(), 102, 239, TEXT, get_color(COLOR_TEXT), FONT_BIG); } while (0)
143 
144 Pixmap logo;
145 Pixmap logocar[2];
146 Pixmap logocar_mask[2];
147 GC bufGC;
148 GC dbufGC;
149 
150 // Score struct
151 extern scoreStruct score;
152 
153 // Splash struct
154 struct splash_struct spl;
155 
156 // Help and Info text
157 static char info[512];
158 
159 static char game_help[] = "*Game control*\nArrow keys: Move the car around\nSpace bar: Use smoke\nEscape: Quit level";
160 
161 static char menu_help[] = "*Menu control*\n\nArrow keys\n  Move the cursor around\nEnter key\n  Select an option\nESC key\n  Return to previous screen\n";
162 
163 // Size of sprite
164 extern int SPRITE_SIZE;
165 extern int TILE_WIDTH;
166 extern int TILE_HEIGHT;
167 
168 // Blend cache
169 blend_cache_t blend_cache;
170 
chooseLevel()171 char *chooseLevel() {
172   struct dirent **dirlist = NULL;
173   char **options = NULL;
174   char **info = NULL;
175   int levNum;
176   int n = 0, m = 0;
177 
178   // Search the dir
179   n = scandir("./maps", &dirlist, 0, alphasort);
180   if (n <= 0) {
181     hdbg("Can't find the maps directory");
182     return NULL;
183   }
184   // Create the string list
185   // Allocate memory
186   options = (char **)calloc(n, sizeof(char *));
187   while (n--) {
188     if (*dirlist[n]->d_name != '.' && strcmp(dirlist[n]->d_name, "CVS") != 0) {
189       options[m] = dirlist[n]->d_name;
190       m++;
191     }
192   }
193 
194   // Create the info list
195   info = (char **)calloc(m, sizeof(char *));
196   for (n = 0; n < m; n++) {
197     info[n] = levelDescription(options[n]);
198   }
199 
200   levNum = create_menu(options, info, m);
201 
202   for (n = 0; n < m; n++) {
203     free(info[n]);
204   }
205 
206   if (levNum == 255)
207     return NULL;
208   else
209     return options[levNum];
210 }
211 
chooseMap(int num)212 int chooseMap(int num) {
213   char **maps;
214   int a, len, cmd;
215   maps = (char **)calloc(num, sizeof(char *));
216   if (num < 10)
217     len = 1;
218   else if (num < 100)
219     len = 2;
220   else
221     len = 3;
222   for (a = 0; a < num; a++) {
223     maps[a] = (char *)malloc(sizeof(char) * len);
224     sprintf(maps[a], "%d", a+1);
225   }
226   cmd = create_menu(maps, NULL, num);
227   if (cmd == 255)
228     return -1;
229   else
230     return cmd;
231 }
232 
endScreen(levelStruct * level,int oldscore,int mode)233 void endScreen(levelStruct *level, int oldscore, int mode) {
234   char msg[512];
235   int pos = -1;
236   char *name;
237   int x = (WINDOW_WIDTH - 134)/2 - 175;
238   int y = (WINDOW_HEIGHT - 2)/2 - 65;
239   XImage *clean_window;
240 
241   // Victory message
242   if (mode == VICTORY) {
243     sprintf(msg, "Congratulations!\nYou won the %s!\n"
244       "Regular score: %9d\n"
245       "Winning bonus: %9d\n"
246       "Total:         %9d",
247     level->name, oldscore, score.value-oldscore, score.value);
248   }
249 
250   // Game over message
251   if (mode == GAME_OVER) {
252     sprintf(msg, "That's too bad! You lost!\n"
253       "Better luck next time!\n"
254       "Regular score: %9d\n"
255       "Winning bonus: %9d\n"
256       "Total:         %9d",
257     oldscore, score.value-oldscore, score.value);
258   }
259 
260   clean_window = get_image(dbuffer(), x, y, 350, 130);
261 
262   // Draw window
263   draw_window( x, y, 350, 130);
264   // Draw text
265   text(dbuffer(), x+12, y+12, msg, get_color(COLOR_TEXT), FONT_FIXED);
266   graphics_sync();
267   wait_key();
268 
269 
270 
271   // Now checks for the hiscore!
272   if (level->map && newRecord(level, &score)) {
273     ldbg("You got a new record!");
274     sound_select (16);
275     sound_volume (64);
276     sound_start ();
277     // Clean up
278     i_blit(clean_window, dbuffer(), x, y, 350, 130);
279     name = getName();
280     if (name != NULL && *name != 0)
281       pos = addRecord(level, &score, name);
282   }
283 
284   // Puts the window backs to its original size
285   if (WINDOW_WIDTH != MENU_WINDOW_WIDTH || WINDOW_HEIGHT != MENU_WINDOW_HEIGHT) {
286     resize_window(MENU_WINDOW_WIDTH, MENU_WINDOW_HEIGHT);
287   }
288 
289   ldbg("Position: %d", pos);
290   displayHiscores(pos, level, false);
291   return;
292 }
293 
getName()294 char *getName() {
295   int cmd = -1;
296   char temp[3];
297   char msg[256];
298   char *name = (char *)malloc(256 * sizeof(char));
299   int x = (WINDOW_WIDTH-134)/2 - 175;
300   int y = (WINDOW_HEIGHT-2)/2 - 65;
301   KeySym key;
302   XImage *window_img;
303   // If we don't do that, the window will get darker with
304   // every keystroke!
305   draw_window(x, y, 350, 130);
306   window_img = get_image(dbuffer(), x, y, 350, 130);
307   // Now window_img has a XImage of the window we want! How beautiful is that?
308   strcpy(name, "");
309   while (cmd < 0) {
310     strcpy(msg, "Congratulations!\nYou made into the hiscores!\nPlease enter your name:");
311     // Draw window
312     i_blit(window_img, dbuffer(), x, y, 350, 130);
313     text(dbuffer(), x+12, y+12, msg, get_color(COLOR_TEXT), FONT_FIXED);
314     text(dbuffer(), x+12, y+22+3*text_height(FONT_FIXED), name, get_color("#BB0000"), FONT_FIXED);
315     graphics_sync();
316     /* Get the player name */
317     key = wait_char(temp);
318     if (key == XK_Return)
319       break;
320     if (key == XK_Escape)
321       return NULL;
322     if (key == XK_Delete || key == XK_BackSpace) {
323       if (strlen(name) >= 1)
324         name[ strlen(name)-1 ] = 0;
325       continue;
326     }
327     if (temp)
328       strcat(name, temp);
329   }
330   return name;
331 }
332 
initIntro()333 void initIntro() {
334   //cleanScr();
335   text(dbuffer(), MENU_WINDOW_WIDTH/2-50, MENU_WINDOW_HEIGHT/2, "Hold on...",
336     get_color(COLOR_WHITE), FONT_BIG);
337   graphics_sync();
338   load_pixmap(&logocar[0], &logocar_mask[0], "images/logocar.xpm",
339     NULL, NULL);
340   graphics_sync();
341   load_pixmap(&logocar[1], &logocar_mask[1], "images/logocar2.xpm",
342     NULL, NULL);
343   graphics_sync();
344   load_pixmap(&logo, 0, "images/xrally.xpm", NULL, NULL );
345   graphics_sync();
346   strcpy(info, "");
347 }
348 
introAnim()349 void introAnim() {
350   s_blit(logo, dbuffer(), 0, 0, 614, 484);
351   wait_time(1000000); /* wait a few seconds so we can see the intro screen */
352 }
353 
showLogo()354 void showLogo() {
355   //m_blit(logo, 0,  dbuffer(), dbufGC, 604, 144, 5, 5);
356   //m_blit(logo, 0,  dbuffer(), dbufGC, 614, 484, 0, 0);
357   blit(logo, dbuffer(), 0, 0, 614, 484);
358 }
359 
360 #define CH (text_height(FONT_MEDIUM))
361 #define PADDING 4
362 #define CAROFF 18
draw_cursor(int pos)363 void draw_cursor(int pos) {
364   m_blit(logocar[0], logocar_mask[0], dbuffer(), 10 + 4 + 232*(pos/20), 14 + (CH+PADDING)*(2*(pos%20)+1)/2 - CAROFF, 32, 32);
365 }
366 
cleanScr()367 void cleanScr() {
368   rect(dbuffer(), 0, 0, MENU_WINDOW_WIDTH, MENU_WINDOW_HEIGHT, get_color(COLOR_BACK), 1);
369 }
370 
get_user_option()371 int get_user_option() {
372   int cmd = -1;
373   char **options;
374   char **help_msg;
375   options = (char **)calloc(3, sizeof(char *));
376   options[0] = (char *)malloc(16 * sizeof(char));
377   options[1] = (char *)malloc(16 * sizeof(char));
378   options[2] = (char *)malloc(16 * sizeof(char));
379   help_msg = (char **)calloc(3, sizeof(char *));
380   help_msg[0] = menu_help;
381   help_msg[1] = menu_help;
382   help_msg[2] = menu_help;
383   strcpy(options[0], "New Game");
384   strcpy(options[1], "View Hiscores");
385   strcpy(options[2], "Exit");
386   cmd = create_menu(options, help_msg, 3);
387   if (cmd == 255)
388     return 2;
389   else
390     return cmd;
391 }
392 
create_menu(char ** options,char ** info,int len)393 int create_menu(char **options, char **info, int len) {
394   int cmd = -1;
395   int currentOption = 0;
396   int cnt;
397   XColor color;
398   Pixmap menu_pixmap;
399   Pixmap help_pixmap;
400   XImage *help_image = NULL;
401   XImage *old_menu_image = NULL;
402   XImage *old_help_image = NULL;
403   int menu_x, menu_y, menu_w, menu_h;
404   int help_x, help_y, help_w, help_h, tmp_w, tmp_h;
405 
406   /* Geometry */
407   // menu
408   menu_x = 10;
409   menu_y = 10;
410   menu_w = 0;
411   menu_h = 0;
412   for (cnt = 0; cnt < len; cnt++) {
413     text_rectangle(options[cnt], FONT_MEDIUM, &tmp_w, &tmp_h);
414     if (tmp_w > menu_w)
415       menu_w = tmp_w;
416     if (tmp_h > menu_h)
417       menu_h = tmp_h;
418   }
419   menu_w+=42 + (len/20)*(menu_w+PADDING);
420   menu_h = (menu_h+PADDING)*(len>20?20:len) + 8;
421   // help
422   help_w = 0;
423   help_h = 0;
424   for (cnt = 0; cnt < len; cnt++) {
425     if (info)
426       text_rectangle(info[cnt], FONT_MEDIUM, &tmp_w, &tmp_h);
427     else
428       tmp_w = tmp_h = 0;
429     if (tmp_w > help_w)
430       help_w = tmp_w;
431     if (tmp_h > help_h)
432       help_h = tmp_h;
433   }
434   help_w+=8;
435   help_h+=8;
436   help_x = MENU_WINDOW_WIDTH - help_w - 10;
437   help_y = 10;
438 
439   color.red = color.blue = color.green = 0;
440   /* Creates the menu pixmap */
441   menu_pixmap = create_pixmap(menu_w, menu_h);
442   /* Background -> shaded image */
443   i_blit( blend_image(logo, menu_x, menu_y, menu_w, menu_h, &blend_cache),
444           menu_pixmap, 0, 0, menu_w, menu_h);
445   /* Text -> options list */
446   for (cnt = 0; cnt < len; cnt++) {
447     text(menu_pixmap, 32 + 4 + 2, 4 + (text_height(FONT_MEDIUM)+PADDING)*cnt, options[cnt], get_color(COLOR_TEXT), FONT_MEDIUM);
448   }
449   /* Creates the help pixmap */
450   help_pixmap = create_pixmap(help_w, help_h);
451   /* Background -> shaded image */
452   help_image = blend_image(logo, help_x , help_y, help_w, help_h, &blend_cache);
453   i_blit( help_image, help_pixmap, 0, 0, help_w, help_h);
454   /* Text -> infoText */
455   if (info)
456     text(help_pixmap, 4, 4, info[currentOption], get_color(COLOR_TEXT), FONT_MEDIUM);
457 
458   old_menu_image = get_image(logo, menu_x, menu_y, menu_w, menu_h);
459   old_help_image = get_image(logo, help_x , help_y, help_w, help_h);
460 
461   s_blit(menu_pixmap, dbuffer(), menu_x, menu_y, menu_w, menu_h);
462   s_blit(help_pixmap, dbuffer(), help_x, help_y, help_w, help_h);
463   // Main loop
464   while (cmd < 0) {
465     cleanScr();
466     showLogo();
467     i_blit( help_image, help_pixmap, 0, 0, help_w, help_h);
468     if (info)
469       text(help_pixmap, 4, 4, info[currentOption], get_color(COLOR_TEXT), FONT_MEDIUM);
470     blit(menu_pixmap, dbuffer(), menu_x, menu_y, menu_w, menu_h);
471     blit(help_pixmap, dbuffer(), help_x, help_y, help_w, help_h);
472     draw_cursor(currentOption);
473     //optionList(menu_pixmap, options, len);
474     graphics_sync();
475     if (!userOption(&currentOption)) {
476       cmd = currentOption;
477     }
478     currentOption = (currentOption < 0) ? 0 : currentOption;
479     currentOption = (currentOption > (len-1)) ? (len-1) : currentOption;
480   }
481   ldbg("Cmd: %d", cmd);
482   usi_blit(old_menu_image, dbuffer(), menu_x, menu_y, menu_w, menu_h);
483   usi_blit(old_help_image, dbuffer(), help_x, help_y, help_w, help_h);
484   return cmd;
485 }
486 
displayHiscores(int mark,levelStruct * level,bool loadAgain)487 void displayHiscores(int mark, levelStruct *level, bool loadAgain) {
488   char *levelFile = NULL;
489   char **lines;
490   int num, a;
491   int cmd = -1;
492   int limit = 10;
493   char pos[9] = "";
494   int offset = 0;
495   struct splash_struct splScr;
496   XImage *blend_hiscores;
497   XImage *old_blend_hiscores;
498   if (loadAgain) {
499     levelFile = chooseLevel();
500     if (levelFile == NULL)
501       return;
502     sprintf(splScr.txt, "Loading hiscores for %s", levelFile);
503     splScr.n = 9;
504     splScr.mode = 2;
505     splash(splScr, levelFile);
506     if (!levelFile)
507       return;
508     if (!quickLoadLevel(level, levelFile)) {
509       hdbg("Can't load level!");
510       return;
511     }
512   }
513   lines = listRecords(level);
514   if (!lines) {
515     ldbg("No record with that name!");
516     num = 0;
517   } else {
518     num = (int)*lines[0];
519   }
520   if (num == 0) {
521     ldbg("No record with that name!");
522   }
523   lines++;
524   limit = (num < 10) ? num : 10;
525   blend_hiscores = blend_image(logo, 5 - 3, 179 - 3, 600,
526                   (limit != 0 ? limit * 30 : 30), &blend_cache);
527   old_blend_hiscores = get_image(logo, 5 - 3, 179 - 3, 600,
528                   (limit != 0 ? limit * 30 : 30));
529   cleanScr();
530   showLogo();
531   graphics_sync();
532   si_blit(blend_hiscores, dbuffer(), 5 - 3, 179 - 3, 600, (limit != 0 ? limit * 30 : 30));
533   while (cmd < 0) {
534     cleanScr();
535     showLogo();
536     i_blit(blend_hiscores, dbuffer(), 5 - 3, 179 - 3, 600, (limit != 0 ? limit * 30 : 30));
537     for (a = 0; a < limit; a++) {
538       sprintf(pos, "%2d-", a+offset+1);
539       if ((a+offset) != mark) {
540         text(dbuffer(), 57, 179+30*(a%10), lines[a+offset], get_color(COLOR_TEXT), FONT_MEDIUM);
541         text(dbuffer(), 5, 179+30*(a%10), pos, get_color(COLOR_TEXT), FONT_MEDIUM);
542       }
543       else {
544         text(dbuffer(), 57, 179+30*(a%10), lines[a+offset], get_color("#BB0000"), FONT_MEDIUM);
545         text(dbuffer(), 5, 179+30*(a%10), pos, get_color("#BB0000"), FONT_MEDIUM);
546       }
547     }
548     if (num == 0) {
549       text(dbuffer(), 5, 179, "This level doesn't have any Hiscore", get_color(COLOR_TEXT), FONT_MEDIUM);
550     }
551 
552     graphics_sync();
553     if (!userOption(&offset)) {
554       usi_blit(old_blend_hiscores, dbuffer(), 5 - 3, 179 - 3, 600, (limit != 0 ? limit * 30 : 30));
555       return;
556     }
557     offset = (offset > (num-10)) ? num - 10 : offset;
558     offset = (offset < 0) ? 0 : offset;
559   }
560   usi_blit(old_blend_hiscores, dbuffer(), 5 - 3, 179 - 3, 600, (limit != 0 ? limit * 30 : 30));
561   return;
562 }
563 
userOption(int * cmd)564 bool userOption(int *cmd) {
565     KeySym key;
566     int a;
567     a = *cmd;
568     while (a == *cmd) {
569       key = wait_key();
570       switch(key) {
571         case(XK_KP_8):
572         case(XK_Up):
573         case(XK_KP_Up):
574           *cmd-=1;
575           return true;
576           break;
577         case(XK_KP_4):
578         case(XK_Left):
579         case(XK_KP_Left):
580           *cmd-=10;
581           return true;
582           break;
583         case(XK_KP_2):
584         case(XK_Down):
585         case(XK_KP_Down):
586           *cmd+=1;
587           return true;
588           break;
589         case(XK_KP_6):
590         case(XK_Right):
591         case(XK_KP_Right):
592           *cmd+=10;
593           return true;
594           break;
595         case(XK_KP_Enter):
596         case(XK_Return):
597           return false;
598           break;
599         case(XK_Escape):
600         case 'Q':
601         case 'q':
602           *cmd=255;
603           return false;
604         default:
605           break;
606       }
607     }
608 
609     return true;
610 }
611 
splash(struct splash_struct spl_arg,char * filename)612 void splash(struct splash_struct spl_arg, char *filename) {
613   strncpy(spl.txt, spl_arg.txt, 256);
614   spl.info = levelDescription(filename);
615   spl.n = spl_arg.n;
616   spl.mode = spl_arg.mode;
617   spl.cur = 0;
618   update_splash();
619 }
620 
update_splash_hiscore()621 void update_splash_hiscore() {
622   splText2(spl.txt);
623   rect(dbuffer(), 3, 387, 608, 36, get_color("#AA6800"), 1);
624   rect(dbuffer(), 5, 389, (572*spl.cur)/spl.n, 32, get_color("#86A886"), 1);
625   m_blit(logocar[0], logocar_mask[0], dbuffer(), 5 + (572*spl.cur)/spl.n, 389, 32, 32);
626 }
627 
update_splash()628 void update_splash() {
629   XImage *blend_info;
630   XImage *blend_help;
631   XImage *blend_desc;
632   int info_x, info_y, info_w, info_h;
633   int help_x, help_y, help_w, help_h;
634   int desc_x, desc_y, desc_w, desc_h;
635   cleanScr();
636   showLogo();
637   if (spl.mode == 2) {
638     update_splash_hiscore();
639   } else {
640     // Info window
641     info_x = 10;
642     text_rectangle(spl.txt, FONT_BIG, &info_w, &info_h);
643     info_w+=8;
644     info_h+=8;
645     info_y = 10;
646     // Desc window
647     desc_y = 10;
648     text_rectangle(spl.info, FONT_MEDIUM, &desc_w, &desc_h);
649     desc_w+=8;
650     desc_h+=8;
651     desc_x = 614 - desc_w - 10;
652     // Help window
653     help_x = 10;
654     text_rectangle(game_help, FONT_MEDIUM, &help_w, &help_h);
655     help_w+=8;
656     help_h+=8;
657     help_y = desc_y + desc_h - help_h;
658     // Get windows
659     blend_info = blend_image(logo, info_x, info_y, info_w, info_h, &blend_cache);
660     blend_help = blend_image(logo, help_x, help_y, help_w, help_h, &blend_cache);
661     blend_desc = blend_image(logo, desc_x, desc_y, desc_w, desc_h, &blend_cache);
662     // Draw windows
663     i_blit(blend_info, dbuffer(), info_x, info_y, info_w, info_h);
664     i_blit(blend_help, dbuffer(), help_x, help_y, help_w, help_h);
665     i_blit(blend_desc, dbuffer(), desc_x, desc_y, desc_w, desc_h);
666     // Draw texts
667     text(dbuffer(), info_x + 4, info_y + 4, spl.txt, get_color(COLOR_TEXT), FONT_BIG);
668     text(dbuffer(), help_x + 4, help_y + 4, game_help,  get_color(COLOR_TEXT), FONT_MEDIUM);
669     text(dbuffer(), desc_x + 4, desc_y + 4, spl.info, get_color(COLOR_TEXT), FONT_MEDIUM);
670     // Lower sound
671     #ifdef USE_SOUND
672     sound_changevol (-4);
673     #endif
674     // Draw progress bar
675     rect(dbuffer(), 10, 482 - 10 - 32, 614 - 10 - 10, 32, get_color("#AA6800"), 1);
676     rect(dbuffer(), 10, 482 - 10 - 32, ((614 - 10 - 10)*spl.cur)/spl.n, 32, get_color(COLOR_GREEN), 1);
677     m_blit(logocar[0], logocar_mask[0], dbuffer(), 10 + ((614-10-10)*spl.cur)/spl.n, 482-10-32, 32, 32);
678   }
679   graphics_sync();
680   spl.cur++;
681   if (spl.cur > spl.n)
682     spl.cur = spl.n;
683 }
684 
levelDescription(char * level)685 char *levelDescription(char *level) {
686   char *desc;
687   char livStr[16] = "";
688   char bonStr[64] = "";
689   levelStruct lev;
690   desc = (char *)malloc(512 * sizeof(char));
691   quickLoadLevel(&lev, level);
692   if (lev.lives < 0) {
693     sprintf(livStr, "No Lives!");
694   }
695   else if (lev.lives == 1) {
696     sprintf(livStr, "1 live");
697   }
698   else {
699     sprintf(livStr, "%d lives", lev.lives);
700   }
701 
702   if (lev.livesbonus < 0 && lev.lives >= 0) {
703     sprintf(bonStr, "%d pts / lives\nbeyond %d at\nend of level", -lev.livesbonus, lev.lives);
704   }
705   else if (lev.livesbonus >= 0) {
706     sprintf(bonStr, "%d pts / live at\nend of level", lev.livesbonus);
707   }
708 
709   sprintf(desc, "**%s**\n\nTileset: %s\n%d map%c\n%s\n%d pts / extra live\n%s\n\n*First map:*\nPlayer speed: %d\nEnemy speed: %d\n", lev.name, lev.tileset, lev.number, (lev.number>1)?'s':' ', livStr, lev.extra, bonStr, lev.map[0].carVel, lev.map[0].aiVel);
710 
711   return desc;
712 }
713