/*********************************************************************************************/
/*                                                                                           */
/* Main Game Code                                                                            */
/*                                                                                            */
/*********************************************************************************************/

#include <sys\types.h>
#include <libapi.h>
#include <stdio.h>
#include <libpad.h>
#include "typedefs.h"
#include "cd.h"
#include "gpu.h"
#include "file.h"
#include "psxinput.h"
#include "specific.h"
#include "pad.h"
//#include "stypes.h"
#include "..\game\objects.h"
#include "..\game\items.h"
#include "..\game\lara.h"
#include "..\game\laraanim.h"
#include "..\game\sound.h"
#include "..\game\input.h"
#include "..\game\invfunc.h"
#include "..\game\savegame.h"
#include "..\game\gameflow.h"
#include "..\game\title.h"
#include "..\game\demo.h"
#include "..\game\cinema.h"

#include "..\game\control.h"	// SONY_SHELL
#include "picture.h"	// SONY_SHELL

/*---------------------------------------------------------------------------
 *	Externals
\*--------------------------------------------------------------------------*/

extern int level_complete;
extern int cutscene_track;
extern sint32 TitleSequence();

void CheckGymCheat();
void CheckCheatMode();
void CheckRealCheatMode();

/*---------------------------------------------------------------------------
 *	Globals
\*--------------------------------------------------------------------------*/

/* GLOBAL POINTER START ADDRESS (first defined/initialized variable = GP?) */
int gp_start_address = ('D')+('U'<<8)+('D'<<16)+('E'<<24);
char exit_message[128];

/*---------------------------------------------------------------------------
 *	Local Functions
\*--------------------------------------------------------------------------*/

#define MODE_INTERACTIVE 0
#define MODE_NONINTERACTIVE 1

int GnDemoMode;
int GnTimeOut;
int GnCDDATrack;
int GnDemoTracks;
int demo_quit_flag;
int global_frig_timer;

static void StickCheckBackInForReloc()
{
	CheckCallback();
};


#ifdef PSX_SONY_DEMO_SHELL

static void DemoVSyncRoutine(void)
{
	if ((GnDemoMode == 1)
	&&  (global_frig_timer > 0)
	&&  (--global_frig_timer == 0))
		reset_flag = 1;
}

#if !defined(NTSC)

static void Demo1FrontEnd(void)
{
	int	lang;
	TEXTSTRING *nojoytext=NULL;

#ifdef PLAY_FMV
#if !defined(PSX_SONY_DEMO_SHELL) && !defined(TEST_SONY_DEMO_SHELL)
	FMV_Play("\\FMV\\LOGO.FMV", 1, 865);
#else
//	FMV_Play("\\TOMB2\\FMV\\LOGO.FMV", 1, 865);
#endif
#endif

	InitialiseLevel(0, IL_TITLE);

//	S_DisplayPicture(GF_titlefilenames[GFT_TITLEPIC]);
//	printf("LoadTitle\n");
//	S_LoadLevelFile(GF_titlefilenames[GFT_TITLEFILE], 0, IL_QUIET );
//	printf("FadeUp\n");

	fades_enabled = 1;
	S_InitFade(FADE_MAX,FADE_MID,0);
	S_WaitFade();

	T_InitPrint();
	for ( ;; )
	{
		S_InitialisePolyList();
		S_ClearScreen();
		S_UpdateInput();
		if ( !PadConnected )                    // Some Buffoon has removed their Controller
		{
			if ( nojoytext==NULL )
			{
#if defined(NTSC)
  				nojoytext = T_Print(0,40,0,GF_PSXStrings[PSSTR_NOJOY_TEXT] );
#else
  				nojoytext = T_Print(0,29,0,GF_PSXStrings[PSSTR_NOJOY_TEXT] );
#endif
   				T_CentreH( nojoytext, 1 );
				T_FlashText(nojoytext, 1, 20);
			}
		}
		else
		{
			if ( nojoytext )
			{
				T_RemovePrint(nojoytext);
				nojoytext = NULL;
			}
		}
		S_DrawPic();

		inputDB = GetDebouncedInput(input);
		if ((lang=GetLanguageRequester())>0)
			break;

		T_DrawText();
		S_OutputPolyList();
		S_DumpScreen();

	}
	S_InitFade(FADE_MID,FADE_MIN,0);			// Pauls All level stats screens
	S_WaitFade();                               // are on faded down game... Now Fade all way down

	T_RemovePrint(nojoytext);
	nojoytext = NULL;

	reset_flag = 0;

#if !defined(PSX_SONY_DEMO_SHELL) && !defined(TEST_SONY_DEMO_SHELL)
	if (lang==2)
		GF_LoadScriptFile("data\\gerpsx.dat");
	else if (lang==3)
		GF_LoadScriptFile("data\\frpsx.dat");

#ifdef PLAY_FMV
	FMV_Play("\\FMV\\ANCIENT.FMV", 1, 4355);
#endif
#else
	if (lang==2)
		GF_LoadScriptFile("tomb2\\data\\gerpsx.dat");
	else if (lang==3)
		GF_LoadScriptFile("tomb2\\data\\frpsx.dat");
#ifdef PLAY_FMV
	FMV_Play("\\TOMB2\\FMV\\ANCIENT.FMV", 1, 4355);
#endif
#endif


}
#endif

