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

main.c

/***************************************************************************
    copyright            : (C) 2003 by Michael Speck
    email                : http://lgames.sf.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif

#include "defs.h"
#include "shots.h"
#include "units.h"
#include "data.h"
#include "chart.h"
#include "bfield.h"
#include "menu.h"

SDL_Surface *screen;
#define BITDEPTH 16

int delay = 0;
int fullscreen = 1;
int audio_on = 1;
int audio_freq = 22050;
int audio_format = AUDIO_S16LSB;
int audio_channels = 2;
int audio_mix_channel_count = 0;

extern SDL_Surface 
      *img_ammo, *background, *img_ground, *img_logo, *img_icons, *img_black, *img_cursors; 
extern SDL_Font *ft_main, *ft_chart, *ft_chart_highlight, *ft_help, *ft_copyright;
extern SDL_Cursor *cr_empty;
extern int ammo_w, ammo_h;
extern int cursor_w, cursor_x_offset;
extern char *optarg;

Menu main_menu;
enum {
      ID_GAME = 101,
      ID_HELP,
      ID_CHART,
      ID_QUIT
};

Vector gun_base = { 20, 240, 0 };
Vector gun_img_offset = { -9, -20, 0 };

int player_score = 0;
int player_ammo = 0;
char player_name[20] = "Michael"; /* is updated when entering highscore */

int game_start = 0, game_end = 0; /* time in global secs when game started and has to end */

int timer_blink_delay = 0; /* timer starts to blink when time runs out */
int timer_visible = 1; /* used to blink timer */

enum {
      STATE_MENU,
      STATE_HELP,
      STATE_CHART,
      STATE_GAME
};
int state = STATE_MENU; /* state of game */

/* Lets try to get name from environment */
static void set_player_name_from_env() 
{
      char * user_name = getenv("USER");
      if (user_name!=NULL)
      {
            strncpy(player_name, user_name, 19);
      }
};

static void fade_screen( int type, int time )
{
      SDL_Surface *buffer = 0;
      float alpha;
      float alpha_change; /* per ms */
      int leave = 0;
      int ms;
      int cur_ticks, prev_ticks;

      /* get screen contents */
      buffer = SDL_CreateRGBSurface( 
                  SDL_SWSURFACE, screen->w, screen->h, 
                  screen->format->BitsPerPixel,
                  screen->format->Rmask, screen->format->Bmask,
                  screen->format->Gmask, screen->format->Amask );
      if ( buffer == 0 ) return;
      SDL_BlitSurface( screen, 0, buffer, 0 );

      /* compute alpha and alpha change */
      if ( type == FADE_OUT ) {
            alpha = 255;
            alpha_change = -255.0 / time;
      }
      else {
            alpha = 0;
            alpha_change = 255.0 / time;
      }

      /* fade */
      cur_ticks = prev_ticks = SDL_GetTicks();
      while ( !leave ) {
            prev_ticks = cur_ticks;
            cur_ticks = SDL_GetTicks();
            ms = cur_ticks - prev_ticks;
            
            alpha += alpha_change * ms;
            if ( type == FADE_IN && alpha >= 255 ) break;
            if ( type == FADE_OUT && alpha <= 0 ) break;
            
            /* update */
            SDL_FillRect( screen, 0, 0x0 );
            SDL_SetAlpha( buffer, SDL_SRCALPHA | SDL_RLEACCEL, (int)alpha );
            SDL_BlitSurface( buffer, 0, screen, 0 );
            SDL_Flip(screen);
            if (delay>0) SDL_Delay(10);
      }

      /* update screen */
      SDL_SetAlpha( buffer, 0, 0 );
      if ( type == FADE_IN )
            SDL_BlitSurface( buffer, 0, screen, 0 );
      else
            SDL_FillRect( screen, 0, 0x0 );
      SDL_Flip(screen);
      SDL_FreeSurface( buffer );
}

static int all_filter( const SDL_Event *event ) { return 0; }

static void wait_for_input( void )
{
      SDL_EventFilter filter;
      SDL_Event event;
      
      filter = SDL_GetEventFilter();
      SDL_SetEventFilter(all_filter);
      while ( SDL_PollEvent(&event) ); /* clear queue */
      SDL_SetEventFilter(filter);
      
      while ( 1 ) {
            SDL_WaitEvent(&event);
            if (event.type == SDL_QUIT) {
                  return;
            }
            if (event.type == SDL_KEYDOWN || event.type == SDL_MOUSEBUTTONDOWN)
                  return;
      }
}

