/*********************************************************************************************/
/*                                                                                           */
/* Global variables for game, levels, etc                                                    */
/*                                                                                           */
/*********************************************************************************************/

#include <sys\types.h>
#include <stdio.h>
#include "typedefs.h"
#include "malloc.h"
#include "psxinput.h"
#include "picture.h"
#include "file.h"
#include "specific.h"
#include "memcard.h"
#include "option.h"
#include "3d_obj.h"
//#include "psxmisc.h"
#include "..\game\control.h"
#include "..\game\camera.h"
#include "..\game\input.h"
#include "..\game\savegame.h"
#include "..\game\gameflow.h"
#include "..\game\text.h"
#include "..\game\title.h"
#include "..\game\invdata.h"
#include "..\game\inventry.h"
#include "..\game\health.h"
#include "..\game\setup.h"
#include "..\game\draw.h"
#include "..\game\invfunc.h"
#include "..\game\objects.h"

extern sint16 NextAdventure;

//PHD_3DPOS 	mycam,objpos;

uint32	StartLevel=LV_FIRSTLEVEL;
uint32	CurrentLevel=0;
uint32	RestartLevel=LV_FIRSTLEVEL;
int level_complete=0;

int 	MemCardAvailable=1;
int		SavedGames = 1;
//##int		fades_enabled=1;

// Saved Games
sint16	number_saved=0;
sint16	saved_levels[MAXIMUM_LEVELS]={-1};

int		GnGameMode=GAMEMODE_NOT_IN_GAME;

// Valid Levels
/*char Valid_Level_Strings[MAXIMUM_LEVELS][LEVLEN];
sint16	number_valid=16;
sint16	valid_levels[MAXIMUM_LEVELS]={
        1, //LV_WALL,
        2, //LV_BOAT,
        3, //LV_VENICE,
        4, //LV_OPERA,
        5, //LV_RIG,
        6, //LV_UNWATER,
        7, //LV_KEEL,
        8, //LV_LIVING,
        9, //LV_DOCK,
        10, //LV_SKIDOO,
        11, //LV_MONASTRY,
        12, //LV_CATACOMB,
        13, //LV_ICECAVE,
        14, //LV_EMPRTOMB,
        15, //LV_FLOATING,
        16, //LV_HOUSE,
		-1
};
*/
void DisplayCredits( void );
void MeshTest(int mesh);

int Level2World(int level)
{
	if (level <= LV_INDIABOSS)
		return WORLD_INDIA;

	else if (level <= LV_PACBOSS)
		return WORLD_SPACIFIC;

	else if (level <= LV_OFFICE)
		return WORLD_LONDON;

	else if (level <= LV_AREA51)
		return WORLD_NEVADA;

	else
		return WORLD_ANTARCTIC;
}

int World2Level(int world)
{
	if (world == WORLD_INDIA)
		return LV_JUNGLE-1;

	if (world == WORLD_SPACIFIC)
		return LV_SHORE-1;

	if (world == WORLD_LONDON)
		return LV_ROOFTOPS-1;

	if (world == WORLD_NEVADA)
		return LV_DESERT-1;

	else
		return LV_ANTARC-1;
}

void SortOutAdventureSave(int world)
{
	if (savegame.WorldRequired == WORLD_INDIA)
		savegame.AfterIndia = world;

	if (savegame.WorldRequired == WORLD_SPACIFIC)
		savegame.AfterSPacific = world;

	if (savegame.WorldRequired == WORLD_LONDON)
		savegame.AfterLondon = world;

	if (savegame.WorldRequired == WORLD_NEVADA)
		savegame.AfterNevada = world;

	savegame.AfterAdventureSave = 0;
	savegame.WorldRequired = 0;
}

/******************************************************************************
 *						Main Game Loop
 *****************************************************************************/
