Logo Search packages:      
Sourcecode: kball version File versions  Download package

gamemenu.cpp

// ------------------------------------------------------------------
// gamemenu.cpp
// ------------------------------------------------------------------
// This has the menu of the Kball game
// ------------------------------------------------------------------
// Developed By Kronoman - Copyright (c) 2004
// In loving memory of my father
// ------------------------------------------------------------------

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// DEBUG -- THIS FILE IS A MESS, DO SOMETHING ABOUT IT (SPANK IT?)
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

// Dig up her bones!!!
#include "filehelp.h"
#include "gamemenu.h" // I need my prototypes
#include "sound.h" // I need the sound system

// some globals needed by callback
CParticleManager menu_particle_manager; // our own particle managar :^D -- REMEMBER TO CALL NUKE PARTICLES BEFORE LEAVING!
BITMAP *bmp_real_background = NULL; // menu real background
CSoundWrapper *sound_menu = NULL; // sound manager of game menu object

// ------------------------------------------------------------------
// This callback function produces the background animation in the menus
// also, polls the music
// ------------------------------------------------------------------
void menu_callback_animation(CQMenu &d, bool do_logic)
{
      BITMAP *bmp = NULL;

      if (sound_menu) // poll music
            sound_menu->music_poll();
      
      time_t t_now = time(NULL); // get current time, for displaying it, and also, for little surprise :O

      struct tm *time_now_local = localtime (&t_now); // get finally the time in appropiate format

      bmp = d.get_back_bitmap();

      if (bmp == NULL)
            return ; // can't draw :(

      // DEBUG -- improve this animation
      if (do_logic) // update logic
      {
            menu_particle_manager.update_logic();
            // add particles at random
            if (rand() % 100 > 95)
            {
                  int c, x, y; // color, pos of explosion

                  switch (rand() % 4) // pick color scheme
                  {

                        case 0:
                        c = makecol(255, rand() % 256, 0);
                        break;

                        case 1:
                        c = makecol(0, rand() % 256, 255);
                        break;

                        case 2:
                        c = makecol(rand() % 256, 0, 255);
                        break;

                        case 3:
                        c = makecol(rand() % 256, 255, 0);
                        break;

                        default:
                        c = makecol(rand() % 256, rand() % 256, rand() % 256);
                        break;
                  }

                  x = (rand() % (int)(SCREEN_W * 0.8)) + (int)(SCREEN_W * 0.1); // use 80% of screen width
                  y = (rand() % (int)(SCREEN_H * 0.8)) + (int)(SCREEN_H * 0.1); // use 80% of screen height
                  for (int i = 0; i < rand() % 50 + 100; i++) // add particles
                  {
                        if (rand() % 100 < 85)
                              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));
                        else
                              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));
                  }

                  // a little text message
                  if (time_now_local->tm_mday == 30 && time_now_local->tm_mon == 3 && rand() % 100 < 75)
                        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 $$$! ;)")) ) );

                  if (time_now_local->tm_year + 1900 >= 2010 && rand() % 100 < 75)
                  {
                        char tmpstr[256];
                        usprintf(tmpstr, "Yeah! My game still runs in %d", 1900 + time_now_local->tm_year);

                        if (time_now_local->tm_year + 1900 > 2082 && rand() % 100 < 75)
                              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 :'(") ) );
                        else
                              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) ) );
                  }

            }
      }
      else
      {
            // draw particles
            if (bmp_real_background != NULL)
                  blit (bmp_real_background, bmp, 0, 0, 0, 0, bmp_real_background->w, bmp_real_background->h);
            else
                  clear(bmp);

            //set_trans_blender(128,128,128,128);
            //drawing_mode(DRAW_MODE_TRANS, NULL,0,0);
            menu_particle_manager.render(bmp, 0, 0);

            //solid_mode();

            // show time of day
            char tbufstr[256]; // time string buffer

            strftime(tbufstr, 255, "%b %d %Y %H:%M:%S", time_now_local); // This function formats the time data

            text_mode( -1);

            textout(bmp, font, tbufstr, 0, bmp->h - text_height(font), makecol(128, 0, 255));
      }
}


