/*
 * Game.c - Game crap goes here
 * By: Odis
 */
#include <windows.h>
#include "main.h"
#include "game.h"

/* globals...*/
int spause;
DWORD tpause;

static int X,Y;
bool drag_mode_enabled = TRUE;
bool gpause = FALSE;


/* top dog function */
void game_loop( void )
{
    if ( gpause == FALSE )
    {
        SPRITE *s = NULL;
        

        /* add any sprites needed */
        populate_level( lvl );

        bg_update( lvl ); /* update the background */

        UpdateSprites();  /* update sprite movements, collisions, etc */

        /* dodge! dodge! all of you dodge!*/
        for ( s = lvl->first_sprite; s; s = s->next )
          DodgeAI(s);
    }

#ifdef DX
    spause = UMAX( 0, --spause ); /* lower the spause */
#endif

    /* double-buffer! whee! */
    game_paint(memDC); /* now draw */

    HDC hDC = GetDC(game->hWindow);
    BitBlt(hDC, 0, 0, game->width, game->height, memDC, 0, 0, SRCCOPY);
    ReleaseDC(game->hWindow, hDC);
}

/* paint the graphics */
void game_paint(HDC hDC)
{
   char buf[MIL];

   bg_draw(lvl, hDC);

#if defined(VOLUME) || defined(FPS)
   Draw( backbuf, hDC, 0, 0, FALSE, FALSE );
#endif

   /* set the mode..the mode dammit! */
   SetBkMode(hDC, TRANSPARENT);
   SetTextColor(hDC, RGB( 0, 0, 0));

#ifdef FPS
   char fps[20];
   sprintf( fps, "FPS: %d", 1000/game->framedelay);
   TextOut(hDC, 5, 2, fps, strlen(fps) );
#endif

#ifdef VOLUME
 #ifdef DX
   char vol[30];
   sprintf( vol, "Volume: %d", (volume+10000));
   TextOut(hDC, 5, 20, vol, strlen(vol) );
 #else
   char vol[30];
   sprintf( vol, "Volume: Disabled" );
   TextOut(hDC, 5, 20, vol, strlen(vol) );
 #endif
#endif

   /* draw these here so sprites can go over them */

   /* get ready for text */
   SetTextColor(hDC, RGB( 255, 255, 255));
   
   if ( gpause == FALSE )
    DrawSprites( lvl->first_sprite, hDC );
   else
    TextOut(hDC, (PRG_WIDTH-60)/2, (PRG_HEIGHT+18)/2, "PAUSED", strlen("PAUSED"));
}

/* pre-game things */
void game_start(HWND hWindow)
{
    HDC hDC = GetDC( hWindow );

    /* intialize random num gen */
    srand(GetTickCount());

    /* initialize game stuff */

#ifdef LOG
#ifdef XLOG
    init_log(); /* initlialize logging */
#else
    if ( exists_file("log") == FALSE )
     system( "mkdir log" );
#endif
#endif
    
    /* timers */
    start = GetTickCount();
    SetTimer( game->hWindow, T_ID, SECOND, NULL );
#ifdef DX
    SetTimer( game->hWindow, STREAM_TIMER, SECOND*2.1, NULL ); /* 2.1 seconds */
#endif

    /* this needs to be done before load_level, in case the size is changed */
    memDC = CreateCompatibleDC(GetDC(hWindow));
    memBitmap = CreateCompatibleBitmap(GetDC(hWindow), game->width, game->height);
    SelectObject(memDC, memBitmap);

    /* set initial stuff */
    /* initialize level 0 */
    lvl = load_level( game->current_level );
    populate_level( lvl );
    
#ifdef LOG
#ifdef LEVEL_LOG
    if ( lvl != NULL )
    {
#ifdef XLOG
      LT( "Game_Start", MESSAGE, "Level %d loaded and populated. Currently had %d sprites and %d proto-sprites!", lvl->num, lvl->num_sprites, lvl->num_proto );
#else
      glog( "Game_Start: level %d loaded and populated. Currently had %d sprites and %d proto-sprites!", lvl->num, lvl->num_sprites, lvl->num_proto );
#endif
    }
    else
    {
#ifdef XLOG
      LT( "Game_Start", WARNING, "Null level! Expect the worst!", 0 );
#else
      glog( "Game_Start: NULL level! Expect crash!" );
#endif
    }
#endif
#endif

    if ( lvl->bg->type == STARRY )
      init_starry( lvl->bg, MAX_STARS, 75 );

#ifdef DX
    init_dx(lvl->song);

    if ( current_song != MAX_SOUND )
    {
      set_volume( song, volume );
      play_wave( song, TRUE );
    }
#endif

#if defined(VOLUME) || defined(FPS)
 #ifdef DX
  backbuf = bitmap_from_generic(hDC, 110, 40, RGB(255,255,555), "backbuf", FALSE);
 #else
  backbuf = bitmap_from_generic(hDC, 130, 40, RGB(255,255,55), "backbuf", FALSE);
 #endif
#endif

  gpause = FALSE;

  return;
}