/* Main game loop. Frame compensated by performing control phase repeatedly */
sint32 GameLoop(int demo_mode)
{
	sint32 nframes=1, game_over;

	overlay_flag = 1;
	InitialiseCamera();

	noinput_count = 0;

	GnGameMode = demo_mode ? GAMEMODE_IN_DEMO : GAMEMODE_IN_GAME;

	game_over = ControlPhase(nframes, demo_mode);

	while (!game_over)
	{
		nframes = DrawPhaseGame();
		game_over = ControlPhase(nframes, demo_mode);
	}

	GnGameMode=GAMEMODE_NOT_IN_GAME;

	S_SoundStopAllSamples();           // Stop any samples playing

//##	if (CurrentLevel != (gameflow.num_levels-gameflow.num_demos-1))
		S_CDStop();

	return (game_over);
}

/******************************************************************************
 *			Start Game until user Quits or Finishes level etc
 *****************************************************************************/
sint32 StartGame( int level_number, int type )
{
	int	nGameResult;

#ifdef GAMEDEBUG
	printf("Starting level: %d\n\n", (int)level_number);
#endif

	if (type==IL_NORMAL || type==IL_SAVED )
		RestartLevel = CurrentLevel = level_number;
	else
	{
		RestartLevel = LV_FIRSTLEVEL;
		CurrentLevel = level_number = 0;
	}

	if (type!=IL_SAVED)
		ModifyStartInfo(level_number);
	title_loaded = 0;

	if (type != IL_SAVED)
		InitialiseLevelFlags();

	if (!InitialiseLevel(level_number,type))
	{
#ifdef GAMEDEBUG
		printf("ERROR: Couldn't InitialiseLevel(%d,%d)",level_number,type);
#endif
		RestartLevel = CurrentLevel = 0;
		return(EXIT_TO_TITLE);
	}
#ifdef GAMEDEBUG
	printf("Entering GameLoop(0)\n");
#endif
	/* G A M E   L O O P   H E R E */
	/* G A M E   L O O P   H E R E */
	/* G A M E   L O O P   H E R E */
	fades_enabled = 0;
	nGameResult = GameLoop(0);
	fades_enabled = 1;

	if (nGameResult==EXIT_TO_TITLE || nGameResult==STARTDEMO)
	{
#ifdef GAMEDEBUG
		printf("EXIT_TO_TITLE\n");
#endif
		return nGameResult;
	}

	if (nGameResult==EXITGAME)
	{
#ifdef GAMEDEBUG
		printf("EXITGAME\n");
#endif
		CurrentLevel=0;
		return EXIT_TO_TITLE;
	}

	if (level_complete)
	{
		if (gameflow.demoversion && gameflow.singlelevel)
			return EXIT_TO_TITLE;

		if (CurrentLevel == LV_GYM)
		{
			S_FadeToBlack();
			return EXIT_TO_TITLE;
		}
		return LEVELCOMPLETE|CurrentLevel;
	}

	if (Inventory_Chosen)
	{
#ifdef GAMEDEBUG
		printf("Inv Chosen\n");

		printf("InvExtra[0]==%d [1]==%d\n", (int)Inventory_ExtraData[0], (int)Inventory_ExtraData[1]);
#endif
	  	if (Inventory_ExtraData[0] == 0)
	  	{
	  		level_number = Inventory_ExtraData[1];

			if (level_number == -1000)
			{
				S_FadeToBlack();								// Only fade to black if going back
		  		return(STARTSAVEDGAME|savegame.current_level);
			}
		/* -------- adventure select */

			else if (level_number == -2000)
			{
				int i;
				static char Adventure[] = {
					LV_JUNGLE,
					LV_SHORE,
					LV_DESERT,
					LV_JUNGLE,	// ## PERU
					LV_ROOFTOPS,
					LV_ANTARC
				};

				for ( i=0 ; i<3 ; i++ )
				{
					S_InitialisePolyList();
					DrawMonoScreen(0x50, 0x50, 0x70);
					S_OutputPolyList();
					S_DumpScreen();
				}

				S_CopyScreenToBuffer();

				S_LoadLevelFile(GF_titlefilenames[GFT_TITLEFILE], 0, IL_QUIET);

				Display_Inventory(INV_LEVELSELECT_MODE);
				DrawSync(0);
				XAFade(0);
				S_FadeToBlack();
				XAWaitFade();
				S_CDStop();

				return STARTGAME|Adventure[NextAdventure];
			}

			else if (level_number < 0)
			{
				S_FadeToBlack();								// Only fade to black if going back
				return(DOSTORYSOFAR|(-level_number));
			}

			else
			{
				XAFade(0);
				S_FadeToBlack();								// Only fade to black if going back
				XAWaitFade();
		  		return(STARTGAME|level_number);
			}
	  	}

		else if (Inventory_ExtraData[0] == 1)   // Middle Page
	  	{
			XAFade(0);
			S_FadeToBlack();								// Only fade to black if going back
			XAWaitFade();

			if (Inventory_Mode == INV_DEATH_MODE)
				return( STARTGAME|CurrentLevel );

			else if (gameflow.play_any_level)
				return( STARTGAME|Inventory_ExtraData[1] );

			else
				return( STARTGAME|LV_FIRSTLEVEL);
	  	}
	  	else
	  		return(EXITGAME);
	}
#ifdef GAMEDEBUG
		printf("Inv NOT Chosen\n");
#endif
	return(EXIT_TO_TITLE);
}