static void draw_score()
{
      char str[8];

      if ( player_score < 0 ) player_score = 0;
      snprintf( str, 8, "%06i", player_score ); str[7] = 0;
      SDL_WriteText( ft_main, screen, 10, 10, str );
}

static void draw_time( int ms )
{
      static int old_secs = 0;
      char str[8];
      int secs = game_end - time(0);
      
      /* blink timer when time is running out in such a way
       * that it becomes visible everytime a new second started */
      if ( secs < 30 ) {
            if ( timer_blink_delay )
            if ( (timer_blink_delay-=ms) <= 0 )
                  timer_visible = 0;
            if ( secs != old_secs ) {
                  timer_visible = 1;
                  timer_blink_delay = 500;
                  old_secs = secs;
            }
      }
      
      if ( !timer_visible ) return;
      snprintf( str, 8, "%i:%02i", secs/60, secs%60 ); str[7] = 0;
      SDL_WriteTextRight( ft_main, screen, 630, 10, str );
}

static void draw_ammo()
{
      int i, full, rest;
      SDL_Rect drect, srect;
      
      full = player_ammo / AMMO_BOMB; /* one tile represents a bomb ammo which
                                 contains of AMMO_BOMB single grenade shots */
      rest = player_ammo % AMMO_BOMB; /* first ammo may contain less than AMMO_BOMB ammo */
      
      drect.w = srect.w = ammo_w;
      drect.h = srect.h = ammo_h;
      srect.x = 0; srect.y = 0;
      drect.y = 480 - 10 - drect.h;
      drect.x = 10;

      for ( i = 0; i < full; i++ ) { 
            SDL_BlitSurface( img_ammo, &srect, screen, &drect );
            drect.y -= drect.h;
      }

      if ( rest > 0 ) {
            srect.y = (AMMO_BOMB - rest) * ammo_h;
            SDL_BlitSurface( img_ammo, &srect, screen, &drect );
      }
}

extern BField bfield;
/* draw cursor centered at x,y */
static void draw_cursor( SDL_Surface *dest, int x, int y )
{
      SDL_Rect srect,drect;

      drect.w = srect.w = cursor_w;
      drect.h = srect.h = img_cursors->h;
      srect.x = cursor_x_offset; srect.y = 0;
      /* XXX: within gun strip, gun cannot be fired; to indicate this use
       * disabled cursor instead of current selection. (bad hack, state
       * should be properly set somewhere) */
      if ( x < STRIP_OFFSET && !bfield.demo )
            srect.x = CURSOR_DISABLED * cursor_w;
      drect.x = x - (cursor_w>>1); drect.y = y - (img_cursors->h>>1);
      SDL_BlitSurface( img_cursors, &srect, dest, &drect );
}

/* add copyright */
static void draw_logo_centered( SDL_Surface *dest, int y )
{
      SDL_Rect drect;

      drect.x = (dest->w-img_logo->w)/2;
      drect.y = y;
      drect.w = dest->w; drect.h = dest->h;

      SDL_BlitSurface( img_logo, 0, dest, &drect );

      SDL_WriteText( ft_copyright, dest, 4, 454, "(C) 2003-2010 Michael Speck" );
      SDL_WriteTextRight( ft_copyright, dest, 636, 454, "http://lgames.sf.net" );
}