#endif

/*---------------------------------------------------------------------------
 *	Public Functions
\*--------------------------------------------------------------------------*/

#if !defined(PSX_SONY_DEMO_SHELL) && !defined(TEST_SONY_DEMO_SHELL)

int main()
{
	sint32 option=0, ok, level_number;

#if !defined(CD_LOAD) && !defined(EZORAY)
	SetSp(0x807ffff0);
#else
	SetSp(0x807ffff0);
//##	SetSp(0x801ffff0);
#endif

	S_InitialiseSystem();

	init_game_malloc();
	S_DisplayPicture("PIX\\INITLOAD.RAW");
	S_FadeUp();
//	S_ShowPicture("PIX\\INITLOAD.RAW", 1, 0);

	SOUND_Init();

	if (!GF_LoadScriptFile("data\\Tombpsx.dat"))
	{
		printf("ERROR: Can't initialise script file\n\n");
		while(1);
	}

//	FMV_Play("\\FMV\\VICTOR.FMV", 0, 195);
//	FMV_Play("\\FMV\\LOGO.FMV", 1, 880);
/*
	FMV_Play("\\FMV\\ANCIENT.FMV", 1, 4370);
	FMV_Play("\\FMV\\MODERN.FMV", 1, 315);
	FMV_Play("\\FMV\\LANDING.FMV", 1, 365);
	FMV_Play("\\FMV\\MS.FMV", 1, 990);
	FMV_Play("\\FMV\\CRASH.FMV", 1, 1530);
	FMV_Play("\\FMV\\JEEP.FMV", 1, 1856);
	FMV_Play("\\FMV\\END.FMV", 1, 618);
	cutscene_track = 3;
	GF_Cutscene_Orientation = 0;
	StartCinematic(0);
	GF_Cutscene_Orientation = 0x4000;
	cutscene_track = 4;
	StartCinematic(1);
	GF_Cutscene_Orientation = 0x4000;
	cutscene_track = 5;
	StartCinematic(2);
	GF_Cutscene_Orientation = 0;
	cutscene_track = 30;
	StartCinematic(3);
*/

//	GF_DoLevelSequence(1, IL_NORMAL);
//	StartGame(1,IL_NORMAL);
//	StartDemo(1);

	savegame.bonus_flag = 0;
	InitialiseStartInfo(); 		// GAV

#ifdef GAMEDEBUG
	printf("Entering frontend sequence...\n");
#endif


#if defined(DEMO1) && !defined(NTSC)
//	Demo1FrontEnd();
#else
	if (GF_DoFrontEndSequence())
	{
#ifdef GAMEDEBUG
		printf("GameMain: failed in GF_DoFrontEndSequence()\n");
#endif
	}
#endif

#ifndef EZORAY
//	#ifndef GAMEDEBUG
		#if defined(JAPAN)
			S_ShowPicture( GF_titlefilenames[GFT_COPYRIGHTSPIC_JAP], 3*30, 0 );
		#elif defined(NTSC)
			S_ShowPicture( GF_titlefilenames[GFT_COPYRIGHTSPIC_US], 3*30, 0 );
		#else
			S_ShowPicture( GF_titlefilenames[GFT_COPYRIGHTSPIC], 3*25, 0 );
		#endif
//	#endif
#endif

#if defined(CD_LOAD) || defined(PLAY_CDTRACKS)
	CD_Init(1);
#endif

	title_loaded = 0;
	option = gameflow.firstOption;

#ifdef GAMEDEBUG
	printf("First Option: %x (EXIT_TO_TITLE=%x)\n\n",(int)option,(int)EXIT_TO_TITLE);
#endif

	ok = 1;
	while (ok)
	{
		level_number = option & 0xff;
		option &= ~0xff;

		switch(option)
		{
			case EXIT_TO_OPTION:
			case EXIT_TO_TITLE:
#if defined(GAMEDEBUG) && defined(PSX_VERSION)
				printf("EXIT_TO_TITLE\n");
#endif
				if ( !gameflow.title_disabled )
				{
#ifdef GAMEDEBUG
					printf("Entering TitleSequence\n\n");
#endif
					option = TitleSequence();
					GF_StartGame = 1;
				}
				else if (gameflow.title_replace>=0 &&
					     gameflow.title_replace!=EXIT_TO_TITLE)
				{
					option = gameflow.title_replace;
				}
				else
				{
					printf("ERROR: Title disabled & no replacement\n\n");
					while(1);
				}
				break;
			case DOSTORYSOFAR:
#if defined(GAMEDEBUG) && defined(PSX_VERSION)
				printf("DOSTORYSOFAR: %d\n", (int)level_number);
#endif
				title_loaded = 0;
				if (level_number < (gameflow.num_levels-gameflow.num_demos))
					GF_DoStorySoFar( level_number );
				else
					printf("ERROR: Invalid level number (%d)\n", (int)level_number );
				option = EXIT_TO_TITLE;
				break;

			case STARTGAME:
#if defined(GAMEDEBUG) && defined(PSX_VERSION)
				printf("STARTGAME: %d\n", (int)level_number);
#endif
				if ( gameflow.singlelevel>=0 )
				{
					option = GF_DoLevelSequence(gameflow.singlelevel, IL_NORMAL);
				}
				else if (level_number < (gameflow.num_levels-gameflow.num_demos))
				{
					option = GF_DoLevelSequence(level_number, IL_NORMAL);
				}
				else
				{
					printf("ERROR: Invalid level number (%d)\n", (int)level_number );
					option = EXIT_TO_TITLE;
				}
				break;
			case STARTSAVEDGAME:
#if defined(GAMEDEBUG) && defined(PSX_VERSION)
				printf("STARTSAVEDGAME: %d\n", (int)level_number);
#endif
				if ( level_number <= gameflow.num_levels )
				{
					option = GF_DoLevelSequence(level_number, IL_SAVED);
				}
				else
				{
					printf("GameMain: STARTSAVEDGAME with invalid level number (%d)",(int)level_number);
					option = EXIT_TO_TITLE;
				}
				break;

			case STARTCINE:
#if defined(GAMEDEBUG) && defined(PSX_VERSION)
				printf("STARTCINE: %d\n", (int)level_number);
#endif
				StartCinematic(level_number);
				option = EXIT_TO_TITLE;
				break;

			case STARTDEMO:
#if defined(GAMEDEBUG) && defined(PSX_VERSION)
				printf("STARTDEMO\n");
#endif
				option = DoDemoSequence( -1 );
				//option = StartDemo(-1);
				break;
/*			case LEVELCOMPLETE:
#if defined(GAMEDEBUG) && defined(PSX_VERSION)
				printf("LEVELCOMPLETE\n");
#endif
				option = LevelCompleteSequence(level_number);
				break;
*/
			case EXITGAME:
#if defined(GAMEDEBUG) && defined(PSX_VERSION)
				printf("EXITGAME\n");
#endif
	  			option = EXIT_TO_TITLE;
				break;
			default:
#if defined(GAMEDEBUG) && defined(PSX_VERSION)
				printf("OPTION %d (%x)\n", (int)option, (int)option);
#endif
	  			option = EXIT_TO_TITLE;
				break;
		}
	}
	return 0;	// to stop warning
}