CGameMenu::CGameMenu()
{
      mtracer.add("CGameMenu::CGameMenu()");

      menu_back = NULL; // doble buffer bitmap for menu
}

CGameMenu::~CGameMenu()
{
      mtracer.add("CGameMenu::~CGameMenu()");
      // DEBUG!
      // 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!)
}

// ------------------------------------------------------------------
// This shows the main menu to the user
// This is the menu that let the user choose the main options
// ------------------------------------------------------------------
void CGameMenu::do_main_menu()
{
      CQMenu menu; // menu to use/show
      char tmp_file_buf[2048];

      mtracer.add("CGameMenu::do_main_menu() started");

      // I set this so the callback 'knows' the sound manager
      sound_menu = &this->soundw;
      //soundw.set_enabled(true);
      
      int ret = 0;

      clear_bitmap(screen);
      textout_centre_ex(screen, font, "[   Please wait... loading...   ]", SCREEN_W / 2, SCREEN_H / 2, makecol(255, 255, 255), makecol(0, 0, 64));

      menu_datafile.load_datafile(where_is_the_filename(tmp_file_buf, "gui.dat")); // load datafile

      // set music
      soundw.music_load((DUH *)menu_datafile.get_resource_dat("MENU_MUSIC_XM"));
      
      bmp_real_background = (BITMAP *)menu_datafile.get_resource_dat("MENU_BMP_BACKGROUND"); // get back bmp image

      // set some gravity to particles
      menu_particle_manager.add_dy = 0.08;

      menu_back = create_bitmap(SCREEN_W, SCREEN_H); // DEBUG -- HERE I SHOULD LOAD THE BACKGROUND FROM DATAFILE!
      if (menu_back == NULL)
            raise_error("do_main_menu()\nERROR: can't create menu_back bitmap!");

      clear(menu_back);

      menu.set_to_bitmap(screen);

      menu.set_back_bitmap(menu_back);

      menu.set_callback_drawer(menu_callback_animation);

      menu.set_font_s((FONT *)menu_datafile.get_resource_dat("MENU_FONT_BIG"));

      menu.set_fg_color_s(makecol(255, 255, 255));

      menu.set_bg_color_s(makecol(0, 0, 200));

      menu.set_font_ns((FONT *)menu_datafile.get_resource_dat("MENU_FONT_BIG"));

      menu.set_fg_color_ns(makecol(128, 128, 128));

      menu.set_bg_color_ns( -1);

      menu.set_xywh(320, 100, SCREEN_W, SCREEN_H);

      menu.text_align = 2; // center align

      menu.item_y_separation = 25;

      // add menu items
      menu.add_item_to_menu(string("Start new game")); // 0

      menu.add_item_to_menu(string("Options")); // 1

      menu.add_item_to_menu(string("Credits")); // 2

      menu.add_item_to_menu(string("Map editor")); // 3

      menu.add_item_to_menu(string("Quit")); // 4

      while (ret != 4) // 4 = quit
      {
            set_config_file("kball.cfg");
            menu.control.load_configuration_of_controller("KBALL_CONTROLLER");
            
            soundw.music_resume();
            
            ret = menu.do_the_menu(); // show the menu
            
            soundw.music_pause();
            
            switch (ret)
            {

                  case 0:      // start
                  do_file_level_selector();
                  break;

                  case 1:      // options
                  do_options_menu();
                  break;

                  case 2:      // credits
                  do_about_stuff();
                  break;

                  case 3:      // map editor (from hell they came...)
                  map_editor.start_map_editor();
                  break;

                  case 4:      // quit
                  for (int yi = 0; yi < SCREEN_H; yi += 2)
                        hline(screen, 0, yi, SCREEN_W, makecol(0, 0, 20));

                  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));

                  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));

                  clear_keybuf();

                  rest(25);

                  clear_keybuf();

                  if ((readkey() >> 8) != KEY_Y)
                  {
                        ret = -1; // abort exit
                  }

                  break;
            }

            rest(100);
            clear_keybuf();
      }

      // DEBUG -- REMEMBER HERE TO FREE THE MEMORY/OBJECTS USED!
      destroy_bitmap(menu_back);

      menu_particle_manager.nuke_particle_list(); // destroy particles

      menu_datafile.nuke_datafile(); // free RAM of datafile

      bmp_real_background = NULL;
}