#define LINE(y,text) SDL_WriteText(ft_help,dest,x,y,text)
static void draw_help( SDL_Surface *dest )
{
      int x = 70, target_y = 60, gun_y = 180, hint_y = 350;
      SDL_Rect srect, drect;

      SDL_BlitSurface( img_black, 0, dest, 0 );
      
      /* objective */
      LINE(10,"Your objective is to destroy as many dummy" );
      LINE(30,"targets as possible within 3 minutes." );
      
      /* icons and points */
      SDL_WriteText( ft_help, dest, x,target_y, "Target Scores:" );
      srect.w = drect.w = 30;
      srect.h = drect.h = 30;
      srect.y = 0; drect.y = target_y+20;
      srect.x = 0; drect.x = x; 
      SDL_BlitSurface( img_icons, &srect, dest, &drect );
      SDL_WriteText( ft_help, dest, x + 34,target_y+24, "Soldier: 5 Pts" );
      srect.x = 30; drect.x = x+180;
      SDL_BlitSurface( img_icons, &srect, dest, &drect );
      SDL_WriteText( ft_help, dest, x+214,target_y+24, "Jeep: 20 Pts" );
      srect.x = 60; drect.x = x+350;
      SDL_BlitSurface( img_icons, &srect, dest, &drect );
      SDL_WriteText( ft_help, dest, x+384,target_y+24, "Tank: 50 Pts" );
      SDL_WriteText( ft_help, dest, x,target_y+50, 
                  "If a jeep makes it safe through the screen you'll" );
      SDL_WriteText( ft_help, dest, x,target_y+70, 
                  "loose 10 pts. For a tank you'll loose 25 pts. For" );
      SDL_WriteText( ft_help, dest, x,target_y+90,
                  "soldiers there is no such penalty." );

      /* gun handling */
      LINE(gun_y,    "Gun Handling:");
      LINE(gun_y+20, "The gun is controlled by the mouse. Move the");
      LINE(gun_y+40, "crosshair at the target and left-click to fire a" );
      LINE(gun_y+60, "large grenade. (costs 6 rounds, 0.5 secs fire rate)");
      LINE(gun_y+80, "Middle-click to fire a small grenade. (1 round)" );
      LINE(gun_y+100,"Use the right mouse button to reload your gun" );
      LINE(gun_y+120,"to the full 36 rounds. Reloading always costs" );
      LINE(gun_y+140,"36 points so do this as late as possible." );

      /* hint */
      LINE(hint_y,    "NOTE: A tank cannot be damaged by small" ); 
      LINE(hint_y+20, "grenades which you should only use at soldiers" );
      LINE(hint_y+40, "and jeeps when you are experienced enough in" );
      LINE(hint_y+60, "aiming. For rookies it is much better to only" );
      LINE(hint_y+80, "use the large grenades (left-click), count the" );
      LINE(hint_y+100,"shots and reload after six times. (right-click)" );
}

static void take_screenshot()
{
      char buf[32];
      static int i;
      sprintf( buf, "screenshot%i.bmp", i++ );
      SDL_SaveBMP( screen, buf );

}

static void game_init()
{
      bfield_finalize(); /* clear battlefield from menu */
      bfield_init( BFIELD_GAME, &gun_base, &gun_img_offset );
      player_score = 0;
      player_ammo = MAX_AMMO;

      SET_CURSOR( CURSOR_CROSSHAIR );
      fade_screen( FADE_OUT, 500 );
      SDL_BlitSurface( background, 0, screen, 0 );
      fade_screen( FADE_IN, 500 );

      game_start = time(0); game_end = game_start + GAME_TIME; timer_visible = 1;
}

static void game_finalize( int check_chart )
{
      int rank;
      char buf[64];
      
      bfield_finalize();
      SET_CURSOR( CURSOR_ARROW );

      fade_screen( FADE_OUT, 500 );
      bfield_init( BFIELD_DEMO, &gun_base, &gun_img_offset ); /* new battlefield for menu */
      bfield_draw( screen, 0, 0 );
      fade_screen( FADE_IN, 500 );
      
      /* check wether highscore was entered */
      if ( check_chart ) {
            SDL_WriteTextCenter( ft_chart, screen, 320, 130, "The time is up!" );
            sprintf( buf, "Your result is %i points.", player_score );
            SDL_WriteTextCenter( ft_chart, screen, 320, 160, buf );
            if ( ( rank = chart_get_rank( player_score ) ) >= 0 ) {
                  SDL_WriteTextCenter( 
                              ft_chart, screen, 320, 200, "Good job! This makes you" );
                  sprintf( buf, "Topgunner #%i", rank+1 );
                  SDL_WriteTextCenter( ft_chart, screen, 320, 230, buf );
                  SDL_WriteTextCenter( ft_chart, screen, 320, 290, "Sign here:" );
                  SDL_Flip(screen);
                  SDL_EnterTextCenter( ft_chart, screen, 320, 320, 18, player_name );
                  chart_add_entry( player_name, player_score );
            }
            else {
                  SDL_WriteTextCenter( 
                              ft_chart, screen, 320, 290, "Not enough to be a topgunner!" );
                  SDL_WriteTextCenter( 
                              ft_chart, screen, 320, 320, "Go, try again! Dismissed." );
                  SDL_Flip(screen);
                  wait_for_input();
            }
            chart_save();
      }
}
      
