//---------------------------------------------------------------------------
// FILE  : Ass1Main.cpp
// AUTOR : Aymeric
// DATE  : 05/02/2004
//---------------------------------------------------------------------------

#include <vcl.h>
#include <mmsystem.h>
#include <stdlib.h>
#include <time.h>
#pragma hdrstop

#include "Ass1Main.h"

// define the path for the sound files
#define SOUND_PATH "Sounds\\"
#define RIGHT_DIR "Sounds\\Right\\"
#define WRONG_DIR "Sounds\\Wrong\\"

// define the path for the graphic files
#define IMAGE_PATH "Graphics\\"

//de fine the numbre of error before automatic help
#define NB_ERROR_MAX 2

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner): TForm(Owner)
{
	Intro = new Graphics::TBitmap;

	// we load the introduction screen
	Intro->LoadFromFile(String(IMAGE_PATH)+"Intro.bmp");

	Random=new TRandom;
	Auto = new TAutoCursor(this);

	PlayBG=false;
	PlanetsBG=false;
	NewGame=false;
	nbError=0;

	// initialize the random function
	srand((unsigned) time(&t));

}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
	// NewGame is true when a new game has beginning
	if (NewGame)
	{
		try
		{
			// we load the main screen with its hotspots
			PlayHSList=new THotSpotList(this,String(IMAGE_PATH)+"play.bmp",2,String(IMAGE_PATH)+"play.hsp",String(IMAGE_PATH));
			// we load the game screen with its hostspots
			PlanetsHSList=new THotSpotList(this,String(IMAGE_PATH)+"Space.bmp",4,String(IMAGE_PATH)+"Space.hsp",String(IMAGE_PATH));
			OrbitsHSList=new THotSpotList(this,String(IMAGE_PATH)+"Space.bmp",0,String(IMAGE_PATH)+"Orbits.hsp",String(IMAGE_PATH));
		}
		catch (EInOutError &e)
		{
			Application->MessageBox((String("Failed to open \"") + e.Message + "\".  Application will terminate").c_str(),"Fatal Exception",0);
			Application->Terminate();
			return;
		}

		// Keep a record of the last visited hot spot. -1 = none
		mPrevPlanetsHS=-1;
		mPrevPlayHS=-1;

		mDragPHSNum=-1;

		TotalGood=0;
		nbError=0;

		Tx = new TTransition(this, PlayHSList->GetBackground());
                Txx = new TTransitionX(this, PlayHSList->GetBackground());

		int BackgroundState=Transparent;
		int Res=10;
		int Speed=10;

		// Type is initialized with a random number
		int Type=MyRand(6);
		if (Type == 4) Tx->ZoomOut(true);
                else if (Type == 5) Txx->Cutout(40);
		else Tx->Wipe(Type, Res, Speed, BackgroundState);
	}

	// when we launch the Ass1.exe
	if ((!PlayBG) && (!PlanetsBG))
	{

		int BackgroundState=FormColour;
		int Res=10;
		int Speed=10;
		int Type=MyRand(5);

		// random transition for the introduction screen
		Tx2 = new TTransition(this, Intro);

		if (Type == 4) Tx2->ZoomOut(true);
		else Tx2->Wipe(Type, Res, Speed, BackgroundState);

		PlayBG=true;
		Sleep(2000);
	}

	// we print the main screen
	if ((PlayBG) && (PlayHSList))
	{
		if (!NewGame) Canvas->Draw(0,0,PlayHSList->GetBackground());
		else NewGame=false;
	}

	// we print the game screen
	if ((PlanetsBG) && (PlanetsHSList))
	{
		Canvas->Draw(0,0,PlanetsHSList->GetBackground());

                // we draw again the hotspots
                for (int i=0, max=PlanetsHSList->NumHotSpots(); i < max; i++)
                {
					// if a planet has been moved in the right place
					if (!PlanetsHSList->HotSpot[i]->Enabled())
					{
						mBlitPos=PlanetsHSList->HotSpot[i]->GetBlitPos();
						// the planet becomes grey
						Graphics::TBitmap *Blit=PlanetsHSList->HotSpot[i]->GetBlitFrame(2);
						Blit->Transparent=true;
						Canvas->Draw(mBlitPos.x,mBlitPos.y,Blit);
						// we draw the planet in its last position
						Blit=PlanetsHSList->HotSpot[i]->GetBlitFrame(3);
						Canvas->Draw(mBlitPosDrag[i].x,mBlitPosDrag[i].y,Blit);
				   }
                }
	}

}
//---------------------------------------------------------------------------
// Random function
// max is the max value for the number
// Out : a number between 0 and max
int TForm1::MyRand(int max)
{
	return (rand()%max);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
	delete PlanetsHSList;
	delete PlayHSList;
	delete OrbitsHSList;
	delete Drag;
	delete Tx;
	delete Tx2;
	delete [] mBlitPosDrag;
	delete Random;
	delete Auto;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	PlanetsHSList=NULL;  // Don't allow paint until constructed
	OrbitsHSList=NULL;  // Don't allow paint until constructed
	PlayHSList=NULL;  // Don't allow paint until constructed
	mPrevPlanetsHS=-1;   // Keep a record of the last visited hot spot. -1 = none
	mPrevPlayHS=-1;   // Keep a record of the last visited hot spot. -1 = none
	mDragPHSNum=-1;
	TotalGood=0;      // number of planets on the right orbit
	nbError=0;		// number of error

	// mBlitPosDrag contains the position of the planets on the orbit
	mBlitPosDrag = new TPoint[9];


	try
	{
		PlayHSList=new THotSpotList(this,String(IMAGE_PATH)+"play.bmp",2,String(IMAGE_PATH)+"play.hsp",String(IMAGE_PATH));
		PlanetsHSList=new THotSpotList(this,String(IMAGE_PATH)+"Space.bmp",4,String(IMAGE_PATH)+"Space.hsp",String(IMAGE_PATH));
		OrbitsHSList=new THotSpotList(this,String(IMAGE_PATH)+"Space.bmp",0,String(IMAGE_PATH)+"Orbits.hsp",String(IMAGE_PATH));
	}
	catch (EInOutError &e)
	{
		Application->MessageBox((String("Failed to open \"") + e.Message + "\".  Application will terminate").c_str(),"Fatal Exception",0);
		Application->Terminate();
		return;
	}

	Drag = new TDragAndDrop(this, PlanetsHSList->GetBackground());
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
{
	// PlayBG is true when it's the main screen
	if (PlayBG)
	{

		int HotSpotIndex=PlayHSList->GetHotSpot(X,Y);
		if (HotSpotIndex < 0 ) return; // Not hot

		else {
			// if we select Normal Mode
			if (PlayHSList->HotSpot[HotSpotIndex]->GetText() == "Normal")
			{
				PlanetsBG=true;
				PlayBG=false;
				Normal=true;
				if (PlanetsHSList) Canvas->Draw(0,0,PlanetsHSList->GetBackground());
			}
			// else if we select Help Mode
			else if (PlayHSList->HotSpot[HotSpotIndex]->GetText() == "Help")
			{
				PlanetsBG=true;
				PlayBG=false;
				Normal=false;
				if (PlanetsHSList)
				{
					Canvas->Draw(0,0,PlanetsHSList->GetBackground());
					// the first planet is chose with the random function
					idPlanet=MyRand(9);
					Application->MessageBox((String("You must place ") + PlanetsHSList->HotSpot[idPlanet]->GetText() + String(" in first")).c_str(), "Expert mode", MB_OK);
				}
			}
			// if we select End
			else
			{
				Application->MessageBox(String("See you soon !").c_str(), "Orbital Names", MB_OK);
				Close();
			}
		}

	}
	// else we have the play screen
	else {

		int HotSpotIndex=PlanetsHSList->GetHotSpot(X,Y);

		if (HotSpotIndex < 0) return; // Not a hot spot point

		// if Normal is false, we are in the Help Mode
		if (!Normal)
		{
			// if we select the wrong planet a sound is played and a message box appears
			if (idPlanet != HotSpotIndex)
			{
				sndPlaySound(Random->GetFileName("*.wav",WRONG_DIR).c_str(),SND_SYNC);
				Application->MessageBox((String("Wrong answer. You selected ") + PlanetsHSList->HotSpot[HotSpotIndex]->GetText() + String(" and we asked ") + PlanetsHSList->HotSpot[idPlanet]->GetText()).c_str(), "Expert mode", MB_OK);
				return;
			}
		}

		Drag->StartDragging(X,Y,PlanetsHSList->HotSpot[HotSpotIndex]->GetBlitPos(),PlanetsHSList->HotSpot[HotSpotIndex]->GetBlitFrame(0),true,true,true);
		mDragPHSNum=HotSpotIndex;
	}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
{

	// PlayBG is true so we have the main screen
	if (PlayBG)
	{
		int HotSpotIndex=PlayHSList->GetHotSpot(X,Y);


		if (HotSpotIndex < 0 ) // Not hot
		{
			if (mPrevPlayHS >= 0) // Check if just rolled off
			{
				PlayHSList->HotSpot[mPrevPlayHS]->BlitImage(0,Transparent);
				mPrevPlayHS=HotSpotIndex;
			}
			return;
		}
		mPrevPlayHS=HotSpotIndex; // Keep so we know which one to restore when roll off
		PlayHSList->HotSpot[HotSpotIndex]->BlitImage(1,Transparent);
	}
	// else we are in the play mode
	else
	{
		if (Drag->Dragging())
		{
			Drag->MoveTo(TPoint(X,Y));
		}

		int HotSpotIndex=PlanetsHSList->GetHotSpot(X,Y);


		if (HotSpotIndex < 0 ) // Not hot
		{
			if (mPrevPlanetsHS >= 0) // Check if just rolled off
			{
				PlanetsHSList->HotSpot[mPrevPlanetsHS]->BlitImage(0,Transparent);
				mPrevPlanetsHS=HotSpotIndex;
			}
			return;
		}

		// if a planet is enabled it is highlighted
		if (PlanetsHSList->HotSpot[HotSpotIndex]->Enabled())
		{
			mPrevPlanetsHS=HotSpotIndex; // Keep so we know which one to restore when roll off
			PlanetsHSList->HotSpot[HotSpotIndex]->BlitImage(1,Transparent);
		}
	}
}
//---------------------------------------------------------------------------


void __fastcall TForm1::FormMouseUp(TObject *Sender, TMouseButton Button,  TShiftState Shift, int X, int Y)
{

	if (!Drag->Dragging()) return; // Not dragging so have nothing to do

	// we check if we are on the correct orbit
	int HotSpotIndex=OrbitsHSList->GetHotSpot(X,Y);

	// if we are not on the right orbit the planet comes back on the original position
	if (HotSpotIndex < 0)
	{
		THotSpot *SrcHS=PlanetsHSList->HotSpot[mDragPHSNum];
		Drag->SlideBlit(Drag->GetBlitPos(),SrcHS->GetBlitPos(), SrcHS->GetBlitFrame(3));
		Drag->EndDragging();
	}
	else
	{

		// if the planet is on the correct orbit
		if (OrbitsHSList->HotSpot[HotSpotIndex]->GetID() == PlanetsHSList->HotSpot[mDragPHSNum]->GetID())
		{
			mBlitPosDrag[mDragPHSNum]=Drag->GetBlitPos();
			Drag->EndDragging();
			PlanetsHSList->HotSpot[mDragPHSNum]->BlitImage(2,Transparent);
			// we disable the HotSpot of the planet
			PlanetsHSList->HotSpot[mDragPHSNum]->Disable();
			// we play a random sound
			sndPlaySound(Random->GetFileName("*.wav",RIGHT_DIR).c_str(),SND_SYNC);
			// and a message box to say the name of the planet
			Application->MessageBox(PlanetsHSList->HotSpot[mDragPHSNum]->GetText().c_str(), "You found", MB_OK);
			// we increment TotalGood
			TotalGood++;
			nbError=0;

			// if we have found the 9 planets
			if (TotalGood == 9)
			{
				sndPlaySound((String(SOUND_PATH)+"end.wav").c_str(),SND_ASYNC);
				Application->MessageBox("You found all the 9 planets !", "Congratulations", MB_OK);
				PlayBG=true;
				PlanetsBG=false;
				NewGame=true;
				delete PlanetsHSList;
				delete PlayHSList;
				delete OrbitsHSList;
				Drag->ProcessMessages();
				// a new game can start
				Form1->Refresh();
			}
			else
			{
				if (!Normal)
				{
					int j=MyRand(9);
					// we choose a new planet to move. We check if the random number is not a planet already moved.
					while (!PlanetsHSList->HotSpot[j]->Enabled()) j=MyRand(9);
					idPlanet=j;
					// a message box to say the name of the next planet to find
					Application->MessageBox((String("Now you must place ") + PlanetsHSList->HotSpot[idPlanet]->GetText()).c_str(), "Expert Mode", MB_OK);
				}
			}
		}
		// if we are on the wrong orbit
		else
		{
			if (!Normal)
			{
				sndPlaySound(Random->GetFileName("*.wav",WRONG_DIR).c_str(),SND_SYNC);
				// we increment the number of errors
				nbError++;
				Application->MessageBox((String("Wrong answer. You are on the orbit of ") + PlanetsHSList->HotSpot[HotSpotIndex]->GetText()  + String(" and we asked ") + PlanetsHSList->HotSpot[idPlanet]->GetText()).c_str(), "Expert mode", MB_OK);
			}
			// the planet comes back on its original position
			THotSpot *SrcHS=PlanetsHSList->HotSpot[mDragPHSNum];
			Drag->SlideBlit(Drag->GetBlitPos(),SrcHS->GetBlitPos(), SrcHS->GetBlitFrame(0));
			Drag->EndDragging();

			if (!Normal)
			{
				// if we have too many errors, automatic help is called
				if (nbError == NB_ERROR_MAX)
				{
					nbError=0;
					autoHelp();
					PlanetsHSList->HotSpot[mDragPHSNum]->BlitImage(2,Transparent);
					PlanetsHSList->HotSpot[mDragPHSNum]->Disable();
					TotalGood++;
					if (TotalGood == 9)
					{
						sndPlaySound((String(SOUND_PATH)+"end.wav").c_str(),SND_ASYNC);
						Application->MessageBox("You found all the 9 planets !", "Congratulations", MB_OK);
						PlayBG=true;
						PlanetsBG=false;
						NewGame=true;
						delete PlanetsHSList;
						delete PlayHSList;
						delete OrbitsHSList;
						Drag->ProcessMessages();
						Form1->Refresh();
					}
					else
					{
						int j=MyRand(9);
						while (!PlanetsHSList->HotSpot[j]->Enabled()) j=MyRand(9);
						idPlanet=j;
						Application->MessageBox((String("Now you must place ") + PlanetsHSList->HotSpot[idPlanet]->GetText()).c_str(), "Expert Mode", MB_OK);
					}
				}
			}
		}
	}
}
//---------------------------------------------------------------------------
// autoHelp() moves the cursor, takes the correct planet, and puts it on the correct orbit

void TForm1::autoHelp()
{
	int X,Y;

	// Use a pointer to shorten the length of the commands.
	THotSpot *hsPlanet=PlanetsHSList->HotSpot[idPlanet];

	THotSpot *hsOrbit=OrbitsHSList->HotSpot[hsPlanet->GetID()];

	// Send mouse messages so the drag and drop class knows the mouse is moving so moves the blit
	Auto->ProcessMessages(true);
	// Find out where the cursor currently is as we don't have X and Y passed to this event
	Auto->GetCursorPos(&X,&Y);

	// Move cursor from here to centre of the correct planet
	Auto->MoveCursor(X,Y,hsPlanet->GetCentreX(),hsPlanet->GetCentreY(),true,10,50);

	// Start dragging from centre of the planet using the boat blit frame 3
	Drag->StartDragging(hsPlanet->GetCentreX(),hsPlanet->GetCentreY(),hsPlanet->GetBlitPos(),hsPlanet->GetBlitFrame(3));

	// Move the cursor from the planet to the orbit centre.
	// As mouse move messages are being sent, the planet will follow the cursor
	Auto->MoveCursor(hsPlanet->GetCentreX(),hsPlanet->GetCentreY(),hsOrbit->GetCentreX(),hsOrbit->GetCentreY(),10,0);

	Drag->EndDragging();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
{
	// when we press ESC the play is over and we go back on the main screen
	if (Key == VK_ESCAPE)
	{
		PlayBG=true;
		PlanetsBG=false;
		NewGame=true;
		delete PlanetsHSList;
		delete PlayHSList;
		delete OrbitsHSList;
		Drag->ProcessMessages();
		Form1->Refresh();
	}
}






