/*****************************************************************************
 * Microchip Graphics Library Demo Application
 * This program shows how to use the Graphics Primitives Layer.
 *****************************************************************************
 * FileName:        MainDemo.c
 * Dependencies:    MainDemo.h
 * Processor:       PIC24, PIC32
 * Compiler:       	MPLAB C30, MPLAB C32
 * Linker:          MPLAB LINK30, MPLAB LINK32
 * Company:         Microchip Technology Incorporated
 *
 * Software License Agreement
 *
 * Copyright ?2008 Microchip Technology Inc.  All rights reserved.
 * Microchip licenses to you the right to use, modify, copy and distribute
 * Software only when embedded on a Microchip microcontroller or digital
 * signal controller, which is integrated into your product or third party
 * product (pursuant to the sublicense terms in the accompanying license
 * agreement).  
 *
 * You should refer to the license agreement accompanying this Software
 * for additional information regarding your rights and obligations.
 *
 * SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS?WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY
 * OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR
 * PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR
 * OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION,
 * BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT
 * DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL,
 * INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA,
 * COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY
 * CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
 * OR OTHER SIMILAR COSTS.
 *
 * Author               Date        Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Anton Alkhimenok		30/05/07	...
 *****************************************************************************/

/*
******************************************************************************
* Version 120309
* (1) for ssd1982.c, GetReg(), GetPixel() for 8-bit only verified. 
* No code for 16-bit accessing modified yet.
* (2) for MainDemo.c, add #define PIC32_STARTER_KIT to differentiate
* between PIC32MX Starter Kit and PIC24 Eval Board C2 with PIC32MX
* onboard when no crystal soldered.
* Programmer: John Leung
* Date: 12-03-2009
******************************************************************************
*/
/*
****************************** LUNAR LANDER GAME *****************************
* Description : Try to land on the platform
* Use : button 0 for Left
*       button 1 & 2 for Booster
*       button 3 for Right
* Programmer: Fabrice Muller
* Date: 13-03-2009
* HW info : PIC24 Eval Rev C , CPU : PIC32 PIM at 72Mhz
******************************************************************************
*/
/*
******************* LUNAR LANDER GAME , Bugs & improvment ********************
* Programmer: Fabrice Muller
* Date: 16-03-2009
* LEM Display clipping is now correct , it was for a non rotated display
* The srand() function is now used with a 32bits timer to get real random number
*/
#include "Lunar_Lander.h"
// comment the following line if your are using Internal Fast Osc for PIC24 Eval BoardC2
// #define PIC32_STARTER_KIT

// Configuration bits
#ifdef __PIC32MX
#pragma config FPLLODIV = DIV_1, FPLLMUL = MUL_18, FWDTEN = OFF, FCKSM = CSECME, FPBDIV = DIV_1, FPLLIDIV = DIV_2
#pragma config OSCIOFNC = ON, FSOSCEN = OFF, IESO = OFF
#pragma config CP = OFF, BWP = OFF, PWP = OFF

#ifdef PIC32_STARTER_KIT
// PIC32MX Starter Kit
#pragma config FNOSC = PRIPLL, POSCMOD = XT
#else
// PIC24 Eval board RevC2 with PIC32MX360F512L onboard, Internal Fast Osc for 8MHz*18= 72MHz
#pragma config FNOSC = FRCPLL, POSCMOD = OFF, ICESEL = ICS_PGx2
#endif

#else
_CONFIG2(FNOSC_PRIPLL & POSCMOD_XT) // Primary XT OSC with PLL
_CONFIG1(JTAGEN_OFF & FWDTEN_OFF)   // JTAG off, watchdog timer off
#endif

//Define TickRate for the 32 bits Timer (Timer45)
#define TICK_RATE 72000000

///////////////////////////////// FONTS ///////////////////////////////////////
extern const FONT_FLASH Font25;
extern const FONT_FLASH Font35;

/////////////////////////////// Functions ///////////////////////////////////////
void Lander(void);                    			//The game
void DrawLEM();                 	  			//Show the LEM
void TestPlateform();                 			//Test if the LEM have landed or crashed
void DrawScreen();                    			//Draw the terrain and platform at start of the game
void gameovertxt();					  			//If we crash
void winparty();								//You landed

/////////////////////////////// Variables ///////////////////////////////////////