/* cleanup functions go here */
void game_end( void )
{
   DeleteObject(memBitmap);
   DeleteDC(memDC);

   clean_level(lvl, TRUE); /* gets rid of everything within the level, including bitmaps*/

#if defined(VOLUME) || defined(FPS) /* special non-linked bitmaps die here */
   FreeBitmap( backbuf );
#endif
   
   /* dispose of player */
   DISPOSE( player->name );
   DISPOSE( player );

   /* stop the timers */
   KillTimer(game->hWindow, T_ID);
#ifdef DX
   KillTimer(game->hWindow, STREAM_TIMER);
#endif
   
   DISPOSE( game ); /* free the game data */
   
   /* free music */
#ifdef DX
  close_dx();
#endif

  return;
}

/*
 * Function is pretty obvious
 */
void handle_keys( void )
{
#ifdef DX
  if ( (GetAsyncKeyState('w') != 0 || GetAsyncKeyState('W') != 0) && spause <= 0) /* play "whoa strange" */
  {
    play_sound(WHOA_STRANGE);
    spause = 50;
  }
#endif

  if ( GetAsyncKeyState('p') != 0 || GetAsyncKeyState('P') != 0 ) /* toggle pause */
  {
     if ( gpause == TRUE )
     {
        gpause = FALSE;

        /* correct time */
        start += (GetTickCount()-tpause);
        tpause = GetTickCount();
        SetTimer( game->hWindow, T_ID, SECOND, NULL );
     }
     else
     {
        gpause = TRUE;
        tpause = GetTickCount();
        KillTimer(game->hWindow ,T_ID);
     }
  }

#ifdef DX
  if ( GetAsyncKeyState(VK_ADD) < 0 && stopped == FALSE)
  {
    volume = URANGE(-10000,volume+100,0);
    set_volume( song, volume );
  }
  
  if ( GetAsyncKeyState(VK_SUBTRACT) < 0 && stopped == FALSE)
  {
     volume = URANGE(-10000,volume-100,0);
     set_volume( song, volume );
  }
  
  if ( GetAsyncKeyState('s') < 0 || GetAsyncKeyState('S') < 0 )
  {
    if ( spause <= 0 )
    {
      if ( stopped == TRUE )
       game_activate();
      else
       game_deactivate();

      spause = 5;
    }
  }
#endif

}


/* mouse stuffs */
/*
 * Handle if a mouse button is pressed
 */
void mousebuttondown( int x, int y, bool left )
{
  if ( (left == TRUE) && (drag == NULL) && (drag_mode_enabled == TRUE))
  {
    if ( (drag = is_point_in_sprite( x, y ) ) != NULL )
    {
         SetCapture(game->hWindow);

         X = Y = 0;

         /* remember old velocity */
         X = drag->velocity.x;
         Y = drag->velocity.y;
         
         /* stop this fellow from moving while being held */
         drag->velocity.x = 0;
         drag->velocity.y = 0;
         
         mousemove(x,y);
    }
  }
}

/*
 * Handle what happens when a mouse button is released
 */
void mousebuttonup(int x, int y, bool left)
{
     ReleaseCapture();
     
     if ( drag != NULL )
     {
       drag->velocity.x = X;
       drag->velocity.y = Y;
     }
     X = Y = 0;
     
     
     drag = NULL;
}

/*
 * Handle what happens when the mouse moves
 */
void mousemove(int x, int y)
{
    if ( drag != NULL )
     {
          POINT here;
          here.x = x - (drag->width/2);
          here.y = y - (drag->height/2);

          SetPosition( drag, here );
          
          game_paint( memDC );
    }
}



