Imported kball_final_src_16dec2004.tar.gz
[kball.git] / src / gamemenu.cpp
blob6f6e6ab087aab1f7a12050be190baadab05b8681
1 // ------------------------------------------------------------------
2 // gamemenu.cpp
3 // ------------------------------------------------------------------
4 // This has the menu of the Kball game
5 // ------------------------------------------------------------------
6 // Developed By Kronoman - Copyright (c) 2004
7 // In loving memory of my father
8 // ------------------------------------------------------------------
10 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
11 // DEBUG -- THIS FILE IS A MESS, DO SOMETHING ABOUT IT (SPANK IT?)
12 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
14 // Dig up her bones!!!
15 #include "filehelp.h"
16 #include "gamemenu.h" // I need my prototypes
17 #include "sound.h" // I need the sound system
19 // some globals needed by callback
20 CParticleManager menu_particle_manager; // our own particle managar :^D -- REMEMBER TO CALL NUKE PARTICLES BEFORE LEAVING!
21 BITMAP *bmp_real_background = NULL; // menu real background
22 CSoundWrapper *sound_menu = NULL; // sound manager of game menu object
24 // ------------------------------------------------------------------
25 // This callback function produces the background animation in the menus
26 // also, polls the music
27 // ------------------------------------------------------------------
28 void menu_callback_animation(CQMenu &d, bool do_logic)
30 BITMAP *bmp = NULL;
32 if (sound_menu) // poll music
33 sound_menu->music_poll();
35 time_t t_now = time(NULL); // get current time, for displaying it, and also, for little surprise :O
37 struct tm *time_now_local = localtime (&t_now); // get finally the time in appropiate format
39 bmp = d.get_back_bitmap();
41 if (bmp == NULL)
42 return ; // can't draw :(
44 // DEBUG -- improve this animation
45 if (do_logic) // update logic
47 menu_particle_manager.update_logic();
48 // add particles at random
49 if (rand() % 100 > 95)
51 int c, x, y; // color, pos of explosion
53 switch (rand() % 4) // pick color scheme
56 case 0:
57 c = makecol(255, rand() % 256, 0);
58 break;
60 case 1:
61 c = makecol(0, rand() % 256, 255);
62 break;
64 case 2:
65 c = makecol(rand() % 256, 0, 255);
66 break;
68 case 3:
69 c = makecol(rand() % 256, 255, 0);
70 break;
72 default:
73 c = makecol(rand() % 256, rand() % 256, rand() % 256);
74 break;
77 x = (rand() % (int)(SCREEN_W * 0.8)) + (int)(SCREEN_W * 0.1); // use 80% of screen width
78 y = (rand() % (int)(SCREEN_H * 0.8)) + (int)(SCREEN_H * 0.1); // use 80% of screen height
79 for (int i = 0; i < rand() % 50 + 100; i++) // add particles
81 if (rand() % 100 < 85)
82 menu_particle_manager.add_particle(new CCircleParticle(x, y, (float)((rand() % 800) - 400) / 100.0, (float)((rand() % 800) - 400) / 100.0, c, rand() % 60 + 5, rand() % 4 + 1));
83 else
84 menu_particle_manager.add_particle(new CSparkParticle(x, y, (float)((rand() % 800) - 400) / 100.0, (float)((rand() % 800) - 400) / 100.0, c, rand() % 60 + 5, rand() % 3 + 1));
87 // a little text message
88 if (time_now_local->tm_mday == 30 && time_now_local->tm_mon == 3 && rand() % 100 < 75)
89 menu_particle_manager.add_particle(new CTextParticle(x, y, (float)((rand() % 800) - 400) / 100.0, (float)(rand() % 400 + 150) / -100.0, c, rand() % 60 + 35, (rand() % 1000 < 990 ? string("Kronoman Rulez!") : string("Send me lots of $$$! ;)")) ) );
91 if (time_now_local->tm_year + 1900 >= 2010 && rand() % 100 < 75)
93 char tmpstr[256];
94 usprintf(tmpstr, "Yeah! My game still runs in %d", 1900 + time_now_local->tm_year);
96 if (time_now_local->tm_year + 1900 > 2082 && rand() % 100 < 75)
97 menu_particle_manager.add_particle(new CTextParticle(x, y, (float)((rand() % 800) - 400) / 100.0, (float)(rand() % 400 + 150) / -100.0, c, rand() % 60 + 35, string("I must be over 100 years by now... send me dead flowers to my grave :'(") ) );
98 else
99 menu_particle_manager.add_particle(new CTextParticle(x, y, (float)((rand() % 800) - 400) / 100.0, (float)(rand() % 400 + 150) / -100.0, c, rand() % 60 + 35, string(tmpstr) ) );
104 else
106 // draw particles
107 if (bmp_real_background != NULL)
108 blit (bmp_real_background, bmp, 0, 0, 0, 0, bmp_real_background->w, bmp_real_background->h);
109 else
110 clear(bmp);
112 //set_trans_blender(128,128,128,128);
113 //drawing_mode(DRAW_MODE_TRANS, NULL,0,0);
114 menu_particle_manager.render(bmp, 0, 0);
116 //solid_mode();
118 // show time of day
119 char tbufstr[256]; // time string buffer
121 strftime(tbufstr, 255, "%b %d %Y %H:%M:%S", time_now_local); // This function formats the time data
123 text_mode( -1);
125 textout(bmp, font, tbufstr, 0, bmp->h - text_height(font), makecol(128, 0, 255));
130 CGameMenu::CGameMenu()
132 mtracer.add("CGameMenu::CGameMenu()");
134 menu_back = NULL; // doble buffer bitmap for menu
137 CGameMenu::~CGameMenu()
139 mtracer.add("CGameMenu::~CGameMenu()");
140 // DEBUG!
141 // here we should release RAM used, etc (we should wrap init code and end code in a nice place... not the shit that is right now!)
144 // ------------------------------------------------------------------
145 // This shows the main menu to the user
146 // This is the menu that let the user choose the main options
147 // ------------------------------------------------------------------
148 void CGameMenu::do_main_menu()
150 CQMenu menu; // menu to use/show
151 char tmp_file_buf[2048];
153 mtracer.add("CGameMenu::do_main_menu() started");
155 // I set this so the callback 'knows' the sound manager
156 sound_menu = &this->soundw;
157 //soundw.set_enabled(true);
159 int ret = 0;
161 clear_bitmap(screen);
162 textout_centre_ex(screen, font, "[ Please wait... loading... ]", SCREEN_W / 2, SCREEN_H / 2, makecol(255, 255, 255), makecol(0, 0, 64));
164 menu_datafile.load_datafile(where_is_the_filename(tmp_file_buf, "gui.dat")); // load datafile
166 // set music
167 soundw.music_load((DUH *)menu_datafile.get_resource_dat("MENU_MUSIC_XM"));
169 bmp_real_background = (BITMAP *)menu_datafile.get_resource_dat("MENU_BMP_BACKGROUND"); // get back bmp image
171 // set some gravity to particles
172 menu_particle_manager.add_dy = 0.08;
174 menu_back = create_bitmap(SCREEN_W, SCREEN_H); // DEBUG -- HERE I SHOULD LOAD THE BACKGROUND FROM DATAFILE!
175 if (menu_back == NULL)
176 raise_error("do_main_menu()\nERROR: can't create menu_back bitmap!");
178 clear(menu_back);
180 menu.set_to_bitmap(screen);
182 menu.set_back_bitmap(menu_back);
184 menu.set_callback_drawer(menu_callback_animation);
186 menu.set_font_s((FONT *)menu_datafile.get_resource_dat("MENU_FONT_BIG"));
188 menu.set_fg_color_s(makecol(255, 255, 255));
190 menu.set_bg_color_s(makecol(0, 0, 200));
192 menu.set_font_ns((FONT *)menu_datafile.get_resource_dat("MENU_FONT_BIG"));
194 menu.set_fg_color_ns(makecol(128, 128, 128));
196 menu.set_bg_color_ns( -1);
198 menu.set_xywh(320, 100, SCREEN_W, SCREEN_H);
200 menu.text_align = 2; // center align
202 menu.item_y_separation = 25;
204 // add menu items
205 menu.add_item_to_menu(string("Start new game")); // 0
207 menu.add_item_to_menu(string("Options")); // 1
209 menu.add_item_to_menu(string("Credits")); // 2
211 menu.add_item_to_menu(string("Map editor")); // 3
213 menu.add_item_to_menu(string("Quit")); // 4
215 while (ret != 4) // 4 = quit
217 set_config_file("kball.cfg");
218 menu.control.load_configuration_of_controller("KBALL_CONTROLLER");
220 soundw.music_resume();
222 ret = menu.do_the_menu(); // show the menu
224 soundw.music_pause();
226 switch (ret)
229 case 0: // start
230 do_file_level_selector();
231 break;
233 case 1: // options
234 do_options_menu();
235 break;
237 case 2: // credits
238 do_about_stuff();
239 break;
241 case 3: // map editor (from hell they came...)
242 map_editor.start_map_editor();
243 break;
245 case 4: // quit
246 for (int yi = 0; yi < SCREEN_H; yi += 2)
247 hline(screen, 0, yi, SCREEN_W, makecol(0, 0, 20));
249 textout_centre(screen, (FONT *)menu_datafile.get_resource_dat("MENU_FONT_BIG"), "QUIT GAME? Y/N", SCREEN_W / 2 + 2, SCREEN_H / 2 + 2, makecol(0, 0, 0));
251 textout_centre(screen, (FONT *)menu_datafile.get_resource_dat("MENU_FONT_BIG"), "QUIT GAME? Y/N", SCREEN_W / 2, SCREEN_H / 2, makecol(0, 255, 255));
253 clear_keybuf();
255 rest(25);
257 clear_keybuf();
259 if ((readkey() >> 8) != KEY_Y)
261 ret = -1; // abort exit
264 break;
267 rest(100);
268 clear_keybuf();
271 // DEBUG -- REMEMBER HERE TO FREE THE MEMORY/OBJECTS USED!
272 destroy_bitmap(menu_back);
274 menu_particle_manager.nuke_particle_list(); // destroy particles
276 menu_datafile.nuke_datafile(); // free RAM of datafile
278 bmp_real_background = NULL;
281 // ------------------------------------------------------------------
282 // This lets the user choose a level to start it, or a full campaign
283 // It WILL start a game
284 // For this, it list on a menu the files of the current directory
285 // This should *ONLY* be called from main menu, otherwise data needed
286 // for menu will be absent on RAM (have a nice SEG FAULT!)
287 // ------------------------------------------------------------------
288 void CGameMenu::do_file_level_selector()
290 // the level path is defined as [install dir]/levels
292 al_ffblk dir_reader;
293 char path_str[2048]; // path to level to play
294 char level_path[2048]; // full path to levels in general (dir/kball/bin/levels, etc)
295 CQMenu menu;
296 int ret = 0;
297 bool full_campaign = false; // we are going to play full campaing, or single map?
299 mtracer.add("CGameMenu::do_file_level_selector() started\n");
301 set_config_file("kball.cfg");
302 menu.control.load_configuration_of_controller("KBALL_CONTROLLER");
304 menu.set_to_bitmap(screen);
305 menu.set_back_bitmap(menu_back);
306 menu.set_callback_drawer(menu_callback_animation);
307 menu.text_align = 2;
308 menu.item_y_separation = 25;
310 // let choose single level, or campaign
311 menu.set_font_s((FONT *)menu_datafile.get_resource_dat("MENU_FONT_BIG"));
312 menu.set_fg_color_s(makecol(255, 255, 255));
313 menu.set_bg_color_s(makecol(0, 0, 200));
315 menu.set_font_ns((FONT *)menu_datafile.get_resource_dat("MENU_FONT_BIG"));
316 menu.set_fg_color_ns(makecol(128, 128, 128));
317 menu.set_bg_color_ns( -1);
318 menu.set_xywh(320, 100, SCREEN_W, SCREEN_H);
320 menu.clear_menu_list();
321 menu.add_item_to_menu("Full campaign");
322 menu.add_item_to_menu("Single level");
323 menu.add_item_to_menu("< Cancel and return >");
325 // get level
326 get_executable_name(level_path, 2048);
327 replace_filename(level_path, level_path, "", 2048);
328 append_filename(level_path, level_path, "levels", 2048);
330 fix_filename_slashes(level_path);
331 mtracer.add("--> \t Level path == %s", level_path);
333 soundw.music_resume();
335 switch (menu.do_the_menu()) // show the menu and act in consecuence)
339 case 0:
340 soundw.music_pause();
341 usprintf(path_str, "%s/*.fmp", level_path);
342 full_campaign = true;
343 break;
345 case 1:
346 soundw.music_pause();
347 usprintf(path_str, "%s/*.map", level_path);
348 full_campaign = false;
349 break;
351 default:
352 soundw.music_pause();
353 return ;
354 break;
357 fix_filename_slashes(path_str);
360 // --- Now, list files to use ---
361 menu.set_font_s((FONT *)menu_datafile.get_resource_dat("MENU_FONT_MEDIUM"));
362 menu.set_fg_color_s(makecol(255, 255, 255));
363 menu.set_bg_color_s(makecol(0, 0, 200));
365 menu.set_font_ns((FONT *)menu_datafile.get_resource_dat("MENU_FONT_MEDIUM"));
366 menu.set_fg_color_ns(makecol(128, 128, 128));
367 menu.set_bg_color_ns( -1);
369 menu.set_xywh(320, 100, SCREEN_W, SCREEN_H);
370 menu.item_y_separation = 5;
372 menu.clear_menu_list();
374 // read files and populate menu with them
375 ret = al_findfirst(path_str, &dir_reader, FA_ARCH);
377 while (!ret)
379 menu.add_item_to_menu(dir_reader.name);
380 ret = al_findnext(&dir_reader);
383 al_findclose(&dir_reader);
385 // if we don't have items, we must return with a message
386 if (menu.get_menu_item_count() < 1)
388 menu.clear_menu_list();
389 menu.add_item_to_menu("ERROR: NO FILE AVAILABLE!");
391 soundw.music_resume();
393 menu.do_the_menu();
395 soundw.music_pause();
396 return ; // abort the mission :^P
399 menu.add_item_to_menu("< Cancel and return >");
401 soundw.music_resume();
403 ret = menu.do_the_menu(); // show the menu
405 soundw.music_pause();
407 if (ret == menu.get_menu_item_count() - 1)
408 return ; // last item == cancel, then, cancel
410 // get the file name
411 usprintf(path_str, "%s/%s", level_path, menu.get_menu_item_text(ret).c_str());
413 fix_filename_slashes(path_str);
415 // play the game - rock 'n roll!
416 set_config_file("kball.cfg");
418 game_kernel.player_ball.control.load_configuration_of_controller("KBALL_CONTROLLER");
420 text_mode(makecol(0, 0, 0));
422 if (full_campaign)
424 mtracer.add("CGameMenu::do_file_level_selector()\n\tStarting campaign game\n");
426 game_kernel.player_ball.lives = BALL_LIVES_CAMPAIGN; // ball of the player lives
427 game_kernel.player_ball.score = 0;
428 game_kernel.stats.reset();
429 game_kernel.play_a_full_campaign(path_str);
431 mtracer.add("CGameMenu::do_file_level_selector()\n\tEnd of campaign game\n");
433 else
435 // start single level game play
436 mtracer.add("CGameMenu::do_file_level_selector()\n\tStarting single level game\n");
438 game_kernel.player_ball.lives = BALL_LIVES; // ball of the player lives
439 game_kernel.player_ball.score = 0;
440 game_kernel.stats.reset();
441 game_kernel.play_a_single_level(path_str);
443 mtracer.add("CGameMenu::do_file_level_selector()\n\tEnd of single level game\n");
448 // ------------------------------------------------------------------
449 // This shows the 'About' stuff
450 // ------------------------------------------------------------------
451 void CGameMenu::do_about_stuff()
453 mtracer.add("CGameMenu::do_about_stuff();");
455 BITMAP *back = (BITMAP *)menu_datafile.get_resource_dat("ABOUT_BACKGROUND"); // get back bmp image
456 BITMAP *dbuf = create_bitmap(SCREEN_W, SCREEN_H);
457 FONT *font_about = (FONT *)menu_datafile.get_resource_dat("MENU_FONT_SMALL");
458 SAMPLE *snd_loop_sample = (SAMPLE *)menu_datafile.get_resource_dat("ABOUT_BACK_SOUND"); // back sound
459 if (dbuf == NULL)
461 mtracer.add("CGameMenu::do_about_stuff() -- ERROR!!! Can't create dbuf bitmap!");
462 return ;
465 #define LINES_SIZE 30
466 string about_txt[LINES_SIZE]; // current lines of about text
468 DATAFILE *datastream; // data stream for reading about text
470 char *readstream; // stream for reading about text
472 int xstream = 0; // where I'm reading the stream?
474 datastream = menu_datafile.get_resource("ABOUT_TEXT"); // get about text
476 readstream = (char *)datastream->dat;
478 int text_shift_y = 0; // y displacement for smooth text movement
481 if (snd_loop_sample != NULL)
482 play_sample(snd_loop_sample, 255, 128, 1000, TRUE);
484 clear_keybuf();
486 while (!keypressed())
488 blit(back, dbuf, 0, 0, 0, 0, back->w, back->h);
490 if (text_shift_y > text_height(font_about))
492 text_shift_y = 0;
494 // shift 1 up all text in string array
495 for (int i = 0; i < LINES_SIZE - 1; i ++)
497 about_txt[i] = about_txt[i + 1];
500 // take input from user
501 about_txt[LINES_SIZE - 1] = "";
503 while (xstream < datastream->size && readstream[xstream] > 13)
505 // read current line from stream
506 about_txt[LINES_SIZE - 1] = about_txt[LINES_SIZE - 1] + readstream[xstream];
507 xstream++;
510 while (xstream < datastream->size && readstream[xstream] <= 13)
511 xstream++; // skip bad chars (CR, LF, etc)
513 if (xstream >= datastream->size)
514 xstream ++; // if we reached end, keep counting, so the thing starts again
516 if (xstream > datastream->size + LINES_SIZE)
517 xstream = 0; // start again after a whole clear screen
521 // write text
522 int ytext = -5 - (text_height(font_about) / 2) - text_shift_y; // starting (a little above screen top, to make the effect OK)
524 for (int i = 0; i < LINES_SIZE; i ++)
526 text_mode( -1);
527 // the text is rendered in a way so the text is outlined, thats why is rendered many times
529 //textout_centre(dbuf, font_about, about_txt[i].c_str(), SCREEN_W/2+2, ytext-2, makecol(0,0,200));
530 //textout_centre(dbuf, font_about, about_txt[i].c_str(), SCREEN_W/2+2, ytext+2, makecol(0,0,200));
531 //textout_centre(dbuf, font_about, about_txt[i].c_str(), SCREEN_W/2-2, ytext-2, makecol(0,0,200));
532 //textout_centre(dbuf, font_about, about_txt[i].c_str(),SCREEN_W/2-2, ytext+2, makecol(0,0,200));
534 textout_centre(dbuf, font_about, about_txt[i].c_str(), SCREEN_W / 2 + 3, ytext + 3, makecol(0, 0, 0));
536 textout_centre(dbuf, font_about, about_txt[i].c_str(), SCREEN_W / 2, ytext, makecol(255, 255, 255));
537 ytext += text_height(font_about);
540 text_shift_y++; // this makes the 'smooth' scrolling possible :^O (/me pats himself on the back... good job boy...)
542 blit(dbuf, screen, 0, 0, 0, 0, back->w, back->h);
544 rest(7); // do a little pause (time in ms)
547 if (snd_loop_sample != NULL)
548 stop_sample(snd_loop_sample);
550 clear_keybuf();
552 #undef LINES_SIZE
555 // ------------------------------------------------------------------
556 // Options menu
557 // ------------------------------------------------------------------
558 void CGameMenu::do_options_menu()
560 CQMenu menu;
561 int ret = 0;
562 mtracer.add("CGameMenu::do_options_menu() started\n");
564 set_config_file("kball.cfg");
565 menu.control.load_configuration_of_controller("KBALL_CONTROLLER");
566 game_kernel.player_ball.control.load_configuration_of_controller("KBALL_CONTROLLER");
568 menu.set_to_bitmap(screen);
569 menu.set_back_bitmap(menu_back);
570 menu.set_callback_drawer(menu_callback_animation);
571 menu.text_align = 2;
572 menu.set_xywh(SCREEN_W / 2, 100, SCREEN_W, SCREEN_H);
573 menu.item_y_separation = 5;
575 menu.set_font_s((FONT *)menu_datafile.get_resource_dat("MENU_FONT_MEDIUM"));
576 menu.set_fg_color_s(makecol(255, 255, 255));
577 menu.set_bg_color_s(makecol(0, 0, 200));
579 menu.set_font_ns((FONT *)menu_datafile.get_resource_dat("MENU_FONT_MEDIUM"));
580 menu.set_fg_color_ns(makecol(128, 128, 128));
581 menu.set_bg_color_ns( -1);
583 while (ret != 8)
585 menu.clear_menu_list();
587 if (game_kernel.player_ball.control.use_keyboard)
588 menu.add_item_to_menu("Keyboard is ON");
589 else
590 menu.add_item_to_menu("Keyboard is OFF");
592 menu.add_item_to_menu("Configure Keyboard");
594 if (game_kernel.player_ball.control.use_mouse)
595 menu.add_item_to_menu("Mouse is ON");
596 else
597 menu.add_item_to_menu("Mouse is OFF");
599 menu.add_item_to_menu("Configure Mouse");
601 if (game_kernel.player_ball.control.use_joystick)
602 menu.add_item_to_menu("Joystick is ON");
603 else
604 menu.add_item_to_menu("Joystick is OFF");
606 menu.add_item_to_menu("Configure Joystick");
608 if (CSoundWrapper::global_is_enabled())
609 menu.add_item_to_menu("Sound is ON");
610 else
611 menu.add_item_to_menu("Sound is OFF");
613 // add sound volume
614 char tmpstrvol[256];
615 usprintf(tmpstrvol, "Sound volume %3d%%", CSoundWrapper::global_get_volume()*100/255);
616 menu.add_item_to_menu(tmpstrvol);
618 menu.add_item_to_menu("< Return >");
620 set_config_file("kball.cfg");
622 menu.control.load_configuration_of_controller("KBALL_CONTROLLER");
624 soundw.music_resume();
626 ret = menu.do_the_menu(ret);
628 soundw.music_pause();
630 switch (ret)
633 case 0: // toggle keyboard
634 game_kernel.player_ball.control.use_keyboard = !game_kernel.player_ball.control.use_keyboard;
635 break;
637 case 1: // configure keyb
638 blit (bmp_real_background, screen, 0, 0, 0, 0, bmp_real_background->w, bmp_real_background->h);
639 game_kernel.player_ball.control.interactive_configuration_keyboard((FONT *)menu_datafile.get_resource_dat("MENU_FONT_SMALL"), makecol(0, 255, 255));
640 break;
642 case 2: // toggle mouse
643 game_kernel.player_ball.control.use_mouse = !game_kernel.player_ball.control.use_mouse;
644 break;
646 case 3: // configure mouse
647 blit (bmp_real_background, screen, 0, 0, 0, 0, bmp_real_background->w, bmp_real_background->h);
648 game_kernel.player_ball.control.interactive_configuration_mouse((FONT *)menu_datafile.get_resource_dat("MENU_FONT_SMALL"), makecol(0, 255, 255));
649 break;
651 case 4: // toggle joystick
652 game_kernel.player_ball.control.use_joystick = !game_kernel.player_ball.control.use_joystick;
653 break;
655 case 5: // configure joy
656 blit (bmp_real_background, screen, 0, 0, 0, 0, bmp_real_background->w, bmp_real_background->h);
657 game_kernel.player_ball.control.interactive_configuration_joystick((FONT *)menu_datafile.get_resource_dat("MENU_FONT_SMALL"), makecol(0, 255, 255));
658 break;
660 case 6: // sound
661 CSoundWrapper::global_set_enabled(!CSoundWrapper::global_is_enabled());
662 break;
664 case 7: // toggle sound volume
667 int v = CSoundWrapper::global_get_volume();
668 v += 15;
670 if (v > 255)
671 v = 0;
673 CSoundWrapper::global_set_volume(v);
675 soundw.music_stop(); // DEBUG - MUSIC GLITCH TO AJUST MUSIC ; THIS IS ALMOST A BUG
676 soundw.music_start();
678 break;
682 set_config_file("kball.cfg");
683 game_kernel.player_ball.control.save_configuration_of_controller("KBALL_CONTROLLER");