1 /* Tower Toppler - Nebulus
2  * Copyright (C) 2000-2012  Andreas R�ver
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13 
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  */
18 
19 #include "menu.h"
20 
21 #include "game.h"
22 #include "points.h"
23 #include "bonus.h"
24 #include "sprites.h"
25 #include "archi.h"
26 #include "screen.h"
27 #include "keyb.h"
28 #include "decl.h"
29 #include "level.h"
30 #include "sound.h"
31 #include "leveledit.h"
32 #include "stars.h"
33 #include "robots.h"
34 #include "configuration.h"
35 #include "highscore.h"
36 
37 #include <SDL_endian.h>
38 
39 #include <stdlib.h>
40 #include <string.h>
41 
42 #define NUMHISCORES 10
43 #define HISCORES_PER_PAGE 5
44 
45 static unsigned short menupicture, titledata;
46 static unsigned char currentmission = 0;
47 
men_reload_sprites(Uint8 what)48 static void men_reload_sprites(Uint8 what) {
49   Uint8 pal[3*256];
50 
51   if (what & 1) {
52     file fi(dataarchive, menudat);
53 
54     scr_read_palette(&fi, pal);
55     menupicture = scr_loadsprites(&restsprites, &fi, 1, 640, 480, false, pal, 0);
56   }
57 
58   if (what & 2) {
59     file fi(dataarchive, titledat);
60 
61     scr_read_palette(&fi, pal);
62     titledata = scr_loadsprites(&fontsprites, &fi, 1, SPR_TITLEWID, SPR_TITLEHEI, true, pal, config.use_alpha_font());
63   }
64 }
65 
66 #ifdef GAME_DEBUG_KEYS
debug_menu_extralife(_menusystem * ms)67 static const char *debug_menu_extralife(_menusystem *ms) {
68   if (ms) lives_add();
69   return _("Extra Life");
70 }
71 
debug_menu_extrascore(_menusystem * ms)72 static const char *debug_menu_extrascore(_menusystem *ms) {
73   if (ms) pts_add(200);
74   return _("+200 Points");
75 }
76 #endif /* GAME_DEBUG_KEYS */
77 
78 static const char *
men_main_background_proc(_menusystem * ms)79 men_main_background_proc(_menusystem *ms)
80 {
81   if (ms) {
82     scr_blit(restsprites.data(menupicture), 0, 0);
83     scr_blit(fontsprites.data(titledata), (SCREENWID - fontsprites.data(titledata)->w) / 2, 20);
84     return NULL;
85   }
86   return "";
87 }
88 
89 #define REDEFINEREC 5
90 static int times_called = 0;
redefine_menu_up(_menusystem * ms)91 static const char *redefine_menu_up(_menusystem *ms) {
92   static char buf[50];
93   const char *code[REDEFINEREC] = {_("Up"), _("Down"), _("Left"), _("Right"), _("Fire")};
94   const char *keystr;
95   static int blink, times_called;
96   const ttkey key[REDEFINEREC] = {up_key, down_key, left_key, right_key, fire_key};
97   const char *redef_fmt = "%s:  %s";
98   buf[0] = '\0';
99   if (ms) {
100     switch (ms->mstate) {
101     default:
102       if (key_sdlkey2conv(ms->key, false) == fire_key) {
103         ms->mstate = 1;
104         ms->opt_steal_control = ms->hilited;
105         ms->key = SDLK_UNKNOWN;
106       }
107       break;
108     case 1:
109       if (ms->key != SDLK_UNKNOWN) {
110         key_redefine(key[ms->hilited % REDEFINEREC], ms->key);
111         ms->mstate = 2;
112         ms->opt_steal_control = ms->hilited;
113         blink = 0;
114       } else blink++;
115       break;
116     case 2:
117       ms->mstate = 0;
118       ms->opt_steal_control = -1;
119       break;
120     }
121     if ((blink & 4) || (ms->mstate != 1))
122       keystr = SDL_GetKeyName(key_conv2sdlkey(key[ms->hilited % REDEFINEREC], true));
123     else keystr = "";
124     snprintf(buf, 50, redef_fmt, code[ms->hilited % REDEFINEREC], keystr);
125   } else {
126     keystr = SDL_GetKeyName(key_conv2sdlkey(key[times_called], true));
127     snprintf(buf, 50, redef_fmt, code[times_called], keystr);
128     times_called = (times_called + 1) % REDEFINEREC;
129   }
130   return buf;
131 }
132 
game_options_menu_password(_menusystem * prevmenu)133 static const char *game_options_menu_password(_menusystem *prevmenu) {
134   static char buf[50];
135   char pwd[PASSWORD_LEN+1];
136 
137   if (prevmenu) {
138     /* one more character to also copy the termination */
139     strncpy(pwd, config.curr_password(), PASSWORD_LEN+1);
140     while (!men_input(pwd, PASSWORD_LEN, -1, -1, PASSWORD_CHARS)) ;
141     config.curr_password(pwd);
142     /* FIXME: change -1, -1 to correct position; Need to fix menu system
143      first... */
144   }
145   snprintf(buf, 50, _("Password: %s"), config.curr_password());
146   return buf;
147 }
148 
game_options_menu_statustop(_menusystem * prevmenu)149 static const char *game_options_menu_statustop(_menusystem *prevmenu) {
150   static char txt[30];
151   if (prevmenu) {
152     config.status_top(!config.status_top());
153   }
154   if (config.status_top()) sprintf(txt, "%s %c", _("Status on top"), 4);
155   else sprintf(txt, "%s %c", _("Status on top"), 3);
156 
157   return txt;
158 }
159 
game_options_menu_lives(_menusystem * prevmenu)160 static const char *game_options_menu_lives(_menusystem *prevmenu) {
161   static char buf[50];
162   int i;
163   if (prevmenu) {
164     switch (key_sdlkey2conv(prevmenu->key, false)) {
165     case right_key:
166       config.start_lives(config.start_lives() + 1);
167       if (config.start_lives() > 3) config.start_lives(3);
168       break;
169     case left_key:
170       config.start_lives(config.start_lives() - 1);
171       if (config.start_lives() < 1) config.start_lives(1);
172       break;
173     default: return NULL;
174     }
175   }
176   sprintf(buf, _("Lives: "));
177   for (i = 0; i < config.start_lives(); i++)
178     sprintf(buf + strlen(buf), "%c", fonttoppler);
179   return buf;
180 }
181 
182 static const char *
game_options_menu_speed(_menusystem * prevmenu)183 game_options_menu_speed(_menusystem *prevmenu)
184 {
185   // Changing game_speed during a game has no effect until a
186   // a new game is started.
187   static char buf[50];
188   if (prevmenu) {
189     switch (key_sdlkey2conv(prevmenu->key, false)) {
190     case right_key:
191       config.game_speed(config.game_speed() + 1);
192       if (config.game_speed() > MAX_GAME_SPEED) config.game_speed(MAX_GAME_SPEED);
193       break;
194     case left_key:
195       config.game_speed(config.game_speed() - 1);
196       if (config.game_speed() < 0) config.game_speed(0);
197       break;
198     case fire_key:
199       config.game_speed((config.game_speed() + 1) % (MAX_GAME_SPEED+1));
200       break;
201     default: return NULL;
202     }
203   }
204   snprintf(buf, 50, _("Game Speed: %i"), config.game_speed());
205   return buf;
206 }
207 
208 static const char *
game_options_bonus(_menusystem * ms)209 game_options_bonus(_menusystem *ms)
210 {
211   static char txt[30];
212   if (ms) {
213     config.nobonus(!config.nobonus());
214   }
215   if (config.nobonus()) sprintf(txt, "%s %c", _("Bonus"), 3);
216   else sprintf(txt, "%s %c", _("Bonus"), 4);
217 
218   return txt;
219 }
220 
221 
men_game_options_menu(_menusystem * prevmenu)222 static const char *men_game_options_menu(_menusystem *prevmenu) {
223   static const char * s = _("Game Options");
224   if (prevmenu) {
225     _menusystem *ms = new_menu_system(s, NULL, 0, fontsprites.data(titledata)->h+30);
226 
227     ms = add_menu_option(ms, NULL, game_options_menu_password, SDLK_UNKNOWN, MOF_LEFT);
228     ms = add_menu_option(ms, NULL, game_options_menu_lives, SDLK_UNKNOWN,
229                          (menuoptflags)((int)MOF_PASSKEYS|(int)MOF_LEFT));
230     ms = add_menu_option(ms, NULL, game_options_menu_statustop);
231     ms = add_menu_option(ms, NULL, game_options_menu_speed, SDLK_UNKNOWN,
232                          (menuoptflags)((int)MOF_PASSKEYS|(int)MOF_LEFT));
233     ms = add_menu_option(ms, NULL, game_options_bonus);
234 
235     ms = add_menu_option(ms, NULL, NULL);
236     ms = add_menu_option(ms, _("Back"), NULL);
237 
238     ms = run_menu_system(ms, prevmenu);
239 
240     free_menu_system(ms);
241   }
242   return s;
243 }
244 
run_redefine_menu(_menusystem * prevmenu)245 static const char *run_redefine_menu(_menusystem *prevmenu) {
246   if (prevmenu) {
247     _menusystem *ms = new_menu_system(_("Redefine Keys"), NULL, 0, fontsprites.data(titledata)->h+30);
248 
249     times_called = 0;
250 
251     ms = add_menu_option(ms, NULL, redefine_menu_up, SDLK_UNKNOWN, MOF_LEFT);
252     ms = add_menu_option(ms, NULL, redefine_menu_up, SDLK_UNKNOWN, MOF_LEFT);
253     ms = add_menu_option(ms, NULL, redefine_menu_up, SDLK_UNKNOWN, MOF_LEFT);
254     ms = add_menu_option(ms, NULL, redefine_menu_up, SDLK_UNKNOWN, MOF_LEFT);
255     ms = add_menu_option(ms, NULL, redefine_menu_up, SDLK_UNKNOWN, MOF_LEFT);
256     ms = add_menu_option(ms, _("Back"), NULL);
257 
258     ms = run_menu_system(ms, prevmenu);
259 
260     free_menu_system(ms);
261   }
262   return _("Redefine Keys");
263 }
264 
265 static const char *
men_options_windowed(_menusystem * ms)266 men_options_windowed(_menusystem *ms)
267 {
268   static char txt[30];
269   if (ms) {
270     config.fullscreen(!config.fullscreen());
271     scr_reinit();
272     SDL_ShowCursor(config.fullscreen() ? 0 : 1);
273   }
274   if (config.fullscreen()) sprintf(txt, "%s %c", _("Fullscreen"), 4);
275   else sprintf(txt, "%s %c", _("Fullscreen"), 3);
276 
277   return txt;
278 }
279 
280 static const char *
men_options_sounds(_menusystem * ms)281 men_options_sounds(_menusystem *ms)
282 {
283   static char txt[30];
284   if (ms) {
285     if (config.nosound()) {
286       config.nosound(false);
287       snd_init();
288       if (!config.nomusic())
289         snd_playTitle();
290     } else {
291       if (!config.nomusic())
292         snd_stopTitle();
293       snd_done();
294       config.nosound(true);
295     }
296   }
297   if (config.nosound()) sprintf(txt, "%s %c", _("Sounds"), 3);
298   else sprintf(txt, "%s %c", _("Sounds"), 4);
299 
300   return txt;
301 }
302 
303   static const char *
men_options_music(_menusystem * ms)304 men_options_music(_menusystem *ms)
305 {
306   static char txt[30];
307   if (ms) {
308     if (config.nomusic()) {
309       config.nomusic(false);
310       snd_playTitle();
311     } else {
312       snd_stopTitle();
313       config.nomusic(true);
314     }
315   }
316   if (config.nomusic()) sprintf(txt, "%s %c", _("Music"), 3);
317   else sprintf(txt, "%s %c", _("Music"), 4);
318 
319   return txt;
320 }
321 
322 
323 static void
reload_font_graphics(void)324 reload_font_graphics(void) {
325   fontsprites.freedata();
326 
327   scr_reload_sprites(RL_FONT);
328   men_reload_sprites(2);
329 }
330 
331 static void
reload_robot_graphics(void)332 reload_robot_graphics(void) {
333   objectsprites.freedata();
334   scr_reload_sprites(RL_OBJECTS);
335 }
336 
337 static void
reload_layer_graphics(void)338 reload_layer_graphics(void) {
339   layersprites.freedata();
340   scr_reload_sprites(RL_SCROLLER);
341 }
342 
343 static const char *
men_alpha_font(_menusystem * ms)344 men_alpha_font(_menusystem *ms)
345 {
346   static char txt[30];
347   if (ms) {
348     config.use_alpha_font(!config.use_alpha_font());
349     reload_font_graphics();
350   }
351   if (config.use_alpha_font()) sprintf(txt, "%s %c", _("Font alpha"), 4);
352   else sprintf(txt, "%s %c", _("Font alpha"), 3);
353 
354   return txt;
355 }
356 
357 static const char *
men_alpha_sprites(_menusystem * ms)358 men_alpha_sprites(_menusystem *ms)
359 {
360   static char txt[30];
361   if (ms) {
362     config.use_alpha_sprites(!config.use_alpha_sprites());
363     reload_robot_graphics();
364   }
365   if (config.use_alpha_sprites()) sprintf(txt, "%s %c", _("Sprites alpha"), 4);
366   else sprintf(txt, "%s %c", _("Sprites alpha"), 3);
367 
368   return txt;
369 }
370 
371 static const char *
men_alpha_layer(_menusystem * ms)372 men_alpha_layer(_menusystem *ms)
373 {
374   static char txt[30];
375   if (ms) {
376     config.use_alpha_layers(!config.use_alpha_layers());
377     reload_layer_graphics();
378   }
379   if (config.use_alpha_layers()) sprintf(txt, "%s %c", _("Scroller alpha"), 4);
380   else sprintf(txt, "%s %c", _("Scroller alpha"), 3);
381 
382   return txt;
383 }
384 
385 static const char *
men_alpha_menu(_menusystem * ms)386 men_alpha_menu(_menusystem *ms)
387 {
388   static char txt[30];
389   if (ms) {
390     config.use_alpha_darkening(!config.use_alpha_darkening());
391   }
392   if (config.use_alpha_darkening()) sprintf(txt, "%s %c", _("Shadowing"), 4);
393   else sprintf(txt, "%s %c", _("Shadowing"), 3);
394 
395   return txt;
396 }
397 
398 static const char *
men_waves_menu(_menusystem * ms)399 men_waves_menu(_menusystem *ms)
400 {
401   if (ms) {
402     switch (key_sdlkey2conv(ms->key, false)) {
403     case fire_key:
404       config.waves_type((config.waves_type() + 1) % configuration::num_waves);
405       break;
406     case right_key:
407       config.waves_type(config.waves_type() + 1);
408       if (config.waves_type() >= configuration::num_waves) config.waves_type(configuration::num_waves - 1);
409       break;
410     case left_key:
411       config.waves_type(config.waves_type() - 1);
412       if (config.waves_type() < 0) config.waves_type(0);
413       break;
414     default: return NULL;
415     }
416   }
417   switch(config.waves_type()) {
418   case configuration::waves_nonreflecting: return _("Nonreflecting waves");
419   case configuration::waves_simple: return _("Simple waves");
420   case configuration::waves_expensive: return _("Expensive waves");
421   default: return _("Error");
422   }
423 }
424 
425 static const char *
men_full_scroller(_menusystem * ms)426 men_full_scroller(_menusystem *ms)
427 {
428   if (ms) {
429     config.use_full_scroller(!config.use_full_scroller());
430   }
431   if (config.use_full_scroller()) return _("Complete Scroller");
432   else return _("2 layers Scoller");
433 }
434 
435 
436 static const char *
men_alpha_options(_menusystem * mainmenu)437 men_alpha_options(_menusystem *mainmenu) {
438   static const char * s = _("Alpha Options");
439   if (mainmenu) {
440 
441     _menusystem *ms = new_menu_system(s, NULL, 0, fontsprites.data(titledata)->h+30);
442 
443     if (!ms) return NULL;
444 
445     ms = add_menu_option(ms, NULL, men_alpha_font, SDLK_UNKNOWN, MOF_RIGHT);
446     ms = add_menu_option(ms, NULL, men_alpha_sprites, SDLK_UNKNOWN, MOF_RIGHT);
447     ms = add_menu_option(ms, NULL, men_alpha_layer, SDLK_UNKNOWN, MOF_RIGHT);
448     ms = add_menu_option(ms, NULL, men_alpha_menu, SDLK_UNKNOWN, MOF_RIGHT);
449 
450     ms = add_menu_option(ms, NULL, NULL);
451     ms = add_menu_option(ms, _("Back"), NULL);
452 
453     ms = run_menu_system(ms, mainmenu);
454 
455     free_menu_system(ms);
456   }
457   return s;
458 }
459 
460 static const char *
men_options_graphic(_menusystem * mainmenu)461 men_options_graphic(_menusystem *mainmenu) {
462   static const char *s = _("Graphics");
463   if (mainmenu) {
464 
465     _menusystem *ms = new_menu_system(s, NULL, 0, fontsprites.data(titledata)->h+30);
466 
467     if (!ms) return NULL;
468 
469     ms = add_menu_option(ms, NULL, men_options_windowed);
470     ms = add_menu_option(ms, NULL, men_alpha_options);
471     ms = add_menu_option(ms, NULL, men_waves_menu, SDLK_UNKNOWN, MOF_PASSKEYS);
472     ms = add_menu_option(ms, NULL, men_full_scroller, SDLK_UNKNOWN);
473 
474     ms = add_menu_option(ms, NULL, NULL);
475     ms = add_menu_option(ms, _("Back"), NULL);
476 
477     ms = run_menu_system(ms, mainmenu);
478 
479     free_menu_system(ms);
480   }
481   return s;
482 }
483 
484 static const char *
men_options(_menusystem * mainmenu)485 men_options(_menusystem *mainmenu) {
486   static const char * s = _("Options");
487   if (mainmenu) {
488 
489     _menusystem *ms = new_menu_system(s, NULL, 0, fontsprites.data(titledata)->h+30);
490 
491     if (!ms) return NULL;
492 
493     ms = add_menu_option(ms, NULL, men_game_options_menu);
494     ms = add_menu_option(ms, NULL, run_redefine_menu);
495     ms = add_menu_option(ms, NULL, men_options_graphic);
496     ms = add_menu_option(ms, NULL, men_options_sounds);
497     ms = add_menu_option(ms, NULL, men_options_music);
498 
499     ms = add_menu_option(ms, NULL, NULL);
500     ms = add_menu_option(ms, _("Back"), NULL);
501 
502     ms = run_menu_system(ms, mainmenu);
503 
504     free_menu_system(ms);
505   }
506   return s;
507 }
508 
509 static int hiscores_timer = 0;
510 static int hiscores_pager = 0;
511 static int hiscores_state = 0;
512 static int hiscores_xpos = SCREENWID;
513 static int hiscores_hilited = -1;
514 static int hiscores_maxlen_pos = 0;
515 static int hiscores_maxlen_points = 0;
516 static int hiscores_maxlen_name = 0;
517 static int hiscores_maxlen = 0;
518 
519 static void
get_hiscores_string(int p,char ** pos,char ** points,char ** name)520   get_hiscores_string(int p, char **pos, char **points, char **name)
521 {
522   Uint32 pt;
523   Uint8 tw;
524 
525   static char buf1[SCORENAMELEN + 5];
526   static char buf2[SCORENAMELEN + 5];
527   static char buf3[SCORENAMELEN + 5];
528 
529   buf1[0] = buf2[0] = buf3[0] = '\0';
530 
531   hsc_entry(p, buf3, &pt, &tw);
532 
533   snprintf(buf1, SCORENAMELEN + 5, "%i.", p + 1);
534   snprintf(buf2, SCORENAMELEN + 5, "%i", pt);
535 
536   *pos = buf1;
537   *points = buf2;
538   *name = buf3;
539 }
540 
541 static void
calc_hiscores_maxlen(int * max_pos,int * max_points,int * max_name)542 calc_hiscores_maxlen(int *max_pos, int * max_points, int *max_name)
543 {
544   for (int x = 0; x < hsc_entries(); x++) {
545     char *a, *b, *c;
546     int clen;
547 
548     get_hiscores_string(x, &a, &b, &c);
549 
550     clen = scr_textlength(a);
551     if (clen > *max_pos) *max_pos = clen;
552 
553     clen = scr_textlength(b);
554     if (clen < 64) clen = 64;
555     if (clen > *max_points) *max_points = clen;
556 
557     clen = scr_textlength(c);
558     if (clen > *max_name) *max_name = clen;
559   }
560 }
561 
562 static const char *
men_hiscores_background_proc(_menusystem * ms)563 men_hiscores_background_proc(_menusystem *ms)
564 {
565   static int blink_r = 120, blink_g = 200, blink_b = 40;
566   static int next_page = 0;
567 
568   if (ms) {
569 
570     scr_blit(restsprites.data(menupicture), 0, 0);
571     scr_blit(fontsprites.data(titledata), (SCREENWID - fontsprites.data(titledata)->w) / 2, 20);
572 
573     switch (hiscores_state) {
574     case 0: /* bring the scores in */
575       if (hiscores_xpos > ((SCREENWID - hiscores_maxlen) / 2)) {
576         hiscores_xpos -= 10;
577         break;
578       } else hiscores_state = 1;
579     case 1: /* hold the scores on screen */
580       if (hiscores_timer < 100) {
581         hiscores_timer++;
582         break;
583       } else {
584         bool filled_page = false;
585         bool firstpage = (hiscores_pager == 0);
586         int pager = (hiscores_pager + 1) % (NUMHISCORES / HISCORES_PER_PAGE);
587         for (int tmp = 0; tmp < HISCORES_PER_PAGE; tmp++) {
588           //          int cs = tmp + (pager * HISCORES_PER_PAGE);
589           //          if (scores[cs].points || strlen(scores[cs].name)) {
590           filled_page = true;
591           break;
592           //          }
593         }
594         if (!filled_page && firstpage) {
595           hiscores_timer = 0;
596           break;
597         } else {
598           hiscores_state = 2;
599           next_page = pager;
600         }
601       }
602     case 2: /* move the scores out */
603       if (hiscores_xpos > -(hiscores_maxlen + 40)) {
604         hiscores_timer = 0;
605         hiscores_xpos -= 10;
606         break;
607       } else {
608         hiscores_state = 0;
609         hiscores_xpos = SCREENWID;
610         hiscores_pager = next_page;
611       }
612     default: break;
613     }
614     for (int t = 0; t < HISCORES_PER_PAGE; t++) {
615       int cs = t + (hiscores_pager * HISCORES_PER_PAGE);
616       int ypos = (t*(FONTHEI+1)) + fontsprites.data(titledata)->h + FONTHEI*2;
617       char *pos, *points, *name;
618       get_hiscores_string(cs, &pos, &points, &name);
619       if (cs == hiscores_hilited) {
620         int clen = hiscores_maxlen_pos + hiscores_maxlen_points + hiscores_maxlen_name + 20 * 2 + 20;
621         scr_putbar(hiscores_xpos - 5, ypos - 3,
622                    clen, FONTHEI + 3, blink_r, blink_g, blink_b, (config.use_alpha_darkening())?128:255);
623       }
624       scr_writetext(hiscores_xpos + hiscores_maxlen_pos - scr_textlength(pos), ypos, pos);
625       scr_writetext(hiscores_xpos + hiscores_maxlen_pos + 20 + hiscores_maxlen_points - scr_textlength(points), ypos, points);
626       scr_writetext(hiscores_xpos + hiscores_maxlen_pos + 20 + 20 + hiscores_maxlen_points, ypos, name);
627     }
628     scr_color_ramp(&blink_r, &blink_g, &blink_b);
629   }
630   return _("HighScores");
631 }
632 
show_scores(bool back=true,int mark=-1)633 static void show_scores(bool back = true, int mark = -1) {
634   static char buf[50];
635   snprintf(buf, 50, _("Scores for %s"), lev_missionname(currentmission));
636   _menusystem *ms = new_menu_system(buf, men_hiscores_background_proc, 0, fontsprites.data(titledata)->h + 30);
637 
638   if (!ms) return;
639 
640   hsc_select(lev_missionname(currentmission));
641 
642   hiscores_timer = 0;
643   if ((mark >= 0) && (mark < NUMHISCORES))
644     hiscores_pager = (mark / HISCORES_PER_PAGE);
645   else
646     hiscores_pager = 0;
647   hiscores_state = 0;
648   calc_hiscores_maxlen(&hiscores_maxlen_pos, &hiscores_maxlen_points, &hiscores_maxlen_name);
649   hiscores_maxlen = hiscores_maxlen_pos + hiscores_maxlen_points + hiscores_maxlen_name + 20;
650   hiscores_xpos = SCREENWID;
651   hiscores_hilited = mark;
652 
653   /* fake options; the empty lines are used by the background proc */
654   for (int tmpz = 0; tmpz < HISCORES_PER_PAGE; tmpz++) ms = add_menu_option(ms, NULL, NULL);
655 
656   if (back)
657     ms = add_menu_option(ms, _("Back"), NULL);
658   else
659     ms = add_menu_option(ms, _("OK"), NULL);
660 
661   ms = run_menu_system(ms, 0);
662 
663   free_menu_system(ms);
664 }
665 
666 static void
congrats_background_proc(void)667 congrats_background_proc(void)
668 {
669   scr_blit(restsprites.data(menupicture), 0, 0);
670   scr_blit(fontsprites.data(titledata), (SCREENWID - fontsprites.data(titledata)->w) / 2, 20);
671 
672   /* you can use up to 4 lines of text here, but please check
673    * if the text fits onto the screen
674    */
675   const char * text = _("Congratulations! You are\n"
676                         "probably good enough to\n"
677                         "enter the highscore table!");
678 
679   int ypos = 210;
680 
681   for (int pos = 0; text[pos]; pos++)
682     if (text[pos] == '\n') ypos -= 40;
683 
684   char line[200];
685   int pos = 0;
686   int linepos = 0;
687 
688   while (text[pos]) {
689 
690     if (text[pos] == '\n') {
691       line[linepos] = 0;
692       scr_writetext_center(ypos, line);
693       linepos = 0;
694       ypos += 40;
695     } else {
696       if (linepos < 198) {
697         line[linepos] = text[pos];
698         linepos++;
699       }
700     }
701     pos++;
702   }
703 
704   line[linepos] = 0;
705   scr_writetext_center(ypos, line);
706 
707   scr_writetext_center(270, _("Please enter your name"));
708 }
709 
710 /* highscores, after the game
711  * pt = points,
712  * twr = tower reached, -1 = mission finished
713  */
men_highscore(unsigned long pt,int twr)714 static void men_highscore(unsigned long pt, int twr) {
715 
716   Uint8 pos = 0xff;
717 
718 #ifndef GAME_DEBUG_KEYS
719 
720   hsc_select(lev_missionname(currentmission));
721 
722   /* check, if there is a chance at all to get into the list,
723    * if not we don't need to lock the highscoretable
724    */
725   if (hsc_canEnter(pt)) {
726 
727     set_men_bgproc(congrats_background_proc);
728 
729     char name[SCORENAMELEN+1];
730 
731 #ifndef WIN32
732     /* copy the login name into the name entered into the highscore table */
733     strncpy(name, getenv("LOGNAME"), SCORENAMELEN);
734     name[SCORENAMELEN] = 0; // to be sure we have a terminated string
735 #else
736     /* on systems without login we have no name */
737     name[0] = 0;
738 #endif
739 
740     while (!men_input(name, SCORENAMELEN)) ;
741 
742     pos = hsc_enter(pt, twr, name);
743   }
744 
745 #endif /* GAME_DEBUG_KEYS */
746 
747   show_scores(false, pos);
748 }
749 
750 static void
main_game_loop()751 main_game_loop()
752 {
753   unsigned char tower;
754   Uint8 anglepos;
755   Uint16 resttime;
756   int demo = 0;
757   int gameresult;
758   Uint16 *tmpbuf = NULL;
759 
760   if (!lev_loadmission(currentmission)) {
761     if (!men_yn(_("This mission contains\n"
762                 "unknown building blocks.\n"
763                 "You probably need a new\n"
764                 "version of Tower Toppler.\n"
765                 "Do you want to continue?"), false, men_main_background_proc))
766       return;
767   }
768 
769   tower = lev_tower_passwd_entry(config.curr_password());
770 
771   gam_newgame();
772   bns_restart();
773 
774   do {
775     ttsounds::instance()->startsound(SND_WATER);
776     do {
777       gam_loadtower(tower);
778       scr_settowercolor(lev_towercol_red(), lev_towercol_green(), lev_towercol_blue());
779       ttsounds::instance()->setsoundvol(SND_WATER, 128);
780       gam_arrival();
781       gameresult = gam_towergame(anglepos, resttime, demo, &tmpbuf);
782     } while ((gameresult == GAME_DIED) && pts_lifesleft());
783 
784     if (gameresult == GAME_FINISHED) {
785       gam_pick_up(anglepos, resttime);
786 
787       ttsounds::instance()->stopsound(SND_WATER);
788       tower++;
789 
790       if (tower < lev_towercount()) {
791 
792         // load next tower, because its colors will be needed for bonus game
793         gam_loadtower(tower);
794 
795         if (!config.nobonus())
796           if (!bns_game())
797             gameresult = GAME_ABORTED;
798       }
799     } else {
800       ttsounds::instance()->stopsound(SND_WATER);
801     }
802   } while (pts_lifesleft() && (tower < lev_towercount()) && (gameresult != GAME_ABORTED));
803 
804   if (gameresult != GAME_ABORTED)
805     men_highscore(pts_points(), (tower >= lev_towercount()) ? tower : -1);
806 }
807 
808 #ifdef HUNT_THE_FISH
809 static const char *
men_main_bonusgame_proc(_menusystem * ms)810 men_main_bonusgame_proc(_menusystem *ms)
811 {
812   if (ms) {
813     gam_newgame();
814     scr_settowercolor(rand() % 256, rand() % 256, rand() % 256);
815     lev_set_towercol(rand() % 256, rand() % 256, rand() % 256);
816     bns_game();
817   }
818   return _("Hunt the Fish");
819 }
820 #endif /* HUNT_THE_FISH */
821 
822 static const char *
men_main_startgame_proc(_menusystem * ms)823 men_main_startgame_proc(_menusystem *ms)
824 {
825   if (ms) {
826     int missioncount = lev_missionnumber();
827     switch (key_sdlkey2conv(ms->key, false)) {
828     case fire_key:
829       dcl_update_speed(config.game_speed());
830       snd_musicVolume(MIX_MAX_VOLUME/4);
831       main_game_loop();
832       snd_musicVolume(MIX_MAX_VOLUME);
833       dcl_update_speed(MENU_DCLSPEED);
834       break;
835     case right_key: currentmission = (currentmission + 1) % missioncount; break;
836     case left_key: currentmission = (currentmission + missioncount - 1) % missioncount; break;
837     default: return NULL;
838     }
839   }
840   static char s[30];
841   snprintf(s, 30, _("%c Start: %s %c"), fontptrleft, _(lev_missionname(currentmission)), fontptrright);
842   return s;
843 }
844 
845 static const char *
men_main_highscore_proc(_menusystem * ms)846 men_main_highscore_proc(_menusystem *ms)
847 {
848   if (ms) {
849     show_scores();
850   }
851   return _("Highscores");
852 }
853 
854 static const char *
men_main_leveleditor_proc(_menusystem * ms)855 men_main_leveleditor_proc(_menusystem *ms)
856 {
857   if (ms) {
858     le_edit();
859     (void)key_sdlkey();
860   }
861   return _("Level Editor");
862 }
863 
864 static const char *
men_main_timer_proc(_menusystem * ms)865 men_main_timer_proc(_menusystem *ms)
866 {
867   if (ms) {
868     Uint8 num_demos = 0;
869     Uint8 demos[256];
870     Uint16 miss = rand() % lev_missionnumber();
871     Uint8 num_towers;
872 
873     int demolen;
874     Uint16 *demobuf;
875     Uint8 anglepos;
876     Uint16 resttime;
877 
878     for (int tmpm = 0; (tmpm < lev_missionnumber()) && (num_demos == 0); tmpm++) {
879       Uint16 tmiss = (miss + tmpm) % lev_missionnumber();
880 
881       if (lev_loadmission(tmiss)) {
882         num_towers = lev_towercount();
883 
884         for (Uint8 idx = 0; (idx < num_towers) && (num_demos < 256); idx++) {
885           lev_selecttower(idx);
886           lev_get_towerdemo(demolen, demobuf);
887           if (demolen) demos[num_demos++] = idx;
888         }
889       }
890     }
891 
892     if (num_demos < 1) return NULL;
893 
894     lev_selecttower(demos[rand() % num_demos]);
895     lev_get_towerdemo(demolen, demobuf);
896 
897     dcl_update_speed(config.game_speed());
898     gam_newgame();
899     ttsounds::instance()->startsound(SND_WATER);
900     scr_settowercolor(lev_towercol_red(), lev_towercol_green(), lev_towercol_blue());
901     ttsounds::instance()->setsoundvol(SND_WATER, 128);
902     rob_initialize();
903     (void)gam_towergame(anglepos, resttime, demolen, &demobuf);
904     ttsounds::instance()->stopsound(SND_WATER);
905     dcl_update_speed(MENU_DCLSPEED);
906   }
907   return NULL;
908 }
909 
910 static const char *
men_game_return2game(_menusystem * tms)911 men_game_return2game(_menusystem *tms)
912 {
913   if (tms) {
914     tms->exitmenu = true;
915     tms->mstate = 0;
916   }
917   return _("Return to Game");
918 }
919 
920 static const char *
men_game_leavegame(_menusystem * tms)921 men_game_leavegame(_menusystem *tms)
922 {
923   if (tms) {
924     tms->exitmenu = true;
925     tms->mstate = 1;
926   }
927   return _("Quit Game");
928 }
929 
930 
931 
932 #ifdef GAME_DEBUG_KEYS
run_debug_menu(void)933 void run_debug_menu(void) {
934   _menusystem *ms = new_menu_system(_("DEBUG MENU"), NULL, 0, SCREENHEI / 5);
935 
936   ms = add_menu_option(ms, NULL, debug_menu_extralife);
937   ms = add_menu_option(ms, NULL, debug_menu_extrascore);
938   ms = add_menu_option(ms, NULL, NULL);
939   ms = add_menu_option(ms, _("Back to Game"), NULL);
940 
941   ms = run_menu_system(ms, 0);
942 
943   free_menu_system(ms);
944 }
945 #endif
946 
men_init(void)947 void men_init(void) {
948   men_reload_sprites(3);
949 }
950 
men_main()951 void men_main() {
952   _menusystem *ms;
953 
954   ms = new_menu_system(NULL, men_main_background_proc, 0, fontsprites.data(titledata)->h + 30);
955 
956   if (!ms) return;
957 
958   ms = set_menu_system_timeproc(ms, 200, men_main_timer_proc);
959 
960   ms = add_menu_option(ms, NULL, men_main_startgame_proc, SDLK_s, MOF_PASSKEYS);
961   ms = add_menu_option(ms, NULL, NULL);
962   ms = add_menu_option(ms, NULL, men_main_highscore_proc, SDLK_h);
963   ms = add_menu_option(ms, NULL, men_options, SDLK_o);
964   ms = add_menu_option(ms, NULL, men_main_leveleditor_proc, SDLK_e);
965 #ifdef HUNT_THE_FISH
966   ms = add_menu_option(ms, NULL, men_main_bonusgame_proc);
967 #endif
968   ms = add_menu_option(ms, NULL, NULL);
969   ms = add_menu_option(ms, _("Quit"), NULL, SDLK_q);
970 
971   ms->wraparound = true;
972 
973   ms = run_menu_system(ms, 0);
974 
975   free_menu_system(ms);
976 }
977 
men_game()978 bool men_game() {
979   _menusystem *ms;
980   bool do_quit;
981   int  speed = dcl_update_speed(MENU_DCLSPEED);
982 
983   ms = new_menu_system(NULL, NULL, 0, fontsprites.data(titledata)->h + 30);
984 
985   if (!ms) return 0;
986 
987   ms = add_menu_option(ms, NULL, men_game_return2game);
988   ms = add_menu_option(ms, NULL, men_options, SDLK_o);
989   ms = add_menu_option(ms, NULL, NULL);
990   ms = add_menu_option(ms, NULL, men_game_leavegame);
991 
992   ms->wraparound = true;
993 
994   ms = run_menu_system(ms, 0);
995 
996   do_quit = ms->mstate != 0;
997 
998   free_menu_system(ms);
999 
1000   dcl_update_speed(speed);
1001 
1002   return do_quit;
1003 }
1004 
men_done(void)1005 void men_done(void) {
1006 }
1007 
1008