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

#include "standard.h"
#include "global.h"
#include "game1.h"
#include "frontend.h"
#include "file.h"
#include "input.h"
#include "output.h"
#include "display.h"


#include "..\game\invdata.h"
#include "..\game\health.h" 
#include "..\game\invfunc.h"
#include "..\game\inventry.h"
#include "..\game\gameflow.h"
#include "..\game\savegame.h"
#include "..\game\title.h"
#include "..\game\setup.h"
#include "..\game\camera.h"
#include "..\game\control.h"
#include "..\game\objects.h"
#include "..\game\lara.h"
#include "..\game\sound.h"



uint32	StartLevel=LV_FIRSTLEVEL;
uint32	CurrentLevel=0;
int level_complete=0, SavedGames, save_counter=0;

int "C" GnGameMode=GAMEMODE_NOT_IN_GAME;

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

// Valid Levels
/*sint16	number_valid=0;
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
};

sint16	level_types[MAXIMUM_LEVELS]={
		LVT_PLAYABLE,
		LVT_PLAYABLE,
		LVT_PLAYABLE,
		LVT_PLAYABLE,
		LVT_PLAYABLE,
		LVT_PLAYABLE,
		LVT_PLAYABLE,
		LVT_PLAYABLE,
		LVT_PLAYABLE,
		LVT_PLAYABLE,
		LVT_PLAYABLE,
		LVT_PLAYABLE,
		LVT_PLAYABLE,
		LVT_PLAYABLE,
		LVT_PLAYABLE,
		LVT_PLAYABLE,
		LVT_PLAYABLE,
		LVT_CUTSCENE,
		LVT_CUTSCENE,
		LVT_CUTSCENE,
		LVT_CUTSCENE,
		LVT_PLAYABLE,
		LVT_PLAYABLE
};
*/



void	DisplayCredits( void );

extern "C" void FadePictureDown();

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

	//FMV_Play("eidos\\movies\\wg22m.rpl");
	if (type==IL_NORMAL || type==IL_SAVED || type==IL_DEMO)
		CurrentLevel = level_number;
	if (type!=IL_SAVED)
		ModifyStartInfo(level_number); 	
	title_loaded = 0;

	if (type!=IL_SAVED)
		InitialiseLevelFlags();

	if (!InitialiseLevel(level_number,type))
	{
		CurrentLevel = 0;
		Log(LT_Info,"ERROR: Load level failed, %s", exit_message);
		return(EXITGAME);
	}

#ifdef GAMEDEBUG
#if CODER==JASON
	Log(LT_Info,"Entering GameLoop(0) CurrentLevel=%d",CurrentLevel);
#endif
#ifdef PSX_VERSION
	printf("Entering GameLoop(0)\n");
#endif
#endif

//	FadePictureDown();
		
	int nGameResult=GameLoop(0);

	// if Inventory_Chosen then user chose to load/save/exit
	//Inventory_ExtraData[0] == load/save/exit
	//Inventory_ExtraData[1] == level_number chosen (-1 if load current mid-level position)
	if (nGameResult==EXIT_TO_TITLE || nGameResult==STARTDEMO)
		return nGameResult;
	if (nGameResult==EXITGAME)
	{
		CurrentLevel=0;
		return nGameResult;
	}


	// Redundent???
	if (level_complete)
	{
		if (gameflow.demoversion && gameflow.singlelevel)
			return(EXIT_TO_TITLE);
		if (CurrentLevel == LV_GYM)
		{
			S_FadeToBlack();
			return (EXIT_TO_TITLE);
		}

		S_FadeInInventory(1);
//		Log(LT_Info,"LEVELCOMPLETE|%d",CurrentLevel);
		return( LEVELCOMPLETE|CurrentLevel );
	}
	//

