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