// Global variables for the Lunar Lander game
short   LemX,OldLemX;                    //LEM X pos
short   LemY,OldLemY;                    //LEM Y pos
short   PlatformX;                       //Platform X pos
short   PlatformY;                       //Platform Y pos
short   Booster = 0;                     //1 = show the booster flame
float   LEMSpeed = 0.1;                  //LEM falldown speed
float   Vx = 0.0;                        //LEM horizontal speed
float   Fuel = 50.0;                	 //LEM fuel
float   ForceG = 1.63;                   //Gravity (1.63 for the Moon "9.8 / 6")
short   RightFoot,LeftFoot;              //Color under the left and right LEM foot
short   Cnt1 = 0;                   	 //counter
short   RecomputeSpeed = 0;              //1 = Recompute the speed
short   RedrawLEM = 0;                   //1 = Redraw the LEM
short   GoRight = 0,GoLeft = 0,GoUP = 0; //Directional button pressed
WORD    TerrainColor;					 //Color to use for draw the terrain
char    chiffre[5];                      //For write the score (if needed)
short Score = 0;                         // ...
short GMx,GMy;							 //Max X and Max Y from the Screen

// Predefined Colors (just for memo)
// BRIGHTBLUE,BRIGHTGREEN,BRIGHTCYAN,BRIGHTRED,BRIGHTMAGENTA,BRIGHTYELLOW,
// BLUE,GREEN,CYAN,RED,MAGENTA,BROWN,LIGHTGRAY,DARKGRAY,LIGHTBLUE,LIGHTGREEN,
// LIGHTCYAN,LIGHTRED,LIGHTMAGENTA,YELLOW,WHITE

int main(void){
	SHORT width, height;

	#ifdef __PIC32MX__
    	INTEnableSystemMultiVectoredInt();
    	SYSTEMConfigPerformance(GetSystemClock());
	#endif

	/////////////////////////////////////////////////////////////////////////////
  InitGraph();

	// Set buttons pins as inputs
	PORTSetPinsDigitalIn(IOPORT_D, BIT_8);
	PORTSetPinsDigitalIn(IOPORT_D, BIT_9);
	PORTSetPinsDigitalIn(IOPORT_A, BIT_14);
	PORTSetPinsDigitalIn(IOPORT_A, BIT_15);

	//********************************************
	// Demo section for Main Window, simple primitive function performed	
											
	SetColor(BLACK);
	ClearDevice();

	//~~~~~~~~~~~~~     Configurer a 32 bits Timer    ~~~~~~~~~~~~~
	OpenTimer45(T45_ON | T45_PS_1_64 | T45_32BIT_MODE_ON | T45_SOURCE_INT,TICK_RATE);
	// Ticks for 72Mhz
	// 1 sec = 1125000 ticks 
	// 1 mS  =    1125 ticks
	// 1 µS  =   1.125 ticks

    // Init the Timer
    WriteTimer45(0x0);

	GMx = GetMaxX();
	GMy = GetMaxY();

  	SetFont((void*)&Font25);
  	SetColor(BRIGHTGREEN);
  	width = GetTextWidth("SupraBotics",(void*)&Font25);
  	height = GetTextHeight((void*)&Font25);

  	OutTextXY( (GMx-width)>>1,
               (GMy-height)>>1,
                "SupraBotics");

  	DelayMs(2000);
	SetColor(BLACK);
	ClearDevice();

  	SetColor(BRIGHTBLUE);
  	width = GetTextWidth("Press a button to start",(void*)&Font25);
  	height = GetTextHeight((void*)&Font25);

  	OutTextXY( (GMx-width)>>1,
               (GMy-height)>>1,
                "Press a button to start");
	
	//Wait up a button is pressed
	while(PORTReadBits(IOPORT_A, BIT_15) && PORTReadBits(IOPORT_D, BIT_8) &&
      	  PORTReadBits(IOPORT_D, BIT_9)  && PORTReadBits(IOPORT_A, BIT_14))
      		{continue;}

	SetColor(BLACK);
	ClearDevice();

	//Value for the random generator
	srand(ReadTimer45());

	// Color to use for the Terrain
	TerrainColor = BROWN;

    while(1)
	{
		DelayMs(1000);
		//Launch the Game
		Lander();
    } 
}

