/********************************/
/*** omsk Pong - omsk@usa.net ***/
/*** Version 0.01  04/06/1999 ***/
/********************************/

/***      THE BUTTONS ARE:        ***/
/*** CONT_A CONT_B U_JPAD D_JPAD  ***/
/***   L_JPAD R_JPAD CONT_START   ***/
/*** D_CBUTTONS L_CBUTTONS Z_TRIG ***/
/***    U_CBUTTONS R_CBUTTONS     ***/


#include <ultra64.h>	// Include standard libs from the dev kit
#include "main.h"	// Various things defined here
#include "static.h"	// Static display lists
#include "stdio.h"	// For printf
#include "cont.h"	// Controllers
#include "display.h"

extern void	InitImage(void);
extern void	DrawImage(void);
extern void	DrawIt(void);
extern void     InitDraw(void);
extern void     CleanScreenDL(void);
extern void     InitDisplay(void);
extern void     InitDL(void);
extern void     ExecDL(void);
extern void     EndDisplay(void);
extern void     InitTextDisplay(void);

extern FB              fb;
extern OSContStatus    statusdata[MAXCONTROLLERS];
extern OSContPad       controllerdata[MAXCONTROLLERS];
extern int             draw_buffer;
extern Gfx             *glistp;
OSPfs                  pfs[MAXCONTROLLERS];
extern char            *staticSegment;

uSprite MySprite[10];
extern u16 ball[];
extern u16 border01[];
extern u16 paddle1[];
extern u16 paddle2[];
extern u16 scorebck[];
extern u16 pic1[];
extern u16 title[];
extern u16 onewins[];
extern u16 twowins[];
extern u16 drawgame[];


float x1;            // x1 is balls horizontal position
float y1;            // y1 is balls vertical position
float xmove;         // horizontal speed additive for x1
float ymove;         // vertical speed additive for y1
float speed;         // ball speed
float pl1y,pl2y;     // paddle one y pos ; paddle two y pos
float pl1x,pl2x;     // paddle one x pos ; paddle two x pos
int i;               // multi use variable
int i2;              // extra counter
int score1;          // score of player 1
int score2;          // score of player 2
int computer;        // if comp is playing it = 1
int counter;	     // Time counter
int level;           // level number -> more level is high more comp moves quickly
int maxlevel=6;      // Total number of levels to win
int flipx=0,flipy=0;
int button[4];
int pushup2=0,pushdown2=0,pushleft,pushright,pusha,pushb,pushz,ucpush,dcpush,rcpush,lcpush;
int pushup,pushdown,pushstart;
int PADHT=32*4,PADWD=4*4;
int BALLWD=6*4,BALLHT=6*4;
int limitup=8*4,limitdown=199*4,limitright=311*4,limitleft=9*4;

void CheckController()
{
ReadController();  
button[0]=controllerdata[0].button;
button[1]=controllerdata[1].button;
button[2]=controllerdata[2].button;
button[3]=controllerdata[3].button;
}


void chekmove()
 {
int pspeed=10;

  CheckController();  
  if (button[0] & U_JPAD)                   // if up1 (paddle one up)
    {
     pl1y=pl1y-pspeed;                      // move paddle one y pos up
    }
   if (button[0] & D_JPAD)                  // if S (paddle one down)
    {
     pl1y=pl1y+pspeed;                      // move paddle one y pos down
    }
   if (button[1] & U_JPAD)                  // if P (paddle 2 up)
    {
      pl2y=pl2y-pspeed;
    }
   if (button[1] & D_JPAD)
    {
      pl2y=pl2y+pspeed;
    }
  }

void comp_move()
 {
int comspeed=2+level;
float x2,y2,xmove2,ymove2;
x2=x1;y2=y1;
xmove2=xmove;ymove2=ymove;

while (x2<(limitright-PADWD-BALLWD)) // we are going to calculate the futur ball position
	{				     // so we can move the paddle for the computer
	x2=x2+xmove2;
	if (y2>limitdown-BALLHT) ymove2=-speed;      // if ball hits bottom set ball going up
	if (y2<limitup) ymove2=+speed;            // if ball hits top set ball going down
	y2=y2+ymove2;
	}

if (y2>pl2y+(PADHT/2)+4) pl2y=pl2y+comspeed; // if distance between ball and pad > x then move down
else if (y2<pl2y+(PADHT/2)-4) pl2y=pl2y-comspeed;  // if distance between ball and pad < x then move up

 }


/*** The work horse of this demo ***/

