/*

This write-up contains code that implements the game Pong in C using the cross-platform Allegro library. (I wrote the game in all of an hour on a dare to see who could get Pong done first, me using C and Allegro or Josh using Visual Basic and WinAPI.) Player 1's controls are W and S; player 2's are the arrow keys. (It's not an entirely authentic experience; there is no support for PC game port paddles, and the screen is colored.) To build it:

  1. If you do not have a supported GCC compiler (MinGW or GNU/Linux GCC), get DJGPP (a DOS GCC) from http://www.delorie.com/djgpp/ and install it according to README.1ST.
  2. Get the Allegro library (version 3.9.33 or later is best) from http://www.talula.demon.co.uk/allegro/ and install it, following the instructions in the appropriate readme file. (It's not a wasted effort; there are scores of Allegro games at http://www.allegro.cc)
  3. Paste this source code into a file called pong.c
  4. DJGPP or MinGW: gcc -Wall -O2 pong.c -lalleg -o pong.exe
    Linux: gcc -Wall -O2 pong.c `allegro-config --libs` -o pong
*/

/**************************************\
* pong.c                               *
* a simple air hockey game             *
*                                      ********************************\
* Copyright 2000 Damian Yerrick                                        *
*                                                                      *
* 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.                                  *
*                                                                      *
* This program is distributed in the hope that it will be useful,      *
* but WITHOUT ANY WARRANTY; without even the implied warranty of       *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
* GNU General Public License for more details.                         *
*                                                                      *
* You should have received a copy of the GNU General Public License    *
* along with this program; if not, write to the Free Software          *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
* Or view the License online at http://www.gnu.org/copyleft/gpl.html   *
*                                                                      *
* Damian Yerrick's World Wide Web pages are located at                 *
*   http://www.pineight.com/                                           *
*                                                                      *
\**********************************************************************/

#include <allegro.h>

#define PDL_HEIGHT 40

/* set up initial positions for the players ********
 * y[i] is how far from the top is paddle
 * x[i] is how far from the left to draw paddle
 * dy[i] is how fast the paddle is moving
 * upkey[i] is the key that moves the paddle up
 * downkey[i] is the key that moves the paddle down
 */
int y[2] = {80, 80};
const int x[2] = {0, 310};
int dy[2] = {0, 0};
const int upkey[2] = {KEY_W, KEY_UP};
const int downkey[2] = {KEY_S, KEY_DOWN};
int score[2] = {0, 0};

/* DrawPlayer() ************************
 * Draw player p's paddle in color c.
 */
void DrawPlayer(int p, int c)
{
  rectfill(screen, x[p], y[p] + 3, x[p] + 9, y[p] + PDL_HEIGHT - 4, c);
}

void DrawBall(int x, int y, int c)
{
  ellipsefill(screen, x, y, 6, 5, c);
}

int main()
{
  int lastWinner = 1;
  int lastClock = 0;

  allegro_init();
  install_timer();
  install_keyboard();

  if(set_gfx_mode(GFX_AUTODETECT, 320, 200, 0, 0) < 0)
  {
    allegro_message("could not shift to gfx mode\n");
    exit(1);
  }

  while(score[0] < 7 && score[1] < 7)
  {
    int balldone, ballx = 0, bally = 0, balldx, balldy;

    /* setup ball */
    ballx = lastWinner ? 40 : 280;
    bally = 100;
    balldx = lastWinner ? 3 : -3;
    balldy = rand() % 8 - 4;
    if(balldy >= 0)
      balldy += 4;
    balldone = 0;
    while(!balldone)
    {
      int oldx, oldy, i;


      while(lastClock == retrace_count)
        yield_timeslice();
      lastClock = retrace_count;

      /* players */

      for(i = 0; i < 2; i++)
      {
        dy[i] = dy[i] * 15/16;

        if(key[upkey[i]])
          dy[i] -= 4;

        if(key[downkey[i]])
          dy[i] += 4;

        DrawPlayer(i, 0);
        y[i] += dy[i] / 4;

        if(y[i] < 0)
        {
          y[i] = 0;
          dy[i] = -dy[i] / 2;
        }
        if(y[i] > 200 - PDL_HEIGHT)
        {
          y[i] = 200 - PDL_HEIGHT;
          dy[i] = -dy[i] / 2;
        }
        DrawPlayer(i, i ? 1 : 4);
      }

      /* the ball */

      oldx = ballx;
      oldy = bally;

      bally += balldy;
      if(bally < 5) /* bounce off top */
      {
        bally = 10 - bally;
        balldy = -balldy;
      }
      else if(bally > 195) /* bounce off bottom */
      {
        bally = 390 - bally;
        balldy = -balldy;
      }

      ballx += balldx;

      if(balldx > 0)
      {
        if(ballx > 305 && bally >= y[1] &&
           bally < y[1] + PDL_HEIGHT)
        {
          balldx = -balldx;
          balldy = (bally - y[1] - PDL_HEIGHT / 2) / 4;
          if(balldy >= 0)
            balldy++;
        }
        else if(ballx >= 316)
        {
          score[0]++;
          rest(1000);
          lastWinner = 0;
          balldone = 1;
        }
      }
      else
      {
        if(ballx < 15 && bally >= y[0] &&
           bally < y[0] + PDL_HEIGHT)
        {
          balldx = -balldx;
          balldy = (bally - y[0] - PDL_HEIGHT / 2) / 4;
          if(balldy >= 0)
            balldy++;
        }
        else if(ballx < 5)
        {
          score[1]++;
          rest(1000);
          lastWinner = 1;
          balldone = 1;
        }
      }
      DrawBall(oldx, oldy, 0);
      if(!balldone)
        DrawBall(ballx, bally, 10);

      textprintf(screen, font, 140, 0, 15, "%d - %d",
                 score[0], score[1]);

      while(keypressed())
      {
        switch(readkey() >> 8)
        {
          case KEY_ESC:
            score[1] = score[2] = 7;
            balldone = 1;
            break;
          default:
            break;
        }
      }

    }
    
  }
  return 0;
} END_OF_MAIN();