static void main_loop()
{
      Uint8 *keystate, empty_keys[SDLK_LAST];
      int x = 0, y = 0;
      int cur_ticks, prev_ticks;
      int ms;
      int buttonstate;
      int reload_clicked = 0;
      int reload_key = SDLK_SPACE;
      int frame_time = 0, frames = 0;
      Vector dest;
      int quit = 0;
      int input_delay = 0; /* while >0 no clicks are accepted */
      SDLMod modstate = 0;
      int shot_type;
      
      frame_time = SDL_GetTicks(); /* for frame rate */
      memset( empty_keys, 0, sizeof( empty_keys ) ); /* to block input */
            
      state = STATE_MENU;
      bfield_init( BFIELD_DEMO, &gun_base, &gun_img_offset );
      
      cur_ticks = prev_ticks = SDL_GetTicks();
      while ( !quit ) {
        if (delay>0) SDL_Delay(delay);
        
            prev_ticks = cur_ticks;
            cur_ticks = SDL_GetTicks();
            ms = cur_ticks - prev_ticks;

            /* gather events in queue and get mouse/keyboard states */
            SDL_PumpEvents();
            buttonstate = SDL_GetMouseState( &x, &y );
            keystate = SDL_GetKeyState( 0 );
            modstate = SDL_GetModState();
      
            /* update the battefield (particles,units,new cannonfodder) */
            bfield_update( ms );

            /* update input_delay */
            if ( input_delay > 0 ) 
            if ( (input_delay-=ms) < 0 ) input_delay = 0;
            
            /* draw ground, trees, units, particles */
            bfield_draw( screen, 0, 0 );
            
            /* according to state draw add-ons */
            switch ( state ) {
                  case STATE_GAME:
                        draw_score();
                        draw_time( ms );
                        draw_ammo();
                        break;
                  case STATE_MENU:
                        draw_logo_centered( screen, 70 );
                        menu_draw( &main_menu, screen );
                        break;
                  case STATE_CHART:
                        chart_draw( screen );
                        break;
                  case STATE_HELP:
                        draw_help( screen );
                        break;
            }
            
            /* add cursor */
            draw_cursor( screen, x, y );
            
            /* udpate screen */
            SDL_Flip(screen); frames++;

            /* end game? */
            if ( state == STATE_GAME )
            if ( time(0) >= game_end ) {
                  game_finalize( 1 /*check highscore*/ );
                  state = STATE_CHART;
                  input_delay = INPUT_DELAY;
                  cur_ticks = prev_ticks = SDL_GetTicks(); /* reset timer */
            }
            
            /* after this point only input is handled */
            if ( input_delay > 0 ) continue;
            
            /* handle input */
            switch ( state ) {
                case STATE_HELP:
                case STATE_CHART:
                  if ( keystate[SDLK_ESCAPE] ||
                       keystate[SDLK_SPACE] || 
                       keystate[SDLK_RETURN] || 
                       keystate[SDLK_SPACE] ||
                       buttonstate ) {
                        input_delay = INPUT_DELAY;
                        state = STATE_MENU;
                        /* clear the selection of the menu entry */
                        menu_handle_motion( &main_menu, -1, -1 );
                  }
                  break;
                case STATE_GAME:
                  /* abort game */
                  if ( keystate[SDLK_ESCAPE] ) {
                        game_finalize( 0/*don't check highscore*/ );
                        cur_ticks = prev_ticks = SDL_GetTicks(); /* reset timer */
                        state = STATE_CHART;
                        input_delay = INPUT_DELAY;
                  }
                  /* set direction of gun */
                  bfield_update_gun_dir( x, y );
                  /* fire gun */
                  if ( bfield_gun_is_ready() ) {
                        dest.x = x; dest.y = y; dest.z = 0;
                        shot_type = ST_NONE;
                        if ( buttonstate & SDL_BUTTON(1) ) {
                              if ( modstate & (KMOD_LCTRL|KMOD_RCTRL) )
                                    shot_type = ST_GRENADE;
                              else
                                    shot_type = ST_BOMB;
                        }
                        if ( buttonstate & SDL_BUTTON(2) )
                              shot_type = ST_GRENADE;
                        if ( shot_type != ST_NONE )
                              bfield_fire_gun( shot_type, &dest, 60, 0 );
                  }
                  /* reload */
                  if ( buttonstate & SDL_BUTTON(3) || keystate[reload_key] ) {
                        if ( !reload_clicked ) {
                              reload_clicked = 1;
                              bfield_reload_gun();
                        }
                  }
                  else
                        reload_clicked = 0;
                  break;
                case STATE_MENU:
                  if ( keystate[SDLK_ESCAPE] )
                        quit = 1;
                  if ( buttonstate & SDL_BUTTON(1) ) {
                        switch (menu_handle_click( &main_menu, x, y ) ) {
                            case ID_QUIT: 
                              quit = 1; 
                              break;
                            case ID_HELP:
                              state = STATE_HELP;
                              input_delay = INPUT_DELAY;
                              break;
                            case ID_CHART: 
                              state = STATE_CHART; 
                              input_delay = INPUT_DELAY;
                              break;
                            case ID_GAME:
                              state = STATE_GAME; 
                              game_init();
                              break;
                        }
                  }
                  else
                        menu_handle_motion( &main_menu, x, y );
                  break;
            }
            
            /* switch fullscreen/window anywhere */
            if ( keystate[SDLK_f] ) {
                  fullscreen = !fullscreen;
                  SDL_SetVideoMode( 640, 480, BITDEPTH, 
                        (fullscreen?SDL_FULLSCREEN:0) | SDL_HWSURFACE | SDL_DOUBLEBUF );
                  input_delay = INPUT_DELAY;
            }
            /* enabe/disable sound anywhere */
            if ( keystate[SDLK_s] ) {
                  audio_on = !audio_on;
                  input_delay = INPUT_DELAY;
            }
            /* take screenshots anywhere */
            if ( keystate[SDLK_TAB] )
                  take_screenshot();
      }

      frame_time = SDL_GetTicks() - frame_time;
      printf( "Time: %.2f, Frames: %i\n", (double)frame_time/1000, frames );
      printf( "FPS: %.2f\n", 1000.0 * frames / frame_time );

      fade_screen( FADE_OUT, 500 );
      
}