/**********************/
/* for historical reference only
void write_log( char *data )
{
  char buf[MSL];
  
  HANDLE hFile = CreateFile(LOG_FILE, FILE_APPEND_DATA, 0, NULL,
         OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  if ( hFile == INVALID_HANDLE_VALUE )
    return;

  if ( log_num == 0 )
  {
    log_num++;
    sprintf( buf, "\n\n-----------------\n%d.  %s\n", log_num, data );
  }
  else
  {
        log_num++;
        sprintf( buf, "%d.  %s\n", log_num, data );
  }
  
  
  {
    DWORD byteswritten;
    
    if ( !WriteFile(hFile, &buf, strlen(buf), &byteswritten, NULL) )
    {
        CloseHandle(hFile);
        return;
    }
  }
  
  CloseHandle(hFile);
}
*/

/* Window is activated again! */
void game_activate( void )
{
}

/* The user switched windows! */
void game_deactivate( void )
{
}

/************************/
/** VARIOUS FUNCTIIONS **/
/************************/
/* this was for the dodging saucers! */
void DodgeAI( SPRITE *sprite )
{
   if ( sprite == NULL )
    return;

   POINT pos = sprite->position;

   /* find closest sprite */
   int xcol = PRG_WIDTH, ycol = PRG_HEIGHT, xycol = PRG_WIDTH+PRG_HEIGHT;
   SPRITE *loop = NULL;

   for ( loop = lvl->first_sprite; loop != NULL; loop = loop->next )
   {
     if ( loop == sprite )
       continue;

     POINT lpos = loop->position;

     /* calculate minimum xy distance */
     int xdist = (pos.x + sprite->bitmap->width / 2) -
                 (lpos.x + loop->bitmap->width  /2);
     int ydist = (pos.y + sprite->bitmap->height / 2) -
                 (lpos.y + loop->bitmap->height /2);

     if ( abs(xdist) < abs(xcol) || abs(ydist) < abs(ycol) )
     {
          if ( abs(xdist) + abs(ydist) < xycol )
          {
               xycol = abs(xcol) + abs(ycol);
               xcol = xdist;
               ycol = ydist;
          }
     }
     
   }
   
   POINT velo = sprite->velocity;

   if ( abs(xcol) < 100 )
   {
        if ( xcol < 0 )
         velo.x = UMAX(velo.x - 1, -MAXSPEED );
        else
         velo.x = UMIN(velo.x + 1, MAXSPEED );
   }
   
   if ( abs(ycol) < 100 )
   {
        if ( ycol < 0 )
         velo.y = UMAX(velo.y - 1, -MAXSPEED );
        else
         velo.y = UMIN(velo.y + 1, MAXSPEED );
   }

   SetVelocity(sprite, velo.x, velo.y );
}

/*
 * Resizes the window and corrects everything that needs correcting
 */
void game_size( LONG x, LONG y, LEVEL *l )
{
    PRG_WIDTH = x;
    PRG_HEIGHT = y;

    /* Calculate the window size and position based upon the game size */
    int width = PRG_WIDTH + GetSystemMetrics(SM_CXFIXEDFRAME) * 2;
    int height = PRG_HEIGHT + GetSystemMetrics(SM_CYFIXEDFRAME) * 2 + GetSystemMetrics(SM_CYCAPTION);

    int xpos = (GetSystemMetrics(SM_CXSCREEN) - width) / 2;
    int ypos = (GetSystemMetrics(SM_CYSCREEN) - height) / 2;

    SetWindowPos( game->hWindow, HWND_TOPMOST, xpos, ypos, width, height, SWP_NOZORDER );

    game->width = PRG_WIDTH;
    game->height = PRG_HEIGHT;

    /* delete old */
    DeleteObject(memBitmap);
    DeleteDC(memDC);

    /* make new */
    memDC = CreateCompatibleDC(GetDC(game->hWindow));
    memBitmap = CreateCompatibleBitmap(GetDC(game->hWindow), game->width, game->height);
    SelectObject(memDC, memBitmap);

    /* fix the level's background */
    if ( l != NULL )
    {
      if ( l->bg != NULL )
      {
       l->bg->width = PRG_WIDTH;
       l->bg->height = PRG_HEIGHT;
      }
    }
}

/* restart game */
void NewGame( bool reset_score )
{
  gpause = FALSE;

  if ( reset_score == TRUE )
   player->score = 0;

  CleanSprites(); /* clear out all sprites */
  
  populate_level( lvl );

  start = GetTickCount();
  SetTimer( game->hWindow, T_ID, SECOND, NULL );
}

/*
 * Random int between low and high
 */
int random( int low, int high )
{
  int num = rand() % (high+1);

  if ( num < low )
    num = low;

  if ( num > high )
   num = high;

   return num;
}