// ------------------------------------------------------------------
// This lets the user choose a level to start it, or a full campaign
// It WILL start a game
// For this, it list on a menu the files of the current directory
// This should *ONLY* be called from main menu, otherwise data needed
// for menu will be absent on RAM (have a nice SEG FAULT!)
// ------------------------------------------------------------------
void CGameMenu::do_file_level_selector()
{
      // the level path is defined as [install dir]/levels

      al_ffblk dir_reader;
      char path_str[2048]; // path to level to play
      char level_path[2048]; // full path to levels in general (dir/kball/bin/levels, etc)
      CQMenu menu;
      int ret = 0;
      bool full_campaign = false; // we are going to play full campaing, or single map?

      mtracer.add("CGameMenu::do_file_level_selector() started\n");

      set_config_file("kball.cfg");
      menu.control.load_configuration_of_controller("KBALL_CONTROLLER");

      menu.set_to_bitmap(screen);
      menu.set_back_bitmap(menu_back);
      menu.set_callback_drawer(menu_callback_animation);
      menu.text_align = 2;
      menu.item_y_separation = 25;

      // let choose single level, or campaign
      menu.set_font_s((FONT *)menu_datafile.get_resource_dat("MENU_FONT_BIG"));
      menu.set_fg_color_s(makecol(255, 255, 255));
      menu.set_bg_color_s(makecol(0, 0, 200));

      menu.set_font_ns((FONT *)menu_datafile.get_resource_dat("MENU_FONT_BIG"));
      menu.set_fg_color_ns(makecol(128, 128, 128));
      menu.set_bg_color_ns( -1);
      menu.set_xywh(320, 100, SCREEN_W, SCREEN_H);

      menu.clear_menu_list();
      menu.add_item_to_menu("Full campaign");
      menu.add_item_to_menu("Single level");
      menu.add_item_to_menu("< Cancel and return >");

      // get level
      get_executable_name(level_path, 2048);
      replace_filename(level_path, level_path, "", 2048);
      append_filename(level_path, level_path, "levels", 2048);

      fix_filename_slashes(level_path);
      mtracer.add("--> \t Level path == %s", level_path);

      soundw.music_resume();
      
      switch (menu.do_the_menu()) // show the menu and act in consecuence)
      {
            
            
            case 0:
            soundw.music_pause();
            usprintf(path_str, "%s/*.fmp", level_path);
            full_campaign = true;
            break;

            case 1:
            soundw.music_pause();
            usprintf(path_str, "%s/*.map", level_path);
            full_campaign = false;
            break;

            default:
            soundw.music_pause();
            return ;
            break;
      }

      fix_filename_slashes(path_str);


      // --- Now, list files to use ---
      menu.set_font_s((FONT *)menu_datafile.get_resource_dat("MENU_FONT_MEDIUM"));
      menu.set_fg_color_s(makecol(255, 255, 255));
      menu.set_bg_color_s(makecol(0, 0, 200));

      menu.set_font_ns((FONT *)menu_datafile.get_resource_dat("MENU_FONT_MEDIUM"));
      menu.set_fg_color_ns(makecol(128, 128, 128));
      menu.set_bg_color_ns( -1);

      menu.set_xywh(320, 100, SCREEN_W, SCREEN_H);
      menu.item_y_separation = 5;

      menu.clear_menu_list();

      // read files and populate menu with them
      ret = al_findfirst(path_str, &dir_reader, FA_ARCH);

      while (!ret)
      {
            menu.add_item_to_menu(dir_reader.name);
            ret = al_findnext(&dir_reader);
      }

      al_findclose(&dir_reader);

      // if we don't have items, we must return with a message
      if (menu.get_menu_item_count() < 1)
      {
            menu.clear_menu_list();
            menu.add_item_to_menu("ERROR: NO FILE AVAILABLE!");
            
            soundw.music_resume();
            
            menu.do_the_menu();
            
            soundw.music_pause();
            return ; // abort the mission :^P
      }

      menu.add_item_to_menu("< Cancel and return >");
      
      soundw.music_resume();
      
      ret = menu.do_the_menu(); // show the menu
      
      soundw.music_pause();
      
      if (ret == menu.get_menu_item_count() - 1)
            return ; // last item == cancel, then, cancel

      // get the file name
      usprintf(path_str, "%s/%s", level_path, menu.get_menu_item_text(ret).c_str());

      fix_filename_slashes(path_str);

      // play the game - rock 'n roll!
      set_config_file("kball.cfg");

      game_kernel.player_ball.control.load_configuration_of_controller("KBALL_CONTROLLER");

      text_mode(makecol(0, 0, 0));

      if (full_campaign)
      {
            mtracer.add("CGameMenu::do_file_level_selector()\n\tStarting campaign game\n");

            game_kernel.player_ball.lives = BALL_LIVES_CAMPAIGN; // ball of the player lives
            game_kernel.player_ball.score = 0;
            game_kernel.stats.reset();
            game_kernel.play_a_full_campaign(path_str);

            mtracer.add("CGameMenu::do_file_level_selector()\n\tEnd of campaign game\n");
      }
      else
      {
            // start single level game play
            mtracer.add("CGameMenu::do_file_level_selector()\n\tStarting single level game\n");

            game_kernel.player_ball.lives = BALL_LIVES; // ball of the player lives
            game_kernel.player_ball.score = 0;
            game_kernel.stats.reset();
            game_kernel.play_a_single_level(path_str);

            mtracer.add("CGameMenu::do_file_level_selector()\n\tEnd of single level game\n");
      }

}