int main( int argc, char **argv )
{
  char c;
  
  printf( "BARRAGE v%s\n", VERSION );
  printf( "Copyright 2003-2010 Michael Speck (http://lgames.sf.net)\n" );
  printf( "Released under Gnu GPL\n---\n" );

  while ( ( c = getopt( argc, argv, "d:ws" ) ) != -1 )
    {
      switch (c)
      {
      case 'd': delay = atoi(optarg); break;
      case 'w': fullscreen=0; break;
      case 's': audio_on = 0; break;
      }
    }
  printf("main loop delay: %d ms\n",delay);
      
  srand( time(0) );

  set_player_name_from_env();
      
  if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO ) < 0 ) {
    printf( "%s\n", SDL_GetError() );
    exit(1);
  }
  if ( SDL_SetVideoMode( 640, 480, BITDEPTH, 
                   (fullscreen?SDL_FULLSCREEN:0) | SDL_HWSURFACE | SDL_DOUBLEBUF ) < 0 ) {
    printf( "%s\n", SDL_GetError() );
    exit(1);
  }
  screen = SDL_GetVideoSurface();
  atexit(SDL_Quit);
  SDL_WM_SetCaption( "LBarrage", 0 );
      
#ifdef AUDIO_ENABLED    
  if ( Mix_OpenAudio( audio_freq, audio_format, audio_channels, 1024 ) < 0 ) {
    printf( "%s\n", SDL_GetError() );
    exit(1);
  }
  audio_mix_channel_count = Mix_AllocateChannels( 16 );
#endif
      
  atexit(data_delete); data_load();
  chart_load();

  SDL_SetCursor( cr_empty );
  /* create simple menu */
  menu_init( &main_menu, 230, 40 );
  menu_add_entry( &main_menu, "Enter Shooting Range", ID_GAME );
  menu_add_entry( &main_menu, "Receive Briefing", ID_HELP );
  menu_add_entry( &main_menu, "Topgunners", ID_CHART );
  menu_add_entry( &main_menu, "", 0 );
  menu_add_entry( &main_menu, "Quit", ID_QUIT );
      
  /* run game */
  main_loop();

#ifdef AUDIO_ENABLED
  Mix_CloseAudio();
#endif
      
  return (0);
}

Generated by  Doxygen 1.6.0   Back to index