//	FadePictureDown();
//	S_FadeToBlack();
	if (Inventory_Chosen)
	{
		if (Inventory_ExtraData[0]==0)
		{
			S_LoadGame(&savegame, sizeof(SAVEGAME_INFO), Inventory_ExtraData[1]);
			return(STARTSAVEDGAME|Inventory_ExtraData[1]);
		}
		if (Inventory_ExtraData[0]==1)
		{
			if (gameflow.play_any_level)
				return( STARTGAME|Inventory_ExtraData[1]+1 );
			else
				return( STARTGAME|LV_FIRSTLEVEL);
		}
	}
	return(EXIT_TO_TITLE);
}


extern "C" void CreateMonoScreen();
extern "C" void FadePictureUp();

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

	overlay_flag = 1;
	InitialiseCamera();

	noinput_count = 0; // for demo time out

	GnGameMode=demo_mode?GAMEMODE_IN_DEMO:GAMEMODE_IN_GAME;



	Inv_AddItem( M16_ITEM );
	Inv_AddItem( ROCKET_GUN_ITEM );
	Inv_AddItem( SHOTGUN_ITEM );
	Inv_AddItem( UZI_ITEM );
	Inv_AddItem( MAGNUM_ITEM );
	Inv_AddItem( GUN_ITEM );
	Inv_AddItem( GRENADE_GUN_ITEM );

	for (int i=0;i<10;i++)
	{
		Inv_AddItem( FLAREBOX_ITEM );
		Inv_AddItem( MEDI_ITEM );
		Inv_AddItem( BIGMEDI_ITEM );
	}
	
	lara.magnums.ammo = MAGNUM_AMMO_CLIP*50;
	lara.uzis.ammo = UZI_AMMO_CLIP*50;
	lara.shotgun.ammo = SHOTGUN_AMMO_CLIP*50;
	lara.harpoon.ammo = SHOTGUN_AMMO_CLIP*50;
	lara.m16.ammo = SHOTGUN_AMMO_CLIP*50;
	lara.rocket.ammo = SHOTGUN_AMMO_CLIP*50;

	
	
	
	
	game_over = ControlPhase(nframes, demo_mode);
	while (!game_over)
	{
		nframes = DrawPhaseGame();
		if (GtWindowClosed)
			game_over=EXITGAME;
		else
			game_over = ControlPhase(nframes, demo_mode);
	}

	GnGameMode=GAMEMODE_NOT_IN_GAME;

	S_SoundStopAllSamples();           // Stop any samples playing
	S_CDStop();
	if (Option_Music_Volume)
		S_CDVolume(Option_Music_Volume * 25 + 5);

	return (game_over);
}

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

/******************************************************************************
 *				Print Statistics for Level
 *****************************************************************************/
int	LevelStats(int level_number)
{
/*	int		   n,numsecrets;
	int		   hours,minutes,seconds;
	TEXTSTRING *heading=NULL, *time=NULL, *kills=NULL,*secrets=NULL,*pickups=NULL;
	char string[100];
*/
//	int n, return_val;
	char string[100];
	int	h=0,m=0,s=0;

	/* 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 );
	}
*/
	S_CDPlay(gameflow.stats_track,0);

	TempVideoAdjust(hires_flag, 1.0);
	FadeToPal(30, game_palette);
	T_InitPrint();

	S_CopyScreenToBuffer();

	while (input & IN_SELECT)
		S_UpdateInput();

	for ( ;; )
	{
		S_InitialisePolyList(SIPL_DONT_CLEAR_SCREEN);	// bgnd clears it
		S_CopyBufferToScreen();

		S_UpdateInput();

		if (reset_flag) input = IN_SELECT;
		inputDB = GetDebouncedInput(input);
		ShowStatsText(string, 0);

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

		if ( input&IN_SELECT )
			break;
	}

//	if (level_number != (gameflow.num_levels-gameflow.num_demos-1))
//	{
		CreateStartInfo(level_number+1);
		savegame.current_level = level_number+1;
//	}
//	else
//	{
//		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);
//		savegame.current_level = LV_FIRSTLEVEL;
//	}
	savegame.start[CurrentLevel].available = 0;

/*	return_val = Display_Inventory(INV_SAVE_MODE);
	if ( return_val )
	{
		// Save game in slot 
		if (Inventory_ExtraData[0] == 1)
		{
			CreateSaveGameInfo();
			S_SaveGame(&savegame, sizeof(SAVEGAME_INFO), Inventory_ExtraData[1]);
			S_SaveSettings();
		}
	}
*/
	S_FadeToBlack();
	TempVideoRemove();
	return(0);
}

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

	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;


	T_InitPrint();

	while (input & IN_SELECT)
		S_UpdateInput();

	for ( ;; )
	{
		S_InitialisePolyList(SIPL_DONT_CLEAR_SCREEN);
		S_CopyBufferToScreen();

		S_UpdateInput();

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

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

		if ( input&IN_SELECT )
			break;
	}

	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);
	savegame.current_level = LV_FIRSTLEVEL;

	S_DontDisplayPicture();

	return(0);
}


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