DemoLoop(void)
{

reset:

counter=0;		// Time counter
osViBlack(0);           // Turn display on
initControllers();      // Initialize Controller Pad

InitTextDisplay();      // Initialise text display related variables (start position...)
InitDisplay();
ClearScreenDL();
InitDL();

guSprite2DInit(&MySprite[6], title, 0,   // Title screen
               320, 320, 240,
               G_IM_FMT_RGBA,
               G_IM_SIZ_16b,
	       1024,1024,
	       flipx, flipy,
	       0, 0,
	       0,0);
gSPSprite2D(glistp++, OS_K0_TO_PHYSICAL(&MySprite[6]));
ExecDL();
EndDisplay();

while (1)
 {
  CheckController();  // Is someone pushing a button on the controller ??

  if (button[0] & CONT_START)
	{
	computer=1;
	break;
	}
  else if (button[1] & CONT_START)
	{
	computer=0;
	break;
	}
 }

score1=0;score2=0;     // set scores to 0
level=1;

start:

if (level>maxlevel)
{
	if (score1>score2)
	{
		InitDisplay();
		ClearScreenDL();
		InitDL();

		guSprite2DInit(&MySprite[7], onewins, 0,   // Title screen
		               320, 320, 240,
		               G_IM_FMT_RGBA,
		               G_IM_SIZ_16b,
			       1024,1024,
			       flipx, flipy,
			       0, 0,
			       0,0);
		gSPSprite2D(glistp++, OS_K0_TO_PHYSICAL(&MySprite[7]));
		ExecDL();
		EndDisplay();
		while (1)
			{
			CheckController();
			if (button[0] & CONT_A) goto reset;
			}
	}
	else
	{
		if (score2>score1)
		{
		InitDisplay();
		ClearScreenDL();
		InitDL();

		guSprite2DInit(&MySprite[8], twowins, 0,   // Title screen
		               320, 320, 240,
		               G_IM_FMT_RGBA,
		               G_IM_SIZ_16b,
			       1024,1024,
			       flipx, flipy,
			       0, 0,
			       0,0);
		gSPSprite2D(glistp++, OS_K0_TO_PHYSICAL(&MySprite[8]));
		ExecDL();
		EndDisplay();
		while (1)
			{
			CheckController();
			if (button[0] & CONT_A) goto reset;
			}
		}
		else  // Draw game
		{
		InitDisplay();
		ClearScreenDL();
		InitDL();

		guSprite2DInit(&MySprite[9], drawgame, 0,   // Title screen
		               320, 320, 240,
		               G_IM_FMT_RGBA,
		               G_IM_SIZ_16b,
			       1024,1024,
			       flipx, flipy,
			       0, 0,
			       0,0);
		gSPSprite2D(glistp++, OS_K0_TO_PHYSICAL(&MySprite[9]));
		ExecDL();
		EndDisplay();
			while (1)
				{
				CheckController();
				if (button[0] & CONT_A) goto reset;
				}
		}
	}
}

i  = RAND(2);     // generate random entry point for ball - x axis
i2 = RAND(1000);

if (i == 1)
x1=limitleft+10+i2;
else
x1=limitright-10-i2;

i  = RAND(2);     // generate random entry point for ball - y axis
i2 = RAND(600);

if ( i == 1)
y1=limitup+10+i2;
else
y1=limitdown-10-i2;

speed=9+level;      // initial ball speed

if (x1>(SCREEN_WD*4)/2)   // if entry point is on the right
 xmove=-speed;            // speed will send ball to the left
else
 xmove=speed;

if (y1>(limitdown+limitup)/2)    // if entry point is down
 ymove=-speed;                   // speed will send ball up
else
 ymove=speed;

pl1y=((limitdown/2)+limitup-(PADHT/2));    // set paddles to the middle of the y plane
pl2y=pl1y;
pl1x=limitleft+10;pl2x=limitright-PADWD-10;

while(1)        // main loop
 {
  counter++;

  CheckController();

  if ((x1>(pl2x-BALLWD-1) && x1<(pl2x+PADWD-BALLWD))
      && (y1>(pl2y-BALLWD) && y1<(pl2y+PADHT))) // if paddle 2 was hit
   {
   speed=speed+0.1;       // increase ball speed
   xmove=-speed;          // set ball going left
   }
  if ((x1<(pl1x+PADWD+1) && x1>pl1x)
      && (y1>(pl1y-BALLWD) && y1<(pl1y+PADHT)))     // if paddle one was hit
   {
   speed=speed+0.1;                       // increase speed
   xmove=speed;                           // set ball going right
   }
  if (y1>limitdown-BALLWD-1)              // if ball hits bottom
   {
   ymove=-speed;                          // set ball going up
   }
  if (y1<limitup+1)                       // if ball hits top
   {
   ymove=+speed;                          // set ball going down
   }

  chekmove();

  if (computer==1 && xmove > 0)
   {
   comp_move();
   }
  if (pl1y<limitup) pl1y=limitup;
  if (pl1y>limitdown-PADHT) pl1y=limitdown-PADHT;  // keep paddles inside boundaries
  if (pl2y<limitup) pl2y=limitup;
  if (pl2y>limitdown-PADHT) pl2y=limitdown-PADHT;

InitTextDisplay();
InitDisplay();
ClearScreenDL();
InitDL();

gDPSetRenderMode(glistp++, G_RM_XLU_SURF, G_RM_XLU_SURF2); // for transparency

guSprite2DInit(&MySprite[4], pic1, 0,   // Picture in the background
               320, 320, 208,
               G_IM_FMT_RGBA,
               G_IM_SIZ_16b,
	       1024,1024,
	       flipx, flipy,
	       0, 0,
	       0,0);
gSPSprite2D(glistp++, OS_K0_TO_PHYSICAL(&MySprite[4]));

guSprite2DInit(&MySprite[5], scorebck, 0,   // Background on the score field
               320, 320, 32,
               G_IM_FMT_RGBA,
               G_IM_SIZ_16b,
	       1024,1024,
	       flipx, flipy,
	       0, 0,
	       0,208*4);
gSPSprite2D(glistp++, OS_K0_TO_PHYSICAL(&MySprite[5]));

guSprite2DInit(&MySprite[2], ball, 0,   // Draw the ball
               6, 6, 6,
               G_IM_FMT_RGBA,
               G_IM_SIZ_16b,
	       1024,1024,
	       flipx, flipy,
	       0, 0,
	       x1,y1);
gSPSprite2D(glistp++, OS_K0_TO_PHYSICAL(&MySprite[2]));

guSprite2DInit(&MySprite[1], paddle2, 0,   // Draw Paddle 2
               4, 4, 32,
               G_IM_FMT_RGBA,
               G_IM_SIZ_16b,
               1024,1024,
               flipx, flipy,
               0, 0,
               pl2x,pl2y); //offy
gSPSprite2D(glistp++, OS_K0_TO_PHYSICAL(&MySprite[1]));

guSprite2DInit(&MySprite[0], paddle1, 0,   // Draw Paddle 1
               4, 4, 32,
               G_IM_FMT_RGBA,
               G_IM_SIZ_16b,
               1024,1024,
               flipx, flipy,
               0, 0,
               pl1x,pl1y); //offy
gSPSprite2D(glistp++, OS_K0_TO_PHYSICAL(&MySprite[0]));

guSprite2DInit(&MySprite[3], border01, 0,   // Draw the background
               320, 320, 240,
               G_IM_FMT_RGBA,
               G_IM_SIZ_16b,
	       1024,1024,
	       flipx, flipy,
	       0, 0,
	       0,0);
gSPSprite2D(glistp++, OS_K0_TO_PHYSICAL(&MySprite[3]));



ExecDL();
fb.x=1;
fb.y=13;
printf(&fb,draw_buffer," Player 1 = %d            Player 2 = %d\n",score1,score2);
printf(&fb,draw_buffer,"Ball Speed = %d          Level = %d\n",(int) speed*100,level);
EndDisplay();

  if (x1<limitleft)
   {                                        // if ball goes past player 1
   score2++;                                // increase player 2 score
   level++;
   goto start;                              // then reset and start again
   }
  if (x1>limitright)
   {                                        // if player 1 scores
   score1++;                                // increase player 1 score
   level++;				    // Go next level
   goto start;                              // then reset and start over
   }
  x1=x1+xmove;                             // add to balls x pos
  y1=y1+ymove;                             // add to balls y pos

  if ((button[0] & (L_TRIG + R_TRIG))) goto reset;

 }
}


/*
 * The main thread, copies static segment to RAM and fires up
 * DemoLoop
 *
 */
void mainproc(void *arg)
{

  /* DMA static segment to ram */
  osPiStartDma(&dmaIOMessageBuf, OS_MESG_PRI_NORMAL, OS_READ,
               (u32)_staticSegmentRomStart, staticSegment,
	       (u32)_staticSegmentRomEnd - (u32)_staticSegmentRomStart,
	       &dmaMessageQ);

  /* Wait for DMA complete */
  (void)osRecvMesg(&dmaMessageQ, NULL, OS_MESG_BLOCK);

  /* Start rocking */
  DemoLoop();

}