void Lander(void)
 {
   short   CntTemp = 0;						//Time Counter
   short   width, height;

   //Plateform position
   PlatformX = (rand() % (GMx - 40)) + 20 ;
   PlatformY = (rand() % 80)  + (GMy - 80);

   //Draw the Screen
   DrawScreen();
   
   //LEM position at Start
   LemX = (rand() % (GMx - 40)) + 20;
   LemY = (rand() % 180) + 25;
   OldLemX = LemX;
   OldLemY = LemY;

   // Init the Timer
   WriteTimer45(0x0);
   
   while(1)
    {
/*
//	Timer Debug routine
      if (ReadTimer45() > 11250)    //10mS
         {
            WriteTimer45(0x0);
			Cnt1++;					//Increment Counter
            if (Cnt1 == 100)        //1 Sec
               {
                  Cnt1 = 0;         //drop Counter to 0
				  CntTemp++;		//Increment Time Counter
				  SetColor(BLACK);
				  ClearDevice();
				  sprintf(chiffre,"%u",CntTemp);
				  SetFont((void*)&Font25);
				  SetColor(BRIGHTGREEN);
				  width = GetTextWidth(chiffre,(void*)&Font25);
				  height = GetTextHeight((void*)&Font25);
				  // Write seconds
				  OutTextXY( (GMx-width)>>1,
				             (GMy-height)>>1,
				              chiffre);
               }
         }
	}
*/

      if (ReadTimer45() > 11250)    //10mS
         {
            WriteTimer45(0x0);
            if ((++Cnt1 % 10) == 0) //100mS
               {
                  RecomputeSpeed = 1;
                  RedrawLEM = 1;
               }
               
            if (Cnt1 == 100)        //1 Sec
               {
                  Cnt1 = 0;         //Remettre le Compteur a 0
               }
         }

      //Test des bouttons
	  if (!PORTReadBits(IOPORT_A, BIT_15) | !PORTReadBits(IOPORT_D, BIT_8)) GoUP = 1;//Active the Booster
      if (!PORTReadBits(IOPORT_D, BIT_9)) GoRight = 1;  					//The LEM go to Right
      if (!PORTReadBits(IOPORT_A, BIT_14)) GoLeft = 1;   					//The LEM go to Left
      
      // Cette routine est execut?toutes les 100mS
      if (RecomputeSpeed == 1)
       {
         LEMSpeed += (ForceG * 0.1) ;     //(ForceG / 10) ,Apply Force every 10tht seconds
         //Slow down if Booster is Active
         if((GoUP == 1) && (Fuel > 0))
          {
           LEMSpeed -= (ForceG * 0.15);  //Slow down if Booster is Active
           Fuel -= 0.3;
           GoUP = 0;
           Booster = 1;
          }
         if((GoRight == 1) && (Fuel > 0))
          {
            Vx += 0.1;                  //LEMSpeed horizontal Right direction
            Fuel -= 0.1;
            GoRight =0;
          }
         if((GoLeft == 1) && (Fuel > 0))
          {
            Vx -= 0.1;                  //LEMSpeed horizontal Left direction
            Fuel -= 0.1;
            GoLeft =0;
          }
          // Record the LEM position
          OldLemX = LemX ; OldLemY = LemY;
          LemY += LEMSpeed;
          //Clip the LEM in screen
          if (LemY > (GMy -20)) LemY = GMy -20;
          if (LemY < 50)  LemY = 50;
          LemX += Vx;
          if (LemX > (GMx - 25)) LemX = GMx - 25;
          if (LemX < 5) LemX = 5;
          
          RecomputeSpeed = 0;
       }
      // This routine execute every 100mS
      if(RedrawLEM == 1)
      {

         snprintf(chiffre,4,"%f2.1",LEMSpeed);
	     SetColor(BLACK);
         Bar(0,6,100,32);
		 SetColor(YELLOW);
		 OutTextXY(1,6,"Speed : ");
         if (LEMSpeed > 2.0)
			{
		    SetColor(BRIGHTRED);
			OutTextXY(65,6,chiffre);
			}
         else
			{
		    SetColor(LIGHTGREEN);
			OutTextXY(65,6,chiffre);
			}
            
         snprintf(chiffre,5,"%f2.1",Fuel);
	     SetColor(BLACK);
         Bar(100,6,200,32);
		 SetColor(YELLOW);
		 OutTextXY(100,6,"Fuel : ");
         if (Fuel > 20.0)
			{
		    SetColor(LIGHTGREEN);
			OutTextXY(160,6,chiffre);
			}
         else
			{
		    SetColor(BRIGHTRED);
			OutTextXY(160,6,chiffre);
			}
            
         //Draw the LEM
         DrawLEM();
         // Test if we have Landed
         RightFoot = GetPixel(LemX , LemY + 31);
         LeftFoot = GetPixel(LemX + 20, LemY + 31);
         RedrawLEM = 0;
      }
      
      // Test if we are over the plateforme
      if (LemY > (PlatformY - 33))
         {
         if ((LemX >= PlatformX ) && (LemX <= (PlatformX + 20)))
            TestPlateform();
         }
         
      if (GetPixel(LemX , LemY + 31) == BROWN)    //Left LEM foot in terrain
         {
			gameovertxt();
			while(1){continue;}
		 }
      if (GetPixel(LemX + 20, LemY + 31) == BROWN)//Right LEM foot in terrain
         {
			gameovertxt();
			while(1){continue;}
		 }
    }

 }