/******************************************************************************
 *				Pauls Most Excellent Random routine....
 *****************************************************************************/
static	sint32	rand_1 = 0xd371f947;

sint32	GetRandomControl( void )
{
	rand_1 = rand_1 * 0x41c64e6d + 0x3039;
	return( ( rand_1 >> 10 )&0x7fff );
}

/*******************************************************************************
 *					Seed Random Number routine....
 ******************************************************************************/
void	SeedRandomControl( sint32 seed )
{
	rand_1 = seed;
}

/*******************************************************************************
 *				Get Random number for Draw Routines
 *		  This is seperate from GetRandomControl due to Demo Playback
 ******************************************************************************/
static	sint32	rand_2 = 0xd371f947;

sint32	GetRandomDraw( void )
{
	rand_2 = rand_2 * 0x41c64e6d + 0x3039;
	return( ( rand_2 >> 10 )&0x7fff );
}

/*******************************************************************************
 *			Seed Random Number routine....
 ******************************************************************************/
void	SeedRandomDraw( sint32 seed )
{
	rand_2 = seed;
}

/*
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);
}

int	NextValidLevel(sint16 level_number)
{
	int		n;
	sint16 *valids;

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

void GetValidLevelsList(REQUEST_INFO *req)
{
	int i;

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


#ifdef DONT_NEED_THIS
void GetAvailableLevels(void)
{
	/* Search the data directory for wad files, and add them to a list */
	int i;

	HANDLE dir;
	WIN32_FIND_DATA found;

	char* szSpec;


	/* Clear validity of levels */
	for (i=LV_FIRSTLEVEL; i<MAXIMUM_LEVELS; i++)
	{
		lstrcpy(GF_Level_Names[i], "");
		valid_levels[i] = 0;
	}
/*******   Find all .TR2 (Playable) Files ****************/
	szSpec="DATA\\*.TR2";
#ifdef CD_LOAD
	szSpec=GetFullPath(szSpec);
#endif
	dir = FindFirstFile(szSpec, &found);
	if (dir == INVALID_HANDLE_VALUE)
		return;

	i=LV_FIRSTLEVEL;
	do
	{
		if (lstrcmpi(found.cFileName, "TITLE.TR2") != 0 && lstrcmpi(found.cFileName, "ASSAULT.TR2") != 0)
		{
			level_types[i] = LVT_PLAYABLE;
			valid_levels[i] = i;
			lstrcpy(GF_Level_Names[i++], found.cFileName);
		}

		if (!FindNextFile(dir, &found))
			break;
	}
	while (i<=MAXIMUM_LEVELS);

	FindClose(dir);
/*******   Find all .CUT (Cutscene) Files ****************/
	szSpec="DATA\\*.CUT";
#ifdef CD_LOAD
	szSpec=GetFullPath(szSpec);
#endif
	dir = FindFirstFile(szSpec, &found);
	if (dir == INVALID_HANDLE_VALUE)
		return;
	do
	{
		level_types[i] = LVT_CUTSCENE;
		valid_levels[i] = i;
		lstrcpy(GF_Level_Names[i++], found.cFileName);

		if (!FindNextFile(dir, &found))
			break;
	}
	while (i<=MAXIMUM_LEVELS);

	FindClose(dir);
/*******   Find all .DEM? (Rolling Demo) Files ****************/
	szSpec="DATA\\*.ROL";
#ifdef CD_LOAD
	szSpec=GetFullPath(szSpec);
#endif
	dir = FindFirstFile(szSpec, &found);
	if (dir == INVALID_HANDLE_VALUE)
		return;
	do
	{
		level_types[i] = LVT_ROLLINGDEMO;
		valid_levels[i] = i;
		lstrcpy(GF_Level_Names[i++], found.cFileName);

		if (!FindNextFile(dir, &found))
			break;
	}
	while (i<=MAXIMUM_LEVELS);

	FindClose(dir);
	gameflow.num_levels = i-1;

}
#endif


void GetSavedGamesList(REQUEST_INFO *req)
{
	SetPCRequesterSize(req,10,-32);
/*	if (G_RenderInfo.nHeight>=400)
	{
		req->ypos = -90;
		req->vis_lines = 10;
	}
	else
	{
		req->ypos = -32;
		req->vis_lines = 5;
	}
*/
	if (req->selected >= req->vis_lines)
		req->line_offset = req->selected-req->vis_lines+1;

	memcpy(RequesterFlags1, SaveGameReqFlags1, MAXIMUM_LEVELS*sizeof(uint32));
	memcpy(RequesterFlags2, SaveGameReqFlags2, MAXIMUM_LEVELS*sizeof(uint32));

}


#define NUMBER_CREDITS 10

void DisplayCredits(void)
{
/*
	int i;
	char filename[64] = "data\\credit0?.pcx";
	uint32 size[NUMBER_CREDITS], length;
	uint8 *packed[NUMBER_CREDITS], *unpacked;
	uint8 cache_palette[256*3];
	HANDLE file;

	S_FadeToBlack();

	S_UnloadLevelFile();	// just before InitialiseLevel - I don't think it's needed.

	if (!InitialiseLevel(0,IL_TITLE))
		return;

	GtDisableFullScreenWindowedToggle=true;

	memcpy(cache_palette, game_palette, 256*3);

	memset(game_palette,0,768);
	FadeToPal(0,game_palette);

	// preload all the pictures into memory so CD track can play uninterrupted
	for (i=1; i<NUMBER_CREDITS; i++)
	{
		filename[12] = '0' + i;
#ifdef CD_LOAD
		file = CreateFile(GetFullPath(filename), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
#else
		file = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
#endif
		if (file != INVALID_HANDLE_VALUE)
		{
			size[i] = GetFileSize(file, 0);
			packed[i] = (uint8*)game_malloc(size[i], LOAD_PICCY_BUFFER);
			ReadFile(file, packed[i], 640*480, &length, NULL);
			CloseHandle(file);
		}
	}
	unpacked = (uint8*)game_malloc(640*480, LOAD_PICCY_BUFFER);

	// start CD track
	S_CDPlay(52, 0);

	// display pictures
	for (i=1; i<NUMBER_CREDITS; i++)
	{
		DecompPCX(packed[i], size[i], unpacked, GabPicturePalette);

		if (G_AppSettings.nRenderMode==RENDERER_INTERNAL)
			DD_CopyBitmapToSurface(G_PictureBuffer, unpacked);
		else
			BGND_Make640x480(unpacked, GabPicturePalette);
		
//		memcpy(game_palette,GabPicturePalette,768);
		SWR_Make236Palette(GabPicturePalette,unpacked,640*480,game_palette);

//		FadeToPal(30, game_palette);
		S_InitialisePolyList(SIPL_DONT_CLEAR_SCREEN);
		S_CopyBufferToScreen();
		S_OutputPolyList();
		S_DumpScreen();
		FadeToPal(30, game_palette);

		S_Wait(30*15, false); // lock out key override

//		if (i!=NUMBER_CREDITS-1)
//		{
			S_FadeToBlack();
			S_DontDisplayPicture();
//		}
		if (GtWindowClosed)
			break;
	}

	memcpy(game_palette, cache_palette, 256*3);
//	memcpy(GabPicturePalette, cache_palette, 256*3);
	S_Wait(300,false);
	FadeToPal(30, game_palette);

	GtDisableFullScreenWindowedToggle=false;
*/
}