#else
//------------------------------------------------------------------------------------------------------
//	S O N Y   D E M O   S H E L L   S T U F F
//------------------------------------------------------------------------------------------------------

#if defined(PSX_SONY_DEMO_SHELL)
int main(int argc,char **argv)			// i know, it`s and ifdef nightmare... but it`s got to be done...
#else
void 	main( void )
#endif
{
	sint32 option=0, ok, level_number;

#if defined(TEST_SONY_DEMO_SHELL)
//	GnDemoMode=MODE_INTERACTIVE;
	GnDemoMode=MODE_NONINTERACTIVE;
	GnTimeOut=60;
	GnCDDATrack=2;
	GnDemoTracks=0;
#else
	GnDemoMode=((int *)argv)[0];
	GnTimeOut=((int *)argv)[1];
	GnCDDATrack=((int *)argv)[2];
	GnDemoTracks=((int *)argv)[3];
#endif

	printf("\nmode=%d; timeout=%d; track=%d; tracks=%d\n\n",GnDemoMode,GnTimeOut,GnCDDATrack,GnDemoTracks);

	global_frig_timer = (GnTimeOut*50);
	demo_quit_flag=0;

	S_InitialiseSystem();
	SOUND_Init();

//	GF_DoFrontEndSequence();

#if defined(TEST_SONY_DEMO_SHELL)
	if (!GF_LoadScriptFile("tomb3\\tombpsx.dat"))
#else
	if (!GF_LoadScriptFile("tomb3\\data\\tombpsx.dat"))
#endif
	{
		printf("ERROR: Can't initialise script file\n\n");
		printf("Tombraider III exit... from main();\n");
#if !defined(TEST_SONY_DEMO_SHELL)
		return(0);					// needed for when we return to demodisk cd bootstrap program...
#else
		while(1);
#endif
	}

//#if !defined(NTSC)
//	Demo1FrontEnd();
//#endif

	//	printf("Script initialised\n");
	gameflow.noinput_time = GnTimeOut*30;
	gameflow.noinput_timeout = 1;

	if (GnDemoMode)
		VSYNC_Add(DemoVSyncRoutine);

	savegame.bonus_flag = 0;
	InitialiseStartInfo();

     printf("I am running in %s mode, with a timeout of %d seconds.\n",
            (GnDemoMode == MODE_INTERACTIVE)?"interactive":"attract",GnTimeOut);

	if (GnDemoMode)
	{
		printf("Loading NON-INTERACTIVE demo\n");
		GF_DoLevelSequence(gameflow.singlelevel+1, IL_DEMO);
	}
	else
	{
		printf("Loading INTERACTIVE demo\n");
		GF_DoLevelSequence(gameflow.singlelevel, IL_NORMAL);
	}

//##	init_game_malloc();
//##	fades_enabled = 1;
//##	GF_DoFrontEndSequence();
//	S_ShowPicture("pix\\demopic.raw",5*30,0);

//	load_and_display_hires_picture("pix\\demopic1.raw");
//	load_and_display_hires_picture("pix\\demopic2.raw");

	S_CleanupSystem();
	printf("Tombraider III exit... from main();\n");
#if !defined(TEST_SONY_DEMO_SHELL)
	return(0);					// needed for when we return to demodisk cd bootstrap program...
#endif
}
#endif