// Afficher le Vaisseau
void DrawLEM()
 { 
   //Erase the LEM from old position
   SetColor(BLACK);
   Line(OldLemX + 10 , OldLemY , OldLemX + 20 , OldLemY + 20);
   Line(OldLemX + 20 , OldLemY + 20 , OldLemX + 20 , OldLemY + 30);
   Line(OldLemX + 20 , OldLemY + 30 , OldLemX + 17 , OldLemY + 20);
   Line(OldLemX + 17 , OldLemY + 20 , OldLemX + 3 , OldLemY + 20);
   Line(OldLemX + 3 , OldLemY + 20, OldLemX , OldLemY + 30);
   Line(OldLemX , OldLemY + 30 , OldLemX , OldLemY + 20);
   Line(OldLemX , OldLemY + 20 , OldLemX + 10 , OldLemY);
   //Erase the Booster
   Line(OldLemX + 6 , OldLemY + 21 , OldLemX + 13 , OldLemY + 21);
   Line(OldLemX + 13 , OldLemY + 21 , OldLemX + 10 , OldLemY + 30);
   Line(OldLemX + 10 , OldLemY + 30 , OldLemX + 6 , OldLemY + 21);
 
   //Draw the LEM to new position
   SetColor(WHITE);
   Line(LemX + 10 , LemY , LemX + 20 , LemY + 20);
   Line(LemX + 20 , LemY + 20 , LemX + 20 , LemY + 30);
   Line(LemX + 20 , LemY + 30 , LemX + 17 , LemY + 20);
   Line(LemX + 17 , LemY + 20 , LemX + 3 , LemY + 20);
   Line(LemX + 3 , LemY + 20, LemX , LemY + 30);
   Line(LemX , LemY + 30 , LemX , LemY + 20);
   Line(LemX , LemY + 20 , LemX + 10 , LemY);
   //Draw the Booster if needed
   if (Booster == 1)
   {
   	  SetColor(BRIGHTRED);
      Line(LemX + 6 , LemY + 21 , LemX + 13 , LemY + 21);
      Line(LemX + 13 , LemY + 21 , LemX + 10 , LemY + 30);
      Line(LemX + 10 , LemY + 30 , LemX + 6 , LemY + 21);
      Booster = 0;
   }
 }

// Tester si le Vaisseau se pose ou s'ecrase
void TestPlateform()
 {
   short abc;
   if (LEMSpeed <= 2.0)
		winparty();
   else
      	gameovertxt();
 }

// Affichage de l'ecran en debut de jeux
void DrawScreen()
 {
   unsigned short Cnt;		                               //Loop counter
   unsigned short py;                                      //For the terrain
   
   //Dessin de la plateforme
   SetColor(YELLOW);
   Bar(PlatformX,PlatformY,PlatformX+40,PlatformY+5);
   //Terrain at Left from the Platform
   py = PlatformY + (rand() % 7) - 3;
   SetColor(TerrainColor);
   for (Cnt = PlatformX-1;Cnt > 0;Cnt --)
      {  
         py = py + ((rand()%7)-3);
//         Line(Cnt , py ,Cnt , GMy);
         Line(Cnt , GMy ,Cnt , py);
      }
   //Terrain at Right from the Platform
   py = PlatformY + (rand() % 7) - 3;
   for (Cnt = PlatformX + 41;Cnt < GMx;Cnt ++)
      {
         py = py + (rand() % 7) - 3;
         Line(Cnt , GMy ,Cnt , py);
      }
   //Terrain under the Platform
   for (Cnt = PlatformX;Cnt < PlatformX + 41;Cnt ++)
      {
         Line(Cnt ,GMy  ,Cnt , PlatformY+6);
      }
 }

void gameovertxt()
{
	short width, height;

    SetFont((void*)&Font25);
    SetColor(BRIGHTRED);
    width = GetTextWidth("GAME OVER",(void*)&Font25);
    height = GetTextHeight((void*)&Font25);

    OutTextXY( (GMx-width)>>1,
               (GMy-height)>>1,
                "GAME OVER");

    while(1){continue;}
}

void winparty()
{
	short width, height;

    SetFont((void*)&Font25);
    SetColor(BRIGHTGREEN);
    width = GetTextWidth("YOU WIN",(void*)&Font25);
    height = GetTextHeight((void*)&Font25);

    OutTextXY( (GMx-width)>>1,
               (GMy-height)>>1,
                "YOU WIN");

    while(1){continue;}
}