int S_FrontEndCheck(void *data, int size)
{
	int i;
	REQUEST_INFO *req;
	int count;
	HANDLE file;
	char filename[80], count_str[16];
	DWORD read;

	req = &Load_Game_Requester;

	/* Get list of savegames on the disk */
	Init_Requester(req);             // Initialise Requester

	SavedGames = 0;
	for (i=0; i<16; i++)
	{
		wsprintf(filename, "savegame.%d", i);

		file = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		if (file != INVALID_HANDLE_VALUE)
		{
			/* Read in name */
			ReadFile(file, filename, 75, &read, NULL);
			ReadFile(file, &count, sizeof(sint32), &read, NULL);
			CloseHandle(file);

			wsprintf( count_str, "%d", count);
			AddRequesterItem(req, filename ,R_LEFTALIGN, count_str ,R_RIGHTALIGN);
			if (count > save_counter)
			{
				save_counter = count;
				req->selected = i;
			}

			saved_levels[i] = 1;
			SavedGames++;
		}
		else
		{
//			wsprintf( count_str, "%d", i+1);

			
			
			
			
			
			
			
			
			AddRequesterItem(req, GF_PCStrings[PCSTR_SAVESLOT] ,R_CENTRE, 0,0);
			saved_levels[i] = 0;
		}
	}
	save_counter++;

	memcpy(SaveGameReqFlags1, RequesterFlags1, MAXIMUM_LEVELS*sizeof(uint32));
	memcpy(SaveGameReqFlags2, RequesterFlags2, MAXIMUM_LEVELS*sizeof(uint32));

#ifdef GET_AVAILABLE_LEVELS
#ifdef PLAY_ANY_LEVEL
	GetAvailableLevels();
#endif
#endif

	return 1;
}


int S_SaveGame(void *data, int size, int slot)
{
	HANDLE file;
	char filename[80],count_str[16];
	DWORD write;

	wsprintf(filename, "savegame.%d", slot);

	file = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (file != INVALID_HANDLE_VALUE)
	{
		wsprintf(filename, "%s", GF_Level_Names[savegame.current_level]);
		WriteFile(file, filename, 75, &write, NULL);
		WriteFile(file, &save_counter, sizeof(sint32), &write, NULL);
		WriteFile(file, data, size, &write, NULL);
		CloseHandle(file);
		
		wsprintf(count_str, "%d", save_counter);
		ChangeRequesterItem(&Load_Game_Requester, slot, filename ,R_LEFTALIGN, count_str ,R_RIGHTALIGN);
		saved_levels[slot] = 1;
		save_counter++;
		SavedGames++;

		return (1);
	}

	return (0);
}


int S_LoadGame(void *data, int size, int slot)
{
	HANDLE file;
	char filename[80];
	sint32 count;
	DWORD read;

	wsprintf(filename, "savegame.%d", slot);

	file = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (file != INVALID_HANDLE_VALUE)
	{
		// skip savegame name
		ReadFile(file, filename, 75, &read, NULL);
		ReadFile(file, &count, sizeof(sint32), &read, NULL);

		ReadFile(file, data, size, &read, NULL);
		CloseHandle(file);

		return (1);
	}
  
	return (0);
}