//------------------------------------------------------------------------------------------------------
//	C H E A T M O D E   C H E C K S
//------------------------------------------------------------------------------------------------------

static char Cheats[5][4] = {
	{ 'G'-'A', 'U'-'A', 'N'-'A', 'S'-'A' },
	{ 'L'-'A', 'A'-'A', 'R'-'A', 'A'-'A' },
	{ 'S'-'A', 'K'-'A', 'I'-'A', 'P'-'A' },
	{ 'A'-'A', 'R'-'A', 'S'-'A', 'E'-'A' },
	{ 'R'-'A', 'A'-'A', 'C'-'A', 'E'-'A' }
};

void CheckCheatMode()
{
	static ULONG pad=0;
	static ULONG Edge;

	static char CheatCnt = 0;
	static BYTE CheatSel = -1;

/* -------- read pad */

	Edge = pad;

	if (GoodData(&GPad1))
		pad = (~GPad1.data.pad)&0xffff;

	Edge = ((Edge ^ pad) & pad);

	if (Edge & ~(PAD_L2|PAD_R2))
	{
		CheatCnt = 0;
		CheatSel = -1;
		return;
	}

	if (!(Edge & (PAD_L2|PAD_R2)))
		return;

/* -------- check Gym cheats */

	if (CurrentLevel == LV_GYM)
	{
		char onoff;

		onoff = Cheats[4][CheatCnt/5] & (1 << (CheatCnt % 5));

		if ((!onoff) && (Edge & PAD_L2))
			CheatCnt++;

		else if ((onoff) && (Edge & PAD_R2))
			CheatCnt++;

		else
			CheatCnt=0;

		if (CheatCnt == 20)
		{
 		 	Inv_AddItem(KEY_ITEM1);
			SoundEffect(2, NULL, SFX_ALWAYS);
		}
	}

/* -------- check game cheats */

	else
	{
		char onoff;

		if (CheatSel == -1)
		{
			if (!CheatCnt)
			{
				if (Edge & PAD_R2)
					CheatSel = 1;
			}

			else if ((CheatCnt == 1) && (Edge & PAD_L2))
				CheatSel = 3;

			else if (CheatCnt == 2)
			{
				if (Edge & PAD_R2)
					CheatSel = 0;

				else
					CheatSel = 2;
			}

			CheatCnt++;
		}

		else
		{
			onoff = Cheats[CheatSel][CheatCnt/5] & (1 << (CheatCnt % 5));

			if ((!onoff) && (Edge & PAD_L2))
				CheatCnt++;

			else if ((onoff) && (Edge & PAD_R2))
				CheatCnt++;

			else
			{
#ifdef GAMEDEBUG
				printf("%d failed at %d\n", CheatSel, CheatCnt);
#endif
				CheatCnt = 0;
				CheatSel = -1;
			}

			if (CheatCnt == 20)
			{
				switch (CheatSel)
				{
					int i;

					case 1:
						lara_item->hit_points = 1000;
						SoundEffect(36, NULL, SFX_ALWAYS);
						break;

					case 2:
						level_complete = 1;
						SoundEffect(2, NULL, SFX_ALWAYS);
						break;

					case 3:
			 		 	Inv_AddItem(KEY_ITEM1);
			 		 	Inv_AddItem(KEY_ITEM2);
			 		 	Inv_AddItem(KEY_ITEM3);
			 		 	Inv_AddItem(KEY_ITEM4);
			 		 	Inv_AddItem(PUZZLE_ITEM1);
			 		 	Inv_AddItem(PUZZLE_ITEM2);
			 		 	Inv_AddItem(PUZZLE_ITEM3);
			 		 	Inv_AddItem(PUZZLE_ITEM4);
			 		 	Inv_AddItem(PICKUP_ITEM1);
			 		 	Inv_AddItem(PICKUP_ITEM2);
						savegame.secrets = 255;
						SoundEffect(116, NULL, SFX_ALWAYS);
						break;
					default:
 						Inv_AddItem(HARPOON_ITEM);
 						Inv_AddItem(ROCKET_GUN_ITEM);
 						Inv_AddItem(GRENADE_GUN_ITEM);
 						Inv_AddItem(M16_ITEM);
 						Inv_AddItem(SHOTGUN_ITEM);
 						Inv_AddItem(MAGNUM_ITEM);
 						Inv_AddItem(UZI_ITEM);

						lara.shotgun.ammo = 500;
 						lara.magnums.ammo = 500;
 						lara.uzis.ammo = 5000;
 						lara.rocket.ammo = 5000;
 						lara.grenade.ammo = 5000;
 						lara.m16.ammo = 5000;
 						lara.harpoon.ammo = 5000;

						for ( i=0 ; i<50 ; i++ )
 						{
 							Inv_AddItem(MEDI_ITEM);
							Inv_AddItem(BIGMEDI_ITEM);
							Inv_AddItem(FLARE_ITEM);
							Inv_AddItem(SAVEGAME_CRYSTAL_ITEM);
						}
						SoundEffect(30, NULL, SFX_ALWAYS);
						break;

				}

				CheatCnt = 0;
				CheatSel = -1;
			}
		}
	}
}