// ------------------------------------------------------------------
// This shows the 'About' stuff
// ------------------------------------------------------------------
void CGameMenu::do_about_stuff()
{
      mtracer.add("CGameMenu::do_about_stuff();");

      BITMAP *back = (BITMAP *)menu_datafile.get_resource_dat("ABOUT_BACKGROUND"); // get back bmp image
      BITMAP *dbuf = create_bitmap(SCREEN_W, SCREEN_H);
      FONT *font_about = (FONT *)menu_datafile.get_resource_dat("MENU_FONT_SMALL");
      SAMPLE *snd_loop_sample = (SAMPLE *)menu_datafile.get_resource_dat("ABOUT_BACK_SOUND"); // back sound
      if (dbuf == NULL)
      {
            mtracer.add("CGameMenu::do_about_stuff() -- ERROR!!! Can't create dbuf bitmap!");
            return ;
      }

#define LINES_SIZE 30
      string about_txt[LINES_SIZE]; // current lines of about text

      DATAFILE *datastream; // data stream for reading about text

      char *readstream; // stream for reading about text

      int xstream = 0; // where I'm reading the stream?

      datastream = menu_datafile.get_resource("ABOUT_TEXT"); // get about text

      readstream = (char *)datastream->dat;

      int text_shift_y = 0; // y displacement for smooth text movement


      if (snd_loop_sample != NULL)
            play_sample(snd_loop_sample, 255, 128, 1000, TRUE);

      clear_keybuf();

      while (!keypressed())
      {
            blit(back, dbuf, 0, 0, 0, 0, back->w, back->h);

            if (text_shift_y > text_height(font_about))
            {
                  text_shift_y = 0;

                  // shift 1 up all text in string array
                  for (int i = 0; i < LINES_SIZE - 1; i ++)
                  {
                        about_txt[i] = about_txt[i + 1];
                  }

                  // take input from user
                  about_txt[LINES_SIZE - 1] = "";

                  while (xstream < datastream->size && readstream[xstream] > 13)
                  {
                        // read current line from stream
                        about_txt[LINES_SIZE - 1] = about_txt[LINES_SIZE - 1] + readstream[xstream];
                        xstream++;
                  }

                  while (xstream < datastream->size && readstream[xstream] <= 13)
                        xstream++; // skip bad chars (CR, LF, etc)

                  if (xstream >= datastream->size)
                        xstream ++; // if we reached end, keep counting, so the thing starts again

                  if (xstream > datastream->size + LINES_SIZE)
                        xstream = 0; // start again after a whole clear screen
            }


            // write text
            int ytext = -5 - (text_height(font_about) / 2) - text_shift_y; // starting (a little above screen top, to make the effect OK)

            for (int i = 0; i < LINES_SIZE; i ++)
            {
                  text_mode( -1);
                  // the text is rendered in a way so the text is outlined, thats why is rendered many times

                  //textout_centre(dbuf, font_about, about_txt[i].c_str(), SCREEN_W/2+2, ytext-2, makecol(0,0,200));
                  //textout_centre(dbuf, font_about, about_txt[i].c_str(), SCREEN_W/2+2, ytext+2, makecol(0,0,200));
                  //textout_centre(dbuf, font_about, about_txt[i].c_str(), SCREEN_W/2-2, ytext-2, makecol(0,0,200));
                  //textout_centre(dbuf, font_about, about_txt[i].c_str(),SCREEN_W/2-2, ytext+2, makecol(0,0,200));

                  textout_centre(dbuf, font_about, about_txt[i].c_str(), SCREEN_W / 2 + 3, ytext + 3, makecol(0, 0, 0));

                  textout_centre(dbuf, font_about, about_txt[i].c_str(), SCREEN_W / 2, ytext, makecol(255, 255, 255));
                  ytext += text_height(font_about);
            }

            text_shift_y++; // this makes the 'smooth' scrolling possible :^O (/me pats himself on the back... good job boy...)

            blit(dbuf, screen, 0, 0, 0, 0, back->w, back->h);

            rest(7); // do a little pause (time in ms)
      }

      if (snd_loop_sample != NULL)
            stop_sample(snd_loop_sample);

      clear_keybuf();

#undef LINES_SIZE
}