/******************************************************************************
 *				Level Complete Sequence
 *****************************************************************************/
sint32	LevelCompleteSequence(int level_number)
{
	return(EXIT_TO_TITLE);
}

#ifndef PSX_VERSION
#define TIME_POS		-30
#define SECRET_POS		-60
#define PICKUP_POS		-90
#define KILL_POS		-120
#define HEADING_POS		-150
#else
#define HEADING_POS		-150-40
#define TIME_POS		-30-40
#define SECRET_POS		-60-40
#define PICKUP_POS		-90-40
#define KILL_POS		-120-40
#endif


int LevelStats(int level_number)
{
	int n, world, adv=0;
	int	h=0,m=0,s=0;
	TEXTSTRING *nojoytext=NULL;
	char string[32];


	/* Add stats to savegame.start info for this level (used in final game stats) */
	savegame.start[level_number].timer = savegame.timer;
	savegame.start[level_number].ammo_used = savegame.ammo_used;
	savegame.start[level_number].ammo_hit = savegame.ammo_hit;
	savegame.start[level_number].distance_travelled = savegame.distance_travelled;
	savegame.start[level_number].kills = savegame.kills;
	savegame.start[level_number].secrets_found = savegame.secrets;
	savegame.start[level_number].health_used = savegame.health_used;

	s = savegame.timer/30;
	h = s/3600;
	m = (s/60)%60;
	s = s%60;

	sprintf(string,"%02d:%02d:%02d",h,m,s);

	// Get Number of secrets found
//	n = (savegame.secrets&1) + ((savegame.secrets&2)>>1) + ((savegame.secrets&4)>>2);
//	if (n>=3)
//	{
		// Give player bonuses for getting all secrets on this level!!!
//		GF_ModifyInventory( CurrentLevel,1 );
//	}

//##	printf("%d %d\n", gameflow.num_levels, level_number);


	S_InitFade(FADE_MAX,FADE_MID,1);
	XAFade(0);
	XAWaitFade();

	S_LoadLevelFile(GF_titlefilenames[GFT_TITLEFILE], 0, IL_QUIET );
	S_CDPlay(gameflow.stats_track, 1);

	fades_enabled = 1;
	S_WaitFade();

	RemovePromptText();
	T_InitPrint();
	DisplayContinueText();

	for ( ;; )
	{
		S_InitialisePolyList();
		S_ClearScreen();
		S_UpdateInput();

		if (!PadConnected)
		{
			if (nojoytext == NULL)
			{
#if defined(NTSC)
  				nojoytext = T_Print(0,40,9, GF_PSXStrings[PSSTR_NOJOY_TEXT]);
#else
  				nojoytext = T_Print(0,29,9, 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();

		if (reset_flag)
			input = IN_SELECT;

		inputDB = GetDebouncedInput(input);

		ShowStatsText(string,0);

//		DrawPickups(0);
		T_DrawText();
		S_OutputPolyList();
		S_DumpScreen();

		if (input & IN_SELECT || reset_flag)
			break;
	}

	RemoveContinueText();

/* -------- adventure complete */

	world = Level2World(level_number);

	if (level_number == LV_INDIABOSS)
	{
		if (savegame.IndiaComplete)
		{
			if (savegame.AfterIndia)
				CurrentLevel = World2Level(savegame.AfterIndia);
			else
				adv = world;
		}
		else
		{
			savegame.IndiaComplete = 1;
			savegame.AfterAdventureSave = 1;
			savegame.WorldRequired = world;
			adv = world;
			CreateStartInfo(MAXIMUM_LEVELS);
		}
	}

	else if (level_number == LV_PACBOSS)
	{
		if (savegame.SPacificComplete)
		{
			if (savegame.AfterSPacific)
				CurrentLevel = World2Level(savegame.AfterSPacific);
			else
				adv = world;
		}
		else
		{
			savegame.SPacificComplete = 1;
			savegame.AfterAdventureSave = 1;
			savegame.WorldRequired = world;
			adv = world;
			CreateStartInfo(MAXIMUM_LEVELS);
		}
	}

	else if (level_number == LV_OFFICE)
	{
		if (savegame.LondonComplete)
		{
			if (savegame.AfterLondon)
				CurrentLevel = World2Level(savegame.AfterLondon);
			else
				adv = world;
		}
		else
		{
			savegame.LondonComplete = 1;
			savegame.AfterAdventureSave = 1;
			savegame.WorldRequired = world;
			adv = world;
			CreateStartInfo(MAXIMUM_LEVELS);
		}
	}

	else if (level_number == LV_AREA51)
	{
		if (savegame.NevadaComplete)
		{
			if (savegame.AfterNevada)
		 		CurrentLevel = World2Level(savegame.AfterNevada);
			else
				adv = world;
		}
		else
		{
			savegame.NevadaComplete = 1;
			savegame.AfterAdventureSave = 1;
			savegame.WorldRequired = world;
			adv = world;
			CreateStartInfo(MAXIMUM_LEVELS);
		}
	}

/* -------- game complete */

	else if ((level_number == LV_CHAMBER) && (!savegame.AntarcticaComplete))
	{
		savegame.bonus_flag = 1;

		for ( n=LV_FIRSTLEVEL ; n<=gameflow.num_levels ; n++ )
	      	ModifyStartInfo(n);

		savegame.AntarcticaComplete = 1;
		savegame.current_level = LV_FIRSTLEVEL;
		savegame.AfterAdventureSave = 0;
	}

/* -------- level complete */

	else
	{
		if (savegame.WorldRequired)
		{
			if (((world == WORLD_INDIA) && (savegame.IndiaComplete))
			||  ((world == WORLD_SPACIFIC) && (savegame.SPacificComplete))
			||  ((world == WORLD_LONDON) && (savegame.LondonComplete))
			||  ((world == WORLD_NEVADA) && (savegame.NevadaComplete)))
			{
				savegame.AfterAdventureSave = 1;
//##				savegame.WorldRequired = 1;
			}
			else
				SortOutAdventureSave(world);
		}

		if (level_number == LV_ANTARC)
		{
			Inv_RemoveItem(ICON_PICKUP1_ITEM);
			Inv_RemoveItem(ICON_PICKUP2_ITEM);
			Inv_RemoveItem(ICON_PICKUP3_ITEM);
			Inv_RemoveItem(ICON_PICKUP4_ITEM);
		}

		savegame.current_level = level_number+1;
		CreateStartInfo(level_number+1);
	}

/* -------- bonus level complete */

	if (level_number == LV_STPAULS)
	{
		int n;

   		savegame.bonus_flag = 1;

		for ( n=LV_FIRSTLEVEL ; n<=gameflow.num_levels ; n++ )
		    	ModifyStartInfo(n);

//##		printf("Nicely done chum\n");
	}

	if (!reset_flag)
	{
		savegame.mid_level_save = 0;
		S_SaveGame(&savegame, sizeof(SAVEGAME_INFO), 0);
	}

	if (adv)
		return adv;

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

	S_CDStop();

	if (reset_flag)
		return -1;

	else
		return 0;
}



int	GameStats(int level_number, int type)
{
	TEXTSTRING *nojoytext=NULL;

	S_InitFade(FADE_MAX,FADE_MID, 0);
	S_WaitFade();

	savegame.start[CurrentLevel].timer = savegame.timer;
	savegame.start[CurrentLevel].ammo_used = savegame.ammo_used;
	savegame.start[CurrentLevel].ammo_hit = savegame.ammo_hit;
	savegame.start[CurrentLevel].distance_travelled = savegame.distance_travelled;
	savegame.start[CurrentLevel].kills = savegame.kills;
	savegame.start[CurrentLevel].secrets_found = savegame.secrets;
	savegame.start[CurrentLevel].health_used = savegame.health_used;
	savegame.GameComplete = 1;

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

	RemovePromptText();
	T_InitPrint();
	DisplayContinueText();

	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,9,GF_PSXStrings[PSSTR_NOJOY_TEXT] );
#else
  				nojoytext = T_Print(0,29,9,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();

		if (reset_flag) input = IN_SELECT;
		inputDB = GetDebouncedInput(input);
		ShowEndStatsText();

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

		if ( input&IN_SELECT || reset_flag )
			break;
	}
	RemoveContinueText();

	if ((!reset_flag) && (type != IL_STORY_SO_FAR))
	{

	/* -------- if got all secrets - enable extra level */

		int i, numsecrets=0, num=0;
		int totallevels = (gameflow.num_levels-gameflow.num_demos) - 1;

		for ( i=0 ; i<totallevels ; i++ )
		{
			numsecrets += (savegame.start[i].secrets_found & 1)
					 + ((savegame.start[i].secrets_found & 2) >> 1)
					 + ((savegame.start[i].secrets_found & 4) >> 2)
					 + ((savegame.start[i].secrets_found & 8) >> 3)
					 + ((savegame.start[i].secrets_found & 16) >> 4)
					 + ((savegame.start[i].secrets_found & 32) >> 5)
					 + ((savegame.start[i].secrets_found & 64) >> 6)
					 + ((savegame.start[i].secrets_found & 128) >> 7);

			num += LevelSecrets[i];
		}

		if (numsecrets >= num)
		{
			savegame.start[LV_STPAULS].available = 1;
			savegame.current_level = LV_STPAULS;
		}

		savegame.mid_level_save = 0;
		S_SaveGame(&savegame, sizeof(SAVEGAME_INFO), 0);
//##			savegame.bonus_flag = 1;           // Weve finished the Game so enable All Weapons etc etc
//##			for ( n=LV_FIRSTLEVEL;n<=gameflow.num_levels;n++ )
//##		      	ModifyStartInfo(n);
	}

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


/******************************************************************************
 *				Game Over Sequence
 *****************************************************************************/

/*
int	LevelIsValid(sint16 level_number)
{
	int		n;
	sint16 *valids;

	number_valid = 0;
	valids = valid_levels;
	for (;;)
	{
		if (*(valids++)<0)
			break;
		number_valid++;
	}
	for (n=0;n<number_valid;n++)
	{
		if (valid_levels[n]==level_number)
			return(1);
	}
	return(0);
}
*/

void GetValidLevelsList(REQUEST_INFO *req)
{
	int	n;

	RemoveAllReqItems(req);
	for (n=0;n<(gameflow.num_levels-1);n++)
		AddRequesterItem(req, GF_Level_Names[n+1],R_CENTRE, NULL,0);
}

void GetSavedGamesList(REQUEST_INFO *req)
{
	int	n;
	char str[16];
	int highest_level=0;

	RemoveAllReqItems(req);
	number_saved = 0;

	for ( n=LV_FIRSTLEVEL ; n<(gameflow.num_levels-gameflow.num_demos) ; n++ )
	{
		if (savegame.start[n].available)
		{
			if ((n == savegame.current_level)
			&&  (!savegame.mid_level_save))
			{
				req->selected = req->items;

				if (req->selected >= req->vis_lines)
					req->line_offset = req->selected-req->vis_lines+1;
			}

			AddRequesterItem(req, GF_Level_Names[n], R_CENTRE, NULL, 0);
			saved_levels[number_saved] = n;
			number_saved++;
			highest_level=n;
		}

		if ((n == savegame.current_level)
		&&  (savegame.AfterAdventureSave))
		{
			req->selected = req->items;

			if (req->selected >= req->vis_lines)
				req->line_offset = req->selected-req->vis_lines+1;

			AddRequesterItem(req, GF_PSXStrings[PSSTR_SPARE20], R_CENTRE|R_NO_TIME, NULL, 0);
			saved_levels[number_saved] = -2000;
			number_saved++;
		}

		if ((n == savegame.current_level)
		&&  (savegame.mid_level_save))
		{
			if (savegame.current_level > highest_level)
				highest_level = savegame.current_level;

			req->selected = req->items;

			if (req->selected >= req->vis_lines)
				req->line_offset = req->selected-req->vis_lines+1;

			sprintf(str,GF_GameStrings[GT_CURRENTPOS],n);
			AddRequesterItem( req, str,R_CENTRE|R_NO_TIME, NULL,0 );
			saved_levels[number_saved] = -1000;
			number_saved++;
		}
	}

//	if (!savegame.mid_level_save)
//	{
//		req->selected = req->items-1;
//		if (req->selected >= req->vis_lines)
//			req->line_offset = req->selected-req->vis_lines+1;
//	}

	if (Inventory_Mode == INV_TITLE_MODE)
	{
		AddRequesterItem(req, GF_GameStrings[GT_STORY_SO_FAR], R_CENTRE|R_NO_TIME, NULL, 0);
		saved_levels[number_saved] = -(highest_level);
		number_saved++;
	}

	// If no saved games
	if (!req->items)
		AddRequesterItem(req, GF_PSXStrings[PSSTR_SAVEMESS6], R_CENTRE, NULL, 0);
}



#define NUM_CREDITS 9+1
#define MAX_PACKED_SIZE	100000

void DisplayCredits(void)
{
	int	i;
	char fname[64];
	char *pics[NUM_CREDITS];

	fades_enabled = 1;
	S_FadeToBlack();
	init_game_malloc();

/* -------- load & display 'The End' */

	strcpy(fname, "pix\\theend.raw");
	pics[9] = game_malloc(FILE_Length(fname), LOAD_PICCY_BUFFER);
	FILE_Load(fname, pics[9]);

	S_DisplayPictureMem(pics[9]);
	S_FadeUp();
	S_WaitFade();

/* -------- load & display credits */

	for (i=0;i<NUM_CREDITS-1;i++)
	{
		sprintf(fname,"pix\\credit%02d.raw",i+1);

		pics[i] = game_malloc(FILE_Length(fname), LOAD_PICCY_BUFFER);
		FILE_Load(fname, pics[i]);
	}

	S_StartSyncedAudio(121);
	S_FadeToBlack();

	for ( i=0 ; i<NUM_CREDITS-1 ; i++ )
#ifdef PAL
		S_ShowPictureMem(pics[i], 7*25, 0);
#else
		S_ShowPictureMem(pics[i], 7*30, 0);
#endif

/* -------- load title */

	XAFade(0);
	XAWaitFade();

	S_CDStop();

	init_game_malloc();	// Dude & Jase frig

	S_DisplayPicture("pix\\theend2.raw");
	S_InitFade(FADE_MIN, FADE_MAX, 0);
	S_WaitFade();

	S_LoadLevelFile(GF_titlefilenames[GFT_TITLEFILE], 0, IL_QUIET);

	init_game_malloc();	// Dude & Jase frig
}