// ------------------------------------------------------------------
// Options menu
// ------------------------------------------------------------------
void CGameMenu::do_options_menu()
{
      CQMenu menu;
      int ret = 0;
      mtracer.add("CGameMenu::do_options_menu() started\n");

      set_config_file("kball.cfg");
      menu.control.load_configuration_of_controller("KBALL_CONTROLLER");
      game_kernel.player_ball.control.load_configuration_of_controller("KBALL_CONTROLLER");

      menu.set_to_bitmap(screen);
      menu.set_back_bitmap(menu_back);
      menu.set_callback_drawer(menu_callback_animation);
      menu.text_align = 2;
      menu.set_xywh(SCREEN_W / 2, 100, SCREEN_W, SCREEN_H);
      menu.item_y_separation = 5;

      menu.set_font_s((FONT *)menu_datafile.get_resource_dat("MENU_FONT_MEDIUM"));
      menu.set_fg_color_s(makecol(255, 255, 255));
      menu.set_bg_color_s(makecol(0, 0, 200));

      menu.set_font_ns((FONT *)menu_datafile.get_resource_dat("MENU_FONT_MEDIUM"));
      menu.set_fg_color_ns(makecol(128, 128, 128));
      menu.set_bg_color_ns( -1);

      while (ret != 8)
      {
            menu.clear_menu_list();

            if (game_kernel.player_ball.control.use_keyboard)
                  menu.add_item_to_menu("Keyboard is ON");
            else
                  menu.add_item_to_menu("Keyboard is OFF");

            menu.add_item_to_menu("Configure Keyboard");

            if (game_kernel.player_ball.control.use_mouse)
                  menu.add_item_to_menu("Mouse is ON");
            else
                  menu.add_item_to_menu("Mouse is OFF");

            menu.add_item_to_menu("Configure Mouse");

            if (game_kernel.player_ball.control.use_joystick)
                  menu.add_item_to_menu("Joystick is ON");
            else
                  menu.add_item_to_menu("Joystick is OFF");

            menu.add_item_to_menu("Configure Joystick");

            if (CSoundWrapper::global_is_enabled())
                  menu.add_item_to_menu("Sound is ON");
            else
                  menu.add_item_to_menu("Sound is OFF");

            // add sound volume
            char tmpstrvol[256];
            usprintf(tmpstrvol, "Sound volume %3d%%",  CSoundWrapper::global_get_volume()*100/255);
            menu.add_item_to_menu(tmpstrvol);

            menu.add_item_to_menu("< Return >");

            set_config_file("kball.cfg");

            menu.control.load_configuration_of_controller("KBALL_CONTROLLER");
            
            soundw.music_resume();
            
            ret = menu.do_the_menu(ret);
            
            soundw.music_pause();
            
            switch (ret)
            {

                  case 0:      // toggle keyboard
                  game_kernel.player_ball.control.use_keyboard = !game_kernel.player_ball.control.use_keyboard;
                  break;

                  case 1:      // configure keyb
                  blit (bmp_real_background, screen, 0, 0, 0, 0, bmp_real_background->w, bmp_real_background->h);
                  game_kernel.player_ball.control.interactive_configuration_keyboard((FONT *)menu_datafile.get_resource_dat("MENU_FONT_SMALL"), makecol(0, 255, 255));
                  break;

                  case 2:      // toggle mouse
                  game_kernel.player_ball.control.use_mouse = !game_kernel.player_ball.control.use_mouse;
                  break;

                  case 3:      // configure mouse
                  blit (bmp_real_background, screen, 0, 0, 0, 0, bmp_real_background->w, bmp_real_background->h);
                  game_kernel.player_ball.control.interactive_configuration_mouse((FONT *)menu_datafile.get_resource_dat("MENU_FONT_SMALL"), makecol(0, 255, 255));
                  break;

                  case 4:      // toggle joystick
                  game_kernel.player_ball.control.use_joystick = !game_kernel.player_ball.control.use_joystick;
                  break;

                  case 5:      // configure joy
                  blit (bmp_real_background, screen, 0, 0, 0, 0, bmp_real_background->w, bmp_real_background->h);
                  game_kernel.player_ball.control.interactive_configuration_joystick((FONT *)menu_datafile.get_resource_dat("MENU_FONT_SMALL"), makecol(0, 255, 255));
                  break;

                  case 6:    // sound
                  CSoundWrapper::global_set_enabled(!CSoundWrapper::global_is_enabled());
                  break;

                  case 7:   // toggle sound volume
                  {
                        
                        int v = CSoundWrapper::global_get_volume();
                        v += 15;

                        if (v > 255)
                              v = 0;

                        CSoundWrapper::global_set_volume(v);
                        
                        soundw.music_stop(); // DEBUG - MUSIC GLITCH TO AJUST MUSIC ; THIS IS ALMOST A BUG
                        soundw.music_start();
                  }
                  break;

            }

            set_config_file("kball.cfg");
            game_kernel.player_ball.control.save_configuration_of_controller("KBALL_CONTROLLER");
      }

}


Generated by  Doxygen 1.6.0   Back to index