/*---------------------------------------------------------------------------
 *	Import Headers
\*--------------------------------------------------------------------------*/

#include <sys\types.h>
#include <libgte.h>
#include <libetc.h>
#include <stdio.h>
#include "typedefs.h"
#include "types.h"
#include "gpu.h"
#include "cd.h"
#include "malloc.h"
#include "file.h"
#include "picture.h"
#include "specific.h"
#include "spusound.h"
#include "load_lev.h"
#include "..\game\objects.h"
#include "..\game\items.h"
#include "..\game\room.h"
#include "..\game\anim.h"
#include "..\game\camera.h"
#include "..\game\sound.h"
#include "..\game\box.h"
#include "..\game\demo.h"
#include "..\game\cinema.h"
#include "..\game\gameflow.h"
#include "..\game\control.h"
#include "..\game\setup.h"
#include "..\game\footprnt.h"
#include "..\game\title.h"

extern void init_water_table();
extern void init_square_root();

extern sint16 *aranges;
extern long wibble;

/*---------------------------------------------------------------------------
 *	Constants
\*--------------------------------------------------------------------------*/

#define LOG
#define LOAD_INFO
#define PRINT_MALLOC_INFO

#define NUM_TPAGES	18
#define NUM_CLUTS	2048

/*---------------------------------------------------------------------------
 *	Type Definitions
\*--------------------------------------------------------------------------*/

typedef struct {
	WORD ObjectNum;
	WORD RoomNum;
	LONG XPos;
	LONG YPos;
	LONG ZPos;
	WORD YRot;
	WORD Shade;
	WORD ShadeB;
	WORD Flags;
}FILE_ITEM;

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


uint32 *VehiclePtr;
uint32 *WeatherPtr;
uint32 *Effect1Ptr;
uint32 *Effect2Ptr;
uint32 *Effect3Ptr;
uint32 *Baddie1Ptr;
uint32 *Baddie2Ptr;
uint32 *Baddie3Ptr;
uint32 *Baddie4Ptr;
uint32 *Baddie5Ptr;
uint32 *Baddie6Ptr;
uint32 *Baddie7Ptr;
uint32 *Baddie8Ptr;

static uint32 **ModulePtr[] = {
	&VehiclePtr,
	&WeatherPtr,
	&Effect1Ptr,
	&Effect2Ptr,
	&Effect3Ptr,
	&Baddie1Ptr,
	&Baddie2Ptr,
	&Baddie3Ptr,
	&Baddie4Ptr,
	&Baddie5Ptr,
	&Baddie6Ptr,
	&Baddie7Ptr,
	&Baddie8Ptr
};

UWORD ClutStartY;
SVECTOR *RoomBBoxes;
MMTEXTURE *RoomTextInfo;

sint16* mesh_base;
sint16* floor_data;
sint32 demosize;
uint32 horizon_colour;

#ifdef LOAD_KANJI
sint16 kanji_clutnum;
sint16 kanji_clut_table[32];
sint16 kanji_tpages[20];
#endif

sint16 *cine;
sint16 cine_frame;
sint16 num_cine_frames;
PHD_3DPOS cinematic_pos;

/*---------------------------------------------------------------------------
 *	Locals
\*--------------------------------------------------------------------------*/

static int LtShiftTitleStuff;

static uint16 LnTPX[19] = {
	0x000, 0x040, 0x080, 0x0c0, 0x100, 0x140, 0x180,
	0x000, 0x040, 0x080, 0x0c0, 0x100, 0x140, 0x180, 0x1c0,
	0x000, 0x000, 0x000, 0x000
};

static uint16 LnTPY[19] = {
	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
	0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100,
	0x000,0x000,0x000,0x000,0x000
};

static long LevelHorizonColours[] = {
	0x28402828, 0x28D8C397, 0x28D8C397, 0x28D8C397, 0x28D8C397, 0x28A86758, 0x28685828,
	0x28AC9484, 0x28000000, 0x28000000, 0x28000000, 0x28000000, 0x28000000, 0x28644733,
	0x28476FC3, 0x28476FC3, 0x2877574E, 0x28000000, 0x28000000, 0x28441806, 0x28000000,
	0x28D8C397, 0x28000000, 0x28644733
};

/*---------------------------------------------------------------------------
 *	Macros
\*--------------------------------------------------------------------------*/

#ifdef LOG
#define Log_(format,args...) DebugOut(format "\n" , ## args)
#else
#define Log_(args...)
#endif

#define jprintf(format,args...)	{ printf(format,## args); VSync(3); }

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


static void LoadSamples(int file)
{
	int nVBBLen;
	char* pBody;
	int nSamples;
	uint32* padwOffset;

	GtSFXEnabled = FALSE;

	FILE_Read(&nSamples,sizeof(int),1,file);

	if (nSamples == 0)
		return;

	padwOffset = (uint32*)game_malloc(nSamples*sizeof(uint32), SOUND_FX);

	FILE_Read(padwOffset, sizeof(uint32), nSamples, file);

	FILE_Read((char*)&nVBBLen, sizeof(nVBBLen), 1, file);

	pBody = game_malloc(nVBBLen, SOUND_FX);

	FILE_Read(pBody, nVBBLen, 1, file);

	GtSFXEnabled = SPU_LoadSamples(nSamples, padwOffset, pBody, nVBBLen);

	game_free(nSamples*sizeof(uint32), SOUND_FX);
	game_free(nVBBLen, SOUND_FX);
}

/****************************************************************************
 *						Load Room
 ***************************************************************************/
static int LoadLevelData( char *filename )
{
	FILE_ITEM *fi;
	long	*lptr,temp1;

	int file;
	int					i,j,sizer;
	int					num_anims,nFreeVRamX;
	sint32			 	x, num_tpages,num_cluts,nClutLines,nCLA,nCLU,nCLT;
	sint16				ndoors;
	char				*buffer;
	PSXTEXTI		 	*iptr;
	PSXSPRITESTRUCT		*sptr;
	ANIM_STRUCT			*animptr;
	ITEM_INFO 			*item;
	ROOM_INFO           *r;
	OBJECT_INFO			*obj;
//	BOX_INFO			*box;
	RECT				rc;

#ifdef LOAD_KANJI
	int kanjifile;
#endif

#ifdef LOAD_INFO
	printf("        Loading '%s'...\n", filename);
#endif
#ifdef PRINT_MALLOC_INFO
	printf("Allocating memory...\n");
#endif

#ifdef CD_LOAD
//	GPU_UsePolygonBuffers(GadwPolygonBuffers+0x10000,PBSIZE-0x8000);		// nick some space from the poly buffers
	GPU_UsePolygonBuffers(&GadwPolygonBuffers[0x9000],128*13);			// nick some space from the poly buffers
	CDFS_UseSectorBuffer(GadwPolygonBuffers,0x10000*2);						// give it to the CDFS sector buffer
	VSync(0);
	GPU_FlipNow();															// make sure no more polys are added to old poly buffer
	DrawSync(0);
#endif

	SeedRandomDraw(RANDOM_SEED);
	SeedRandomControl(RANDOM_SEED);
	wibble = 0;

	init_water_table();
	init_square_root();

	file = FILE_Open(filename);                                               // Open Wad File

/* -------- validate version ID */

	FILE_Read((char *)&i, sizeof(long), 1, file);

#if defined(GAMEDEBUG) || defined(EZORAY)

//	if (i != -OBJECT_VERSION)
//	{
//		printf("Wrong Version Number!!!\n");
//		printf("Game Ver: %d  Level Ver: %d\n", OBJECT_VERSION, i);
//		exit(0);
//	}

#endif

	LoadSamples(file);                                                      // Load the Sound shit

/* -------- read code modules */

	for ( i=0 ; i<13 ; i++ )
	{
		FILE_Read((char *)&sizer, sizeof(LONG), 1, file);

		if (sizer)
		{
			uint32 *ptr;
			uint32 *reloc;

			ptr = (uint32*)game_malloc(sizer, 0);
			FILE_Read((char *)ptr, sizeof(char), sizer, file);

			FILE_Read((char *)&sizer, sizeof(LONG), 1, file);
			reloc = (uint32*)game_malloc(sizer, 0);
			FILE_Read((char *)reloc, sizeof(char), sizer, file);

			RelocateModule((uint32)ptr, reloc);

			game_free(sizer, 0);

			*ModulePtr[i] = ptr;
		}
		else
			*ModulePtr[i] = NULL;
	}

/* -------- read rooms */

	Log_("->Rooms\n");

	FILE_Read((char *)&number_rooms, sizeof(number_rooms), 1, file);

#if defined(GAMEDEBUG) || defined(EZORAY)

	if (number_rooms > MAX_ROOMS)
	{
		printf("Maximum Number Rooms reached!!\n");
		exit(0);
	}

#endif

	r = room = (ROOM_INFO *)game_malloc(number_rooms * sizeof(ROOM_INFO), ROOM_INFOS);

	for ( i=0 ; i<number_rooms ; i++,r++ )
	{
		FILE_Read( (char *)&r->x,sizeof(room[0].x),1,file );			// Read Position Of Room
		FILE_Read( (char *)&r->z,sizeof(room[0].z),1,file );

		FILE_Read( (char *)&r->minfloor,sizeof(room[0].minfloor),1,file );
		FILE_Read( (char *)&r->maxceiling,sizeof(room[0].maxceiling),1,file );

		r->y = r->maxceiling;

	/* -------- read room meshes */

		FILE_Read((char *)&sizer, sizeof(sizer), 1, file);

		r->data = (sint16 *)game_malloc(sizer * sizeof(sint16),ROOM_MESH);

		FILE_Read((char *)r->data, sizeof(sint16), sizer, file);

		lptr = (long *) r->data;
		lptr++;

		for ( j=0 ; j<16 ; j++ )
		{
			temp1 = *lptr;
			temp1 += ((long) r->data);
			*lptr++ = temp1;
		}

	/* -------- read doors */

		FILE_Read((char *)&ndoors, sizeof(sint16), 1, file);

		if (ndoors)
		{
			r->door = (sint16 *)game_malloc((ndoors*16+1) * sizeof(sint16), ROOM_DOOR);

			r->door[0] = ndoors;

			FILE_Read( (char *)&r->door[1], sizeof(sint16), ndoors*16, file);
		}
		else
			r->door = NULL;

	/* -------- read collision map */

		FILE_Read((char *)&r->x_size, sizeof(room[0].x_size), 1, file);
		FILE_Read((char *)&r->y_size, sizeof(room[0].y_size), 1, file);

		sizer = (int)r->x_size*r->y_size;

		r->floor = (FLOOR_INFO *)game_malloc(sizer * sizeof(FLOOR_INFO), ROOM_FLOOR);

		FILE_Read((char *)r->floor, sizeof(FLOOR_INFO), sizer, file);

	/* -------- read lights */

		FILE_Read((char *)&r->ambient, sizeof(room[0].ambient), 2, file);

		FILE_Read((char *)&r->num_lights, sizeof(room[0].num_lights), 1, file);

		if (r->num_lights)
		{
			r->light = (LIGHT_INFO *)game_malloc(r->num_lights * sizeof(LIGHT_INFO), ROOM_LIGHTS);

			FILE_Read((char *)r->light, sizeof(LIGHT_INFO), r->num_lights, file);
		}
		else
			r->light=NULL;

	/* -------- read static meshes */

		FILE_Read((char *)&r->num_meshes, sizeof(room[0].num_meshes), 1, file);

		if (r->num_meshes)
		{
			r->mesh = (MESH_INFO *)game_malloc(r->num_meshes * sizeof(MESH_INFO), ROOM_STATIC_MESH_INFOS);

			FILE_Read((char *)r->mesh, sizeof(MESH_INFO), r->num_meshes, file);
		}
		else
			r->mesh=NULL;

	/* -------- read flags */

		FILE_Read((char *)&r->flipped_room, sizeof(sint16), 1, file);
		FILE_Read((char *)&r->flags, sizeof(uint16), 1, file);
		FILE_Read((char *)&r->MeshEffect, sizeof(char), 1, file);
		FILE_Read((char *)&r->ReverbType, sizeof(uint16), 1, file);

		r->bound_active = 0;
		r->left = phd_winxmax;
		r->top = phd_winymax;
		r->right = r->bottom = 0;
		r->item_number = NO_ITEM;
		r->fx_number = NO_ITEM;

	}

//	BuildOutsideTable();
	InitFootPrints();

/* -------- read floor wad */

	FILE_Read((char *)&sizer, sizeof(sizer), 1, file);

	floor_data = (sint16 *)game_malloc(sizer * sizeof(sint16), FLOOR_DATA);

	FILE_Read((char *)floor_data, sizeof(sint16), sizer, file);

/* -------- read outside tables */

	FILE_Read((char *)&OutsideRoomOffsets, sizeof(short), 27*27, file);

	FILE_Read((char *)&sizer, sizeof(long), 1, file);

	if (sizer)
	{
		OutsideRoomTable = (char *)game_malloc(sizer, 0);
		FILE_Read((char *)OutsideRoomTable, sizeof(char), sizer, file);
	}

/* -------- read room mesh bounding boxes*/

	FILE_Read((char *)&sizer, sizeof(long), 1, file);

	RoomBBoxes = (SVECTOR *)game_malloc(sizeof(SVECTOR)*sizer, ROOM_FLOOR);
	FILE_Read((char *)RoomBBoxes, sizeof(SVECTOR), sizer, file);

/* -------- read objects */

	Log_("->Objects\n");

	FILE_Read( (char *)&sizer, sizeof(sizer),1,file );         			// Get size of Mesh Page
#ifdef PRINT_MALLOC_INFO
	printf("          mesh_base: %d\n",sizer*sizeof(sint16));
#endif
	mesh_base = (sint16 *)game_malloc( sizer * sizeof(sint16),MESHES );		// Malloc IT
	FILE_Read( (char *)mesh_base, sizeof(sint16),sizer,file );          // Read It in

	FILE_Read( (char *)&sizer, sizeof(sizer),1,file );       			// Read Number Meshes
#ifdef PRINT_MALLOC_INFO
	printf("             meshes: %d\n",sizer*sizeof(sint16*));
#endif
	meshes = (sint16 **)game_malloc( sizer*sizeof(sint16 *),MESH_POINTERS );          // read Offsets
	FILE_Read( (char *)meshes, sizeof(sint16 *),sizer,file );
	for ( i=0;i<sizer;i++ )
		meshes[i] = mesh_base + (int)meshes[i]/2;						// Make Into Pointers..


	FILE_Read( (char *)&num_anims, sizeof(sizer),1,file );				// Read in ANIM_STRUCTS
#ifdef PRINT_MALLOC_INFO
	printf("              anims: %d\n",num_anims*sizeof(ANIM_STRUCT));
#endif
	anims = (ANIM_STRUCT *)game_malloc( num_anims*sizeof(ANIM_STRUCT),ANIMS );
	FILE_Read( (char *)anims,sizeof(ANIM_STRUCT),num_anims,file );

	FILE_Read( (char *)&sizer, sizeof(sizer),1,file );					// Read in CHANGE_STRUCTS
#ifdef PRINT_MALLOC_INFO
	printf("            changes: %d\n",sizer*sizeof(CHANGE_STRUCT));
#endif
	changes = (CHANGE_STRUCT *)game_malloc( sizer*sizeof(CHANGE_STRUCT),STRUCTS );
	FILE_Read( (char *)changes,sizeof(CHANGE_STRUCT),sizer,file );


	FILE_Read( (char *)&sizer, sizeof(sizer),1,file );					// Read in RANGE_STRUCTS
#ifdef PRINT_MALLOC_INFO
	printf("             ranges: %d\n",sizer*sizeof(RANGE_STRUCT));
#endif
	ranges = (RANGE_STRUCT *)game_malloc( sizer*sizeof(RANGE_STRUCT),RANGES );
	FILE_Read( (char *)ranges,sizeof(RANGE_STRUCT),sizer,file );

	FILE_Read( (char *)&sizer, sizeof(sizer),1,file );					// Read in COMMANDS
#ifdef PRINT_MALLOC_INFO
	printf("           commands: %d\n",sizer*sizeof(sint16));
#endif
	commands = (sint16 *)game_malloc( sizer*sizeof(sint16),COMMANDS );
	FILE_Read( (char *)commands,sizeof(sint16),sizer,file );

	FILE_Read( (char *)&sizer, sizeof(sizer),1,file );					// Read in BONES
#ifdef PRINT_MALLOC_INFO
	printf("              bones: %d\n",sizer*sizeof(sint32));
#endif
	bones = (sint32 *)game_malloc( sizer*sizeof(sint32),BONES );
	FILE_Read( (char *)bones,sizeof(sint32),sizer,file );

	FILE_Read( (char *)&sizer, sizeof(sizer),1,file );					// Read in FRAMES
#ifdef PRINT_MALLOC_INFO
	printf("             frames: %d\n",sizer*sizeof(sint16));
#endif

	frames = (sint16 *)game_malloc( sizer*sizeof(sint16),FRAMES );
	FILE_Read( (char *)frames,sizeof(sint16),sizer,file );

	animptr = anims;                                                    // Get frame pointers for
	for ( i=0;i<num_anims;i++,animptr++ )                               // Anim Structs.
		animptr->frame_ptr = (sint16 *)((int)(animptr->frame_ptr) + (int)(frames));

	FILE_Read( (char *)&sizer, sizeof(sizer),1,file );					// Read in Normal Object Data
	for ( i=0;i<sizer;i++ )
	{
		FILE_Read( (char *)&j, sizeof(j),1,file );
		obj = &objects[j];
		obj->loaded = 1;                                          		// indicate object loaded
		FILE_Read( (char *)&obj->nmeshes,     sizeof(sint16), 1, file );
		FILE_Read( (char *)&obj->mesh_index,  sizeof(sint16), 1, file );
		FILE_Read( (char *)&obj->bone_index,  sizeof(sint32), 1, file );
		FILE_Read( (char *)&x,                sizeof(sint32), 1, file );

		obj->frame_base = (sint16 *)( (int)(frames) + (int)x );
		FILE_Read( (char *)&obj->anim_index,  sizeof(sint16), 1, file );
		FILE_Read( (char *)&j,sizeof(sint16),1,file );					// Padding!!!
	}

	InitialiseObjects();                                                // Now initialise Objects

	FILE_Read( (char *)&sizer, sizeof(sizer),1,file );					// Read in Static Object Data

	for ( i=0;i<sizer;i++ )
	{
		FILE_Read( (char *)&j, sizeof(j),1,file );
		FILE_Read( (char *)&static_objects[j].mesh_number, sizeof(sint16),1,file );
		FILE_Read( (char *)&static_objects[j].x_minp, sizeof(sint16),6,file );		// read Physical Bounds
		FILE_Read( (char *)&static_objects[j].x_minc, sizeof(sint16), 6, file );    // read Collision Bounds
		FILE_Read( (char *)&static_objects[j].flags, sizeof(sint16), 1, file );
	}

//----------------------------------- Textures And Sprites -----------------------------------------------------

#ifdef LOAD_INFO
	printf("               Textures\n");
#endif
	FILE_Read( &num_tpages, sizeof(sint32), 1, file );
#ifdef GAMEDEBUG
	printf("Number of tpages: %d\n", (int)num_tpages);
#endif
#ifdef PRINT_MALLOC_INFO
	printf("      texture_pages: %d (MAX: %d)\n",num_tpages*128*256,NUM_TPAGES*128*256);
#endif
	buffer = game_malloc( 128*256,TEXTURE_PAGES );					// Read In Texture Pages..

	nFreeVRamX=512;

	for (i=0;i<num_tpages;i++)
	{
		FILE_Read( (char *)buffer, sizeof(char), 128*256, file );

		setRECT(&rc,LnTPX[i]+nFreeVRamX,LnTPY[i],64,256);

		LOAD_DrawEnable(FALSE);
		LoadImage( &rc, (u_long *)( buffer ) );						// Down load image to Vidram
		DrawSync(0);												// Wait for Drawing to complete
		LOAD_DrawEnable(TRUE);
	}
	game_free( 128*256,TEXTURE_PAGES );


#ifdef LOAD_KANJI
	FILE_Read(&kanji_clutnum, sizeof(sint16), 1, file);
#endif


#ifdef PRINT_MALLOC_INFO
	printf("FREE  texture_pages:-%d\n",num_tpages*128*256);
	printf("              cluts: %d\n",num_cluts*16*2);
#endif

/* -------- read Cluts */

	FILE_Read(&num_cluts, sizeof(sint32), 1, file);

	buffer = game_malloc(num_cluts*16*2, CLUTS);          							// Read In Clut Pages..
	FILE_Read((char*)buffer,sizeof(uint16),num_cluts*16,file);

	nClutLines = (num_cluts+3) >> 2;
	nCLT = LtShiftTitleStuff ? 0 : 256;
	nCLA = nCLT+256-nClutLines;
	nCLU = nCLA-nClutLines;

	GdwUWClutSub=(getClut(0,nClutLines))<<16;
	ClutStartY = nCLA;

	LOAD_DrawEnable(FALSE);					// load Cluts
	setRECT(&rc, 960, nCLA, 64, nClutLines);
	LoadImage(&rc, (u_long*)buffer);
	DrawSync(0);

/* -------- read underwater Cluts */

	FILE_Read((char*)buffer, sizeof(uint16), num_cluts*16, file);

	rc.y = nCLU;							// load underwater Cluts
	LoadImage(&rc, (u_long*)buffer);
	DrawSync(0);
	LOAD_DrawEnable(TRUE);

	game_free(num_cluts*16*2, CLUTS);

//----------------------------------- Texture And Sprite Infos -----------------------------------------------------

	FILE_Read((char *)&sizer, sizeof(sizer),1,file );

	Log_("->Texture Infos : %d (%d bytes)\n", sizer, sizer*sizeof(PSXTEXTSTRUCT));

	psxtextinfo = (PSXTEXTSTRUCT *)game_malloc( sizer*sizeof(PSXTEXTSTRUCT),TEXTURE_INFOS );		// Load In Texture Infos

	FILE_Read( (char *)psxtextinfo, sizeof(PSXTEXTSTRUCT), sizer, file );
	iptr = (PSXTEXTI *)psxtextinfo;
	for ( i=0;i<sizer;i++,iptr++)
	{
		iptr->tpage = getTPage(0, 1, LnTPX[iptr->tpage]+nFreeVRamX,LnTPY[iptr->tpage]);			// Get Correct Tpage IDs
		iptr->clut  = getClut((960+((iptr->clut&3)<<4)),(nCLA+(iptr->clut>>2)));	// Get Correct Clut IDs (above water)
	}


//------------------------------------------- Sprite Infos --------------------------------------------------------
#ifdef LOAD_INFO
	printf("               Sprite infos\n");
#endif
	FILE_Read( (char *)&sizer, sizeof(sizer),1,file );
#ifdef PRINT_MALLOC_INFO
	printf("      psxspriteinfo: %d\n",sizer*sizeof(PSXSPRITESTRUCT));
#endif
	psxspriteinfo = (PSXSPRITESTRUCT *)game_malloc(sizer*sizeof(PSXSPRITESTRUCT),SPRITE_INFOS );		// Load In Sprite Infos
	FILE_Read( (char *)psxspriteinfo, sizeof(PSXSPRITESTRUCT), sizer, file );

	sptr = psxspriteinfo;

	for ( i=0 ; i<sizer ; i++,sptr++ )
	{
		sptr->tpage = getTPage(0, 1, LnTPX[sptr->tpage]+nFreeVRamX, LnTPY[sptr->tpage]);
		sptr->clut  = getClut((960+((sptr->clut&3)<<4)), (nCLA+(sptr->clut>>2)));
	}


//------------------------------------------ Sprite Data Read In -------------------------------------------------
#ifdef LOAD_INFO
	printf("               Sprite data\n");
#endif
	FILE_Read( ( char *)&sizer, sizeof(sizer),1,file );
	for ( i=0; i<sizer;i++ )
	{
		FILE_Read( (char *)&j, sizeof(j),1,file );
		if ( j<NUMBER_OBJECTS )
		{
			FILE_Read( (char *)&objects[j].nmeshes, sizeof(sint16),1,file );
			FILE_Read( (char *)&objects[j].mesh_index, sizeof(sint16),1,file );
			objects[j].loaded = 1;
		}
		else
		{
			j -= NUMBER_OBJECTS;
			FILE_Read( (char *)&x, sizeof(sint16),1,file );
			FILE_Read( (char *)&static_objects[j].mesh_number, sizeof(sint16),1,file );
		}
	}

//--------------------------------------------- Camera Data -------------------------------------------------------
#ifdef LOAD_INFO
	printf("               Camera data\n");
#endif
	FILE_Read( (char *)&j, sizeof(sint32), 1, file );
	if ( j )	// Gibby - this is the number of fixed cameras.
	{
		NumFixedCameras = j;
#ifdef PRINT_MALLOC_INFO
		printf("       camera.fixed: %d\n",sizeof(GAME_VECTOR)*j);
#endif
		camera.fixed = (OBJECT_VECTOR *)game_malloc( sizeof(GAME_VECTOR) * j,CAMERAS );
		FILE_Read( (char *)camera.fixed, sizeof(GAME_VECTOR),j,file );
	}
	else
	{
		camera.fixed = NULL;
		NumFixedCameras = 0;
	}

//-------------------------------------------- Sound Effects -----------------------------------------------------
#ifdef LOAD_INFO
	printf("               Sound effects\n");
#endif
	FILE_Read((char *)&number_sound_effects,sizeof(sint32),1,file );
	if ( number_sound_effects )
	{
#ifdef PRINT_MALLOC_INFO
		printf("      sound_effects: %d\n",sizeof(OBJECT_VECTOR)*number_sound_effects);
#endif
		sound_effects = (OBJECT_VECTOR *)game_malloc( sizeof(OBJECT_VECTOR)*number_sound_effects,SOUND_FX );
		FILE_Read( (char *)sound_effects, sizeof(OBJECT_VECTOR), number_sound_effects, file );
	}

//---------------------------------------------- Box Data --------------------------------------------------------
#ifdef LOAD_INFO
	printf("               Box data\n");
#endif
	FILE_Read( (char *)&number_boxes, sizeof(sint32), 1, file );        // Read Boxes
#ifdef PRINT_MALLOC_INFO
	printf("              boxes: %dx%d= %d\n",number_boxes, sizeof(BOX_INFO),sizeof(BOX_INFO)*number_boxes);
#endif
	boxes = (BOX_INFO *)game_malloc(sizeof(BOX_INFO) * number_boxes,BOXES );
	FILE_Read( (char *)boxes, sizeof(BOX_INFO), number_boxes, file);
/*	for(i=0, box=boxes;i<number_boxes;i++,box++)
	{
		FILE_Read(&j, sizeof(int), 1, file);
		box->left = j>>WALL_SHIFT;

		FILE_Read(&j, sizeof(int), 1, file);
		box->right = (j+1)>>WALL_SHIFT;

		FILE_Read(&j, sizeof(int), 1, file);
		box->top = j>>WALL_SHIFT;

		FILE_Read(&j, sizeof(int), 1, file);
		box->bottom = (j+1)>>WALL_SHIFT;

		FILE_Read(&box->height, sizeof(sint16), 1, file);
		FILE_Read(&box->overlap_index, sizeof(sint16), 1, file);
	}
*/
	FILE_Read( (char *)&j, sizeof(sint32), 1, file );					// Read Box overlaps
#ifdef PRINT_MALLOC_INFO
	printf("           overlaps: %d\n",sizeof(uint16)*j);
#endif
	overlap = (uint16 *)game_malloc( sizeof(uint16) * j,OVERLAPS );
	FILE_Read( (char *)overlap, sizeof(uint16), j, file );

	/* Zones (version for flipped/unflipped versions of map) */
//##	fly_zone[0] = (sint16 *)game_malloc( sizeof(sint16)*number_boxes,FLYZONE );
//##	fly_zone[1] = (sint16 *)game_malloc( sizeof(sint16)*number_boxes,FLYZONE );

	for ( i=0;i<2;i++ )
	{
		sint16 *boxtemp;

		for ( j=0;j<4;j++ )
		{
			if (j==2 || j==1)
			{
//##				FILE_Read( (char *)fly_zone[1], sizeof(sint16),number_boxes, file);
				boxtemp = (sint16 *)game_malloc( sizeof(sint16) * number_boxes, 0);
				FILE_Read((char *)boxtemp, sizeof(sint16),number_boxes, file);
				game_free(sizeof(sint16) * number_boxes, 0);
			}
			else
			{
				ground_zone[j][i] = (sint16 *)game_malloc( sizeof(sint16) * number_boxes,GROUNDZONE );
				FILE_Read( (char *)ground_zone[j][i], sizeof(sint16),number_boxes, file);
			}
		}
//##		FILE_Read( (char *)fly_zone[i], sizeof(sint16),number_boxes, file);

		boxtemp = (sint16 *)game_malloc( sizeof(sint16) * number_boxes, 0);
		FILE_Read((char *)boxtemp, sizeof(sint16),number_boxes, file);
		game_free(sizeof(sint16) * number_boxes, 0);
	}

//	TS - New code to make splitters block movement even when not attached to door/moveblock

	for ( i=0;i<number_boxes;i++ )
	{
		if (boxes[i].overlap_index & BLOCKABLE)
			boxes[i].overlap_index |= BLOCKED;
	}


//------------------------------------- Load Animated Texture Ranges ------------------------------------------------------
#ifdef LOAD_INFO
	printf("               Animated textures\n");
#endif
	FILE_Read( (char *)&j, sizeof(sint32), 1, file );                // size is always at least 1!!
#ifdef PRINT_MALLOC_INFO
	printf("            aranges: %d\n",sizeof(sint16)*j);
#endif
	aranges = (sint16 *)game_malloc( sizeof(sint16) * j,ANIMATING_TEXTURE_RANGES );

	FILE_Read( (char *)aranges, sizeof(sint16),j, file );

//---------------------------------------------- LoadItems -----------------------------------------------------------------
#ifdef LOAD_INFO
	printf("               Items\n");
#endif

	FILE_Read( (char *)&level_items, sizeof(level_items),1,file );

#ifdef GAMEDEBUG
	if ( level_items>NUMBER_ITEMS )
	{
		printf("Number Items Being Loaded > NUMBER_ITEMS\n" );
		exit(0);
	}
#endif

#ifdef PRINT_MALLOC_INFO
	printf("              items: %d  (actual: %d)\n",NUMBER_ITEMS * sizeof(ITEM_INFO), level_items);
#endif
	items = (ITEM_INFO *)game_malloc( NUMBER_ITEMS * sizeof(ITEM_INFO),ITEMS );		// Load Items...
	InitialiseItemArray( NUMBER_ITEMS );

/* -------- read all items */

	if (level_items)
	{
		fi = (FILE_ITEM *)game_malloc(sizeof(FILE_ITEM)*level_items, 0);
		FILE_Read(fi, sizeof(FILE_ITEM), level_items, file);

		for ( i=0 ; i<level_items ; i++ )
		{
			FILE_ITEM *ff = &fi[i];

			item = &items[i];

			item->object_number = ff->ObjectNum;
			item->room_number = ff->RoomNum;
			item->pos.x_pos = ff->XPos;
			item->pos.y_pos = ff->YPos;
			item->pos.z_pos = ff->ZPos;
			item->pos.y_rot = ff->YRot;
			item->shade = ff->Shade;
			item->shadeB = ff->ShadeB;
			item->flags = ff->Flags;
		}
		game_free(sizeof(FILE_ITEM)*level_items, 0);

		for ( i=0 ; i<level_items ; i++ )
			InitialiseItem(i);
	}

/* -------- fix SHADOW sprite */

	psxspriteinfo[objects[SHADOW].mesh_index].tpage =
	(psxspriteinfo[objects[SHADOW].mesh_index].tpage & (~96)) | (2<<5);

//------------------------------- Read in Horizon Colour ----------------------------------------------------------------
	FILE_Read( &horizon_colour, sizeof(uint32),1,file );

	horizon_colour = LevelHorizonColours[CurrentLevel];

/* -------- read room texture infos */

	{
		MMTEXTURE *mptr;

		FILE_Read((char *)&sizer, sizeof(long), 1, file);

		RoomTextInfo = (MMTEXTURE *)game_malloc(sizeof(MMTEXTURE) * sizer, ROOM_FLOOR);
		FILE_Read((char *)RoomTextInfo, sizeof(MMTEXTURE), sizer, file);

		mptr = RoomTextInfo;

		for ( i=0;i<sizer;i++,mptr++)
		{
			mptr->t[0].tpage = getTPage(0,1,LnTPX[mptr->t[0].tpage]+nFreeVRamX,LnTPY[mptr->t[0].tpage]);			// Get Correct Tpage IDs
			mptr->t[1].tpage = getTPage(0,1,LnTPX[mptr->t[1].tpage]+nFreeVRamX,LnTPY[mptr->t[1].tpage]);			// Get Correct Tpage IDs
			mptr->t[2].tpage = getTPage(0,1,LnTPX[mptr->t[2].tpage]+nFreeVRamX,LnTPY[mptr->t[2].tpage]);			// Get Correct Tpage IDs

			mptr->t[0].clut  = getClut((960+((mptr->t[0].clut&3)<<4)),(nCLA+(mptr->t[0].clut>>2)));	// Get Correct Clut IDs (above water)
			mptr->t[1].clut  = getClut((960+((mptr->t[1].clut&3)<<4)),(nCLA+(mptr->t[1].clut>>2)));	// Get Correct Clut IDs (above water)
			mptr->t[2].clut  = getClut((960+((mptr->t[2].clut&3)<<4)),(nCLA+(mptr->t[2].clut>>2)));	// Get Correct Clut IDs (above water)
		}
	}

//------------------------------- Read in SoundSample stuff ----------------------------------------------------------------
#ifdef LOAD_INFO
	printf("               Sound samples\n");
#endif
	FILE_Read( (char *)sample_lut, sizeof(sint16),MAX_SAMPLES,file );					// Read in Sample number remaps
	FILE_Read( (char *)&num_sample_infos, sizeof(int),1,file );                         // Read in sample infos
#ifdef PRINT_MALLOC_INFO
	printf("       sample_infos: %dx%d= %d\n",num_sample_infos, sizeof(SAMPLE_INFO),num_sample_infos * sizeof(SAMPLE_INFO));
#endif
	sample_infos = (SAMPLE_INFO *)game_malloc( num_sample_infos*sizeof(SAMPLE_INFO), SAMPLEINFOS );
	FILE_Read( (char *)sample_infos, sizeof(SAMPLE_INFO),num_sample_infos,file );
	FILE_Read( (char *)&num_samples, sizeof(int),1,file );

//------------------------------------ Cinematic Data ----------------------------------------------------------------------
#ifdef LOAD_INFO
	printf("               Cinematic data\n");
#endif
	FILE_Read( (char *)&num_cine_frames, sizeof(sint16),1,file );
	if ( num_cine_frames )
	{
#ifdef PRINT_MALLOC_INFO
		printf("               cine: %d\n",8*sizeof(sint16)*num_cine_frames);
#endif
		cine = (sint16 *)game_malloc( (int)(8*sizeof(sint16)*num_cine_frames),CINEMATIC_FRAMES );
		FILE_Read( (char *)cine, sizeof(sint16)*8, (int)num_cine_frames,file );
	}
//------------------------------------ Demo Data ----------------------------------------------------------------------
#ifdef LOAD_INFO
	printf("               Demo data\n");
#endif

	FILE_Read( (char*)&demosize, sizeof(sint32),1,file );
	if ( demosize )
	{
#ifdef GAMEDEBUG
		printf("            demosize: %d\n",(int)demosize);
#endif
		demoptr = (uint32 *)game_malloc(demosize, LOADDEMO_BUFFER);
		FILE_Read( (char*)demoptr, sizeof(uint8), demosize, file );
		democount = 0;
		demo_loaded = 1;
	}
	else
		demo_loaded = 0;


//---------------------------- End Of Room Loading ---------------------------
	FILE_Close(file);


#ifdef LOAD_KANJI
//	printf("Opening 'DATA\\KANJI.PSX'\n");
	kanjifile = FILE_Open("DATA\\KANJI.PSX");
	if (kanjifile<=0)
		printf("Could not open 'DATA\\KANJI.PSX'\n");

//	printf("Reading font texture size...");
	FILE_Read(&sizer, 1, sizeof(int), kanjifile);
//	printf("%d bytes\n", sizer);
	if (sizer)
	{
		buffer = game_malloc( sizer,TEXTURE_PAGES );
		FILE_Read(buffer,sizeof(char), sizer, kanjifile);
		FILE_Close(kanjifile);

	// NOW DOWNLOAD THE 2 KANJI FONT STRIPS INTO THE 16 LINES BELOW EACH DRAW BUFFER
		for (i=0;i<6;i++)
		{
			setRECT(&rc,i*64,240,64,16);
			LOAD_DrawEnable(FALSE);
			LoadImage( &rc, (u_long *)( buffer+(128*16*i)) );						// Down load image to Vidram
			DrawSync(0);												// Wait for Drawing to complete
			LOAD_DrawEnable(TRUE);
		}

		for (i=0;i<6;i++)
		{
			setRECT(&rc,i*64,496,64,16);
			LOAD_DrawEnable(FALSE);
			LoadImage( &rc, (u_long *)( buffer + (128*16*(i+6)) ) );						// Down load image to Vidram
			DrawSync(0);												// Wait for Drawing to complete
			LOAD_DrawEnable(TRUE);
		}

		for (i=0;i<8;i++)
		{
			setRECT(&rc,896,384+i*16,64,16);
			LOAD_DrawEnable(FALSE);
			LoadImage( &rc, (u_long *)( buffer + (128*16*(i+12)) ) );						// Down load image to Vidram
			DrawSync(0);												// Wait for Drawing to complete
			LOAD_DrawEnable(TRUE);
		}
		kanji_tpages[0] = getTPage(0,0,  0,240);
		kanji_tpages[1] = getTPage(0,0, 64,240);
		kanji_tpages[2] = getTPage(0,0,128,240);
		kanji_tpages[3] = getTPage(0,0,192,240);
		kanji_tpages[4] = getTPage(0,0,256,240);
		kanji_tpages[5] = getTPage(0,0,320,240);
		kanji_tpages[6] = getTPage(0,0,  0,496);
		kanji_tpages[7] = getTPage(0,0, 64,496);
		kanji_tpages[8] = getTPage(0,0,128,496);
		kanji_tpages[9] = getTPage(0,0,192,496);
		kanji_tpages[10]= getTPage(0,0,256,496);
		kanji_tpages[11]= getTPage(0,0,320,496);
		kanji_tpages[12]= getTPage(0,0,896,384);
		kanji_tpages[13]= getTPage(0,0,896,400);
		kanji_tpages[14]= getTPage(0,0,896,416);
		kanji_tpages[15]= getTPage(0,0,896,432);
		kanji_tpages[16]= getTPage(0,0,896,448);
		kanji_tpages[17]= getTPage(0,0,896,464);
		kanji_tpages[18]= getTPage(0,0,896,480);
		kanji_tpages[19]= getTPage(0,0,896,496);
		game_free( sizer, TEXTURE_PAGES );
	}
#endif

#ifdef CD_LOAD
	CDFS_UseSectorBuffer(0, 0);						// revert to CDFS's internal sector buffer
	GPU_UsePolygonBuffers(GadwPolygonBuffers,PBSIZE);		// grab back all of the polygon buffer for GPU
	S_CDStop();
#endif

#ifdef GAMEDEBUG
	printf("Level Loaded\n\n");
#endif

	return(1);
}

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

/*****************************************************************************
 *				Load And Process Room Data....
 ****************************************************************************/
int S_LoadLevelFile( char *fname, int level_number, int type)
{
	u_int	level_size;
	int nRetVal;

#ifdef GAMEDEBUG
	printf("S_LoadLevelFile( '%s', %d )\n", fname, level_number );
#endif

	LtShiftTitleStuff = ((type==IL_TITLE) || (type==IL_QUIET));

	init_game_malloc();									// Reset Malloc Tables

	level_size = FILE_Length(fname);
#ifdef GAMEDEBUG
	printf("level size = %d bytes\n", level_size);
#endif

	if (type==IL_TITLE)
#if defined(JAPAN)
		LOAD_Start(GF_titlefilenames[GFT_TITLEPIC_JAP],level_size);
#elif defined(NTSC)
		LOAD_Start(GF_titlefilenames[GFT_TITLEPIC_US],level_size);
#else
		LOAD_Start(GF_titlefilenames[GFT_TITLEPIC],level_size);
#endif
	else if (type!=IL_QUIET && (type!=IL_CUTSCENE || GF_Playing_Story))
		LOAD_Start((GF_LoadingPic>=0)?GF_picfilenames[GF_LoadingPic]:0,level_size);

	else
		LOAD_Start(NULL, level_size);


	nRetVal=LoadLevelData( fname );

//##	if (type!=IL_QUIET && (type!=IL_CUTSCENE || GF_Playing_Story))
		LOAD_Stop();
	if (type==IL_TITLE)
#if defined(JAPAN)
		S_DisplayPicture(GF_titlefilenames[GFT_TITLEPIC_JAP]);
#elif defined(NTSC)
		S_DisplayPicture(GF_titlefilenames[GFT_TITLEPIC_US]);
#else
		S_DisplayPicture(GF_titlefilenames[GFT_TITLEPIC]);
#endif

	return nRetVal;
}


/******************************************************************************
 ******************************************************************************
 *			GameFlow Load Stuff						J.Gosling 1997
 ******************************************************************************
 *****************************************************************************/

//#define SCRIPT_INFO

#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)

char *seqcom_names[]={
	"PICTURE:",
	"LIST START >>>",
	"LIST END <<<<<",
	"FMV:",
	"STARTLEVEL:",
	"CUTSCENE:",
	"LEVCOMPLETE",
	"DEMOPLAY:",
	"JUMPTO_SEQ:",
	"END SEQUENCE",
	"SET CD TRACK:",
	"SUNSET ON",
	"LOADING PIC",		//PSX only
	"DEADLY WATER",
	"REMOVE WEAPONS",
	"GAME COMPLETE",
	"CUT ANGLE",
	"NO FLOOR"
};

#endif


sint16 LGF_offsets[200];

int	Read_Strings( int num_strings, char **strings, char **buffer, int file)
{
	int	i;
	sint16 size;
	char *strptr;

#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
	jprintf("GF:		Num strings=%d\n", num_strings);
#endif
	FILE_Read(LGF_offsets, sizeof(sint16), num_strings, file);

	FILE_Read( &size, sizeof(sint16), 1, file);

	*buffer = (char*) game_malloc(size, SCRIPT_DATA);
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
	jprintf("GF:		String buffer size=%d\n", size);
#endif
	if (!buffer)
	{
 		jprintf("GF:	Could not allocate memory for strings (%d bytes)\n", size);
		return (0);
	}
	FILE_Read(*buffer, sizeof(char), size, file );
	if (gameflow.cyphered_strings)
	{
		// decypher string data
		strptr = *buffer;
		for (i=0;i<size;i++)
			*(strptr+i) ^= gameflow.cypher_code;
	}
	// Setup string ptrs
	for (i=0;i<num_strings;i++)
	{
		strings[i] = *buffer +LGF_offsets[i];
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
		jprintf("GF:			%d:%s\n",i, strings[i]);
#endif
	}
	return(1);
}

#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)

void log_seq(sint16 *seq)
{
	int	i;

	if (!seq)
	{
		jprintf("ERROR: No sequence!!!\n\n");
		return;
	}

	for(i=0;i<1000;i++)
	{
		switch(*(seq+i))
		{
			case GFE_PICTURE:
				jprintf("GF:			%d %d PICTURE: %s\n", *(seq+i), *(seq+i+1), GF_picfilenames[*(seq+i+1)]);
				i++;
				break;
			case GFE_LIST_START:
				jprintf("GF:			%d LIST START>>>\n", *(seq+i));
				break;
			case GFE_LIST_END:
				jprintf("GF:			%d LIST END <<<<\n", *(seq+i) );
				break;
			case GFE_PLAYFMV:
				jprintf("GF:			%d %d FMV: %s\n", *(seq+i), *(seq+i+1), GF_fmvfilenames[*(seq+i+1)]);
				i++;
				break;
			case GFE_STARTLEVEL:
				jprintf("GF:			%d %d STARTLEVEL: %s\n", *(seq+i), *(seq+i+1), GF_Level_Names[*(seq+i+1)]);
				i++;
				break;
			case GFE_CUTANGLE:
				jprintf("GF:			%d %d CUT ANGLE: 0x%x\n", *(seq+i), *(seq+i+1), *(seq+i+1));
				i++;
				break;
			case GFE_CUTSCENE:
				jprintf("GF:			%d %d CUTSCENE: %s\n", *(seq+i), *(seq+i+1), GF_cutscenefilenames[*(seq+i+1)]);
				i++;
				break;
			case GFE_LEVCOMPLETE:
				jprintf("GF:			%d LEVCOMPLETE\n", *(seq+i) );
				break;
			case GFE_DEMOPLAY:
				jprintf("GF:			%d %d DEMOPLAY: %s\n", *(seq+i), *(seq+i+1), GF_demofilenames[*(seq+i+1)]);
				i++;
				break;
			case GFE_JUMPTO_SEQ:
				jprintf("GF:			%d %d JUMPTOSEQ: %d\n", *(seq+i), *(seq+i+1), *(seq+i+1));
				i++;
				break;
			case GFE_END_SEQ:
				jprintf("GF:			%d ENDSEQUENCE\n\n", *(seq+i) );
				return;
			case GFE_SETTRACK:
				jprintf("GF:			%d %d SETTRACK: %d\n", *(seq+i), *(seq+i+1), *(seq+i+1));
				i++;
				break;
			case GFE_SUNSET:
				jprintf("GF:			%d SUNSET ENABLED\n", *(seq+i) );
				break;
			case GFE_LOADINGPIC:
				jprintf("GF:			%d %d LOADING PIC: %s\n", *(seq+i), *(seq+i+1), GF_picfilenames[*(seq+i+1)]);
				i++;
				break;
			case GFE_DEADLY_WATER:
				jprintf("GF:			%d DEADLY WATER\n", *(seq+i) );
				break;
			case GFE_NOFLOOR:
				jprintf("GF:			%d %d NO FLOOR\n", *(seq+i), *(seq+i+1), *(seq+i+1) );
				i++;
				break;
			case GFE_STARTANIM:
				jprintf("GF:			%d %d LARA START ANIM\n", *(seq+i), *(seq+i+1), *(seq+i+1) );
				i++;
				break;
			case GFE_NUMSECRETS:
				jprintf("GF:			%d %d NUMBER OF SECRETS\n", *(seq+i), *(seq+i+1), *(seq+i+1) );
				i++;
				break;
			case GFE_ADD2INV:
				if ( *(seq+i+1)<1000 )
					jprintf("GF:			%d %d ADD TO INVENTORY: %s", *(seq+i), *(seq+i+1), GF_inv_types[*(seq+i+1)] );
				else
					jprintf("GF:			%d %d START INVENTORY: %s", *(seq+i), *(seq+i+1), GF_inv_types[*(seq+i+1)-1000] );
				i++;
				break;
			case GFE_REMOVE_WEAPONS:
				jprintf("GF:			%d REMOVE WEAPONS\n", *(seq+i) );
				break;
			case GFE_REMOVE_AMMO:
				jprintf("GF:			%d REMOVE AMMO\n", *(seq+i) );
				break;
			case GFE_KILL2COMPLETE:
				jprintf("GF:			%d KILL TO COMPLETE\n", *(seq+i) );
				break;
			default:
				jprintf("GF:			ERROR: Unknown sequence command (%d)\n", *(seq+i));
				return;
		}
	}
}
#endif

#if 0
#define CHECK_ALIGN(s) FILE_Read(&number, sizeof(sint16), 1, file ); \
			if ( number!=0x7777 ){printf("GF:	ERROR: Mis-aligned "s); \
			return(0);}
#else
#define CHECK_ALIGN(s) //
#endif

#define THIS_SCRIPT_VERSION 3

int S_LoadGameFlow( char *filename )
{
	int file;
	sint16 number,size;
	int	i;

#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
	jprintf("GF:	Loading GameFlow Data\n\n");
#endif

	script_malloc_size = 0;
	init_game_malloc();
	file = FILE_Open(filename);

//##	if (file == NULL)
	if (file <= 0)
	{
		printf("GF:	ERROR: Could not open file '%s'\n\n",filename);
		return (0);
	}

	FILE_Read( &GF_ScriptVersion, sizeof(uint32), 1, file);
	if (GF_ScriptVersion!=THIS_SCRIPT_VERSION)
	{
		printf("GF:	ERROR: Incorrect script version %d (%d)\n",(int)GF_ScriptVersion,THIS_SCRIPT_VERSION);
		return(0);
	}

	FILE_Read( GF_Description, sizeof(char), 256, file );

	// Read in GAMEFLOW_INFO
	FILE_Read( &size, sizeof(sint16),1,file);
	if (size!=sizeof(GAMEFLOW_INFO))
	{
	 	printf("GF:	ERROR: Incorrect GAMEFLOW_INFO size %d (%d)\n",size,sizeof(GAMEFLOW_INFO));
		return(0);
	}
	FILE_Read( &gameflow, sizeof(GAMEFLOW_INFO), 1, file);

#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
	jprintf("GF:	Cyphered Strings:%d\n", gameflow.cyphered_strings);
	jprintf("GF:	Cypher Code:%x\n", gameflow.cypher_code);

	jprintf("GF:	%d level(s)\n", gameflow.num_levels);
	jprintf("GF:	%d pic file(s)\n", gameflow.num_picfiles);
	jprintf("GF:	%d title file(s)\n", gameflow.num_titlefiles);
	jprintf("GF:	%d fmv file(s)\n", gameflow.num_fmvfiles);
	jprintf("GF:	%d cut file(s)\n", gameflow.num_cutfiles);
	jprintf("GF:	%d demo(s)\n", gameflow.num_demos);
	jprintf("GF:	Title Track: %d\n", gameflow.title_track);
	jprintf("GF:	Single Playable: %d\n", gameflow.singlelevel);

	jprintf("GF:	Title Replace: %x\n", (int)gameflow.title_replace);
	jprintf("GF:	First Option: %x\n", (int)gameflow.firstOption);
	jprintf("GF:	OnDeath Demo: %x\n", (int)gameflow.ondeath_demo_mode);
	jprintf("GF:	OnDeath Ingame: %x\n", (int)gameflow.ondeath_ingame);
	jprintf("GF:	OnDemo Interrupt: %x\n", (int)gameflow.on_demo_interrupt);
	jprintf("GF:	OnDemo End: %x\n", (int)gameflow.on_demo_end);
	jprintf("GF:	NoInput time: %d seconds\n", (int)gameflow.noinput_time/30);

	jprintf("GF:	Title Enabled? %d\n", gameflow.title_disabled);
	jprintf("GF:	CheatmodeCheck Disabled? %d\n", gameflow.cheatmodecheck_disabled);
	jprintf("GF:	Noinput TimeOut? %d\n", gameflow.noinput_timeout);
	jprintf("GF:	Load/Save Disabled? %d\n", gameflow.loadsave_disabled);
	jprintf("GF:	ScreenSizing Disabled? %d\n", gameflow.screensizing_disabled);
	jprintf("GF:	LockOut OptionRing? %d\n", gameflow.lockout_optionring);
	jprintf("GF:	'Dozy' Cheat? %d\n", gameflow.dozy_cheat_enabled);
#endif

	CHECK_ALIGN("Level Names\n");

	// Level Name/Filename Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading LevelNames\n");
#endif
	GF_Level_Names = (char**)game_malloc(gameflow.num_levels*sizeof(char*), SCRIPT_DATA);
	if (!GF_Level_Names)
	{
 		jprintf("GF:	Could not allocate memory for GF_Level_Names(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Level_Names, &GF_levelnames_buffer, file ))
		return(0);

	CHECK_ALIGN("PIC FileNames\n");

#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Pic FNames\n");
#endif
	GF_picfilenames = (char**)game_malloc(gameflow.num_picfiles*sizeof(char*), SCRIPT_DATA );
	if (!GF_picfilenames)
	{
 		jprintf("GF:	Could not allocate memory for GF_picfilenames(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_picfiles, GF_picfilenames,  &GF_picfilenames_buffer, file ))
		return(0);

	CHECK_ALIGN("Title FileNames\n");


#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
	jprintf("GF:	Loading Title FNames\n");
#endif
	GF_titlefilenames = (char**) game_malloc(gameflow.num_titlefiles*sizeof(char*), SCRIPT_DATA);
	if (!GF_titlefilenames)
	{
 		jprintf("GF:	Could not allocate memory for GF_titlefilenames(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_titlefiles, GF_titlefilenames, &GF_titlefilenames_buffer, file ))
		return(0);

	CHECK_ALIGN("FMV FileNames\n");


#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
	jprintf("GF:	Loading FMV FNames\n");
#endif
	GF_fmvfilenames = (char**) game_malloc( gameflow.num_fmvfiles*sizeof(char*), SCRIPT_DATA );
	if (!GF_fmvfilenames)
	{
 		jprintf("GF:	Could not allocate memory for GF_fmvfileenames (%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_fmvfiles, GF_fmvfilenames, &GF_fmvfilenames_buffer, file ))
		return(0);


	CHECK_ALIGN("Level FileNames\n");

#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
	jprintf("GF:	Loading Level FNames\n");
#endif
	GF_levelfilenames = (char**) game_malloc( gameflow.num_levels*sizeof(char*), SCRIPT_DATA );
	if (!GF_levelfilenames)
	{
 		jprintf("GF:	Could not allocate memory for GF_levelfilenames(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_levelfilenames, &GF_levelfilenames_buffer, file ))
		return(0);


	CHECK_ALIGN("CUT FileNames\n");


#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
	jprintf("GF:	Loading Cut FNames\n");
#endif
	GF_cutscenefilenames = (char**) game_malloc( gameflow.num_cutfiles*sizeof(char*), SCRIPT_DATA );
	if (!GF_cutscenefilenames)
	{
 		jprintf("GF:	Could not allocate memory for GF_cutscenefilenames(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_cutfiles, GF_cutscenefilenames, &GF_cutscenefilenames_buffer, file ))
		return(0);


/*
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
	jprintf("GF:	Loading Demo FNames\n");
#endif
	GF_demofilenames = (char**) game_malloc( gameflow.num_demos*sizeof(char*), SCRIPT_DATA  );
	if (!GF_demofilenames)
	{
 		jprintf("GF:	Could not allocate memory for GF_demofilenames(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_demos, GF_demofilenames, &GF_demofilenames_buffer, file ))
		return(0);
*/
/********************  SEQUENCE DATA  *********************************/
	CHECK_ALIGN("Sequence Offset\n");

#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
	jprintf("\nGF:	Loading Sequence Data\n");
#endif

	// Read-in offsets into seq buffer for each sequence
	FILE_Read( &LGF_offsets, sizeof(sint16),(gameflow.num_levels+1), file);
	FILE_Read( &size, sizeof(sint16), 1, file );
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
	jprintf("GF:	Sequence Data= %d bytes\n",size);
#endif

	CHECK_ALIGN("Sequence Data\n");


	// Read-in sequence data
	GF_sequence_buffer = (sint16*) game_malloc(size, SCRIPT_DATA );
	if (!GF_sequence_buffer)
	{
 		jprintf("GF:	Could not allocate memory for sequences (%d bytes)\n", size);
		return (0);
	}
	FILE_Read( GF_sequence_buffer, sizeof(sint16), size/2, file );

	// Frontend Sequence
	GF_frontendSequence = GF_sequence_buffer;
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
	jprintf("GF:		FrontEnd Sequence\n");
//	log_seq(GF_frontendSequence);
#endif

	// Level Sequences
	for (i=0;i<gameflow.num_levels;i++)
	{
		GF_level_sequence_list[i] = GF_sequence_buffer+LGF_offsets[i+1]/2;
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
		jprintf("GF:		Level %d Sequence\n",i);
//		log_seq( GF_level_sequence_list[i] );
#endif
	}
/*	// Demo Sequences
	for (i=0;i<gameflow.num_demos;i++)
	{
		GF_demo_sequence_list[i] = GF_sequence_buffer+LGF_offsets[gameflow.num_levels+i+1]/2;
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
		jprintf("GF:		Demo %d Sequence\n",i);
//		log_seq( GF_demo_sequence_list[i] );
#endif
	}  ``
*/
	CHECK_ALIGN("Demo Numbers\n");

	// Read level number that are actually demos
	if (gameflow.num_demos)
		FILE_Read( GF_valid_demos, sizeof(sint16),gameflow.num_demos, file );

	CHECK_ALIGN("FMV Info\n");

	if (gameflow.num_fmvfiles)
		FILE_Read( GF_fmv_data, sizeof(FMV_INFO),gameflow.num_fmvfiles, file );


/********************  GAME STRINGS  *********************************/
	CHECK_ALIGN("Game Strings\n");

	FILE_Read(&number, sizeof(sint16), 1, file );
	if (number!=GT_NUM_GAMESTRINGS)
	{
		jprintf("GF: ERROR: Incorrect number of GameStrings");
		jprintf("GF:	Script=%d	Game=%d", number, GT_NUM_GAMESTRINGS);
		return(0);
	}


	// GameText Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Game Strings\n");
#endif
	GF_GameStrings = (char**) game_malloc( GT_NUM_GAMESTRINGS*sizeof(char*), SCRIPT_DATA );
	if (!GF_GameStrings)
	{
 		jprintf("GF:	Could not allocate memory for GF_GameStrings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( GT_NUM_GAMESTRINGS, GF_GameStrings, &GF_GameStrings_buffer, file ))
		return(0);

	/* FRIG: SPACE (' ',0) for control config option */
	*GF_GameStrings[GT_SPACE] = ' ';
	*(GF_GameStrings[GT_SPACE]+1) = 0;


	CHECK_ALIGN("PSX Strings\n");

	// PSXText Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading PSX Strings\n");
#endif
	GF_PSXStrings = (char**) game_malloc( PSSTR_NUM_STRINGS*sizeof(char*), SCRIPT_DATA );
	if (!GF_PSXStrings)
	{
 		jprintf("GF:	Could not allocate memory for GF_PSXStrings ptrs(%d bytes)\n", size);
    	return (0);
	}
	if (!Read_Strings( PSSTR_NUM_STRINGS, GF_PSXStrings, &GF_PSXStrings_buffer, file ))
		return(0);



	CHECK_ALIGN("Puzzle1 Strings\n");

	// Puzzle1 Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Puzzle1 Strings\n");
#endif
	GF_Puzzle1Strings = (char**) game_malloc( gameflow.num_levels*sizeof(char*), SCRIPT_DATA );
	if (!GF_Puzzle1Strings)
	{
 		jprintf("GF:	Could not allocate memory for GF_Puzzle1Strings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Puzzle1Strings, &GF_Puzzle1Strings_buffer, file ))
		return(0);

	CHECK_ALIGN("Puzzle2 Strings\n");

	// Puzzle2 Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Puzzle2 Strings\n");
#endif
	GF_Puzzle2Strings = (char**) game_malloc(gameflow.num_levels*sizeof(char*), SCRIPT_DATA);
	if (!GF_Puzzle2Strings)
	{
 		jprintf("GF:	Could not allocate memory for GF_Puzzle2Strings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Puzzle2Strings, &GF_Puzzle2Strings_buffer, file ))
		return(0);

	CHECK_ALIGN("Puzzle3 Strings\n");

	// Puzzle3 Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Puzzle3 Strings\n");
#endif
	GF_Puzzle3Strings = (char**) game_malloc( gameflow.num_levels*sizeof(char*), SCRIPT_DATA);
	if (!GF_Puzzle3Strings)
	{
 		jprintf("GF:	Could not allocate memory for GF_Puzzle3Strings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Puzzle3Strings, &GF_Puzzle3Strings_buffer, file ))
		return(0);

	CHECK_ALIGN("Puzzle4 Strings\n");

	// Puzzle4 Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Puzzle4 Strings\n");
#endif
	GF_Puzzle4Strings = (char**) game_malloc( gameflow.num_levels*sizeof(char*), SCRIPT_DATA);
	if (!GF_Puzzle4Strings)
	{
 		jprintf("GF:	Could not allocate memory for GF_Puzzle4Strings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Puzzle4Strings, &GF_Puzzle4Strings_buffer, file ))
		return(0);

	CHECK_ALIGN("Secret1 Strings\n");





/*
	// Secret1 Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Secret1 Strings\n");
#endif
	GF_Secret1Strings = (char**) game_malloc( gameflow.num_levels*sizeof(char*), SCRIPT_DATA);
	if (!GF_Secret1Strings)
	{
 		jprintf("GF:	Could not allocate memory for GF_Secret1Strings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Secret1Strings, &GF_Secret1Strings_buffer, file ))
		return(0);

	CHECK_ALIGN("Secret2 Strings\n");

	// Secret2 Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Secret2 Strings\n");
#endif
	GF_Secret2Strings = (char**) game_malloc( gameflow.num_levels*sizeof(char*), SCRIPT_DATA);
	if (!GF_Secret2Strings)
	{
 		jprintf("GF:	Could not allocate memory for GF_Secret2Strings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Secret2Strings, &GF_Secret2Strings_buffer, file ))
		return(0);

	CHECK_ALIGN("Secret3 Strings\n");

	// Secret3 Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Secret3 Strings\n");
#endif
	GF_Secret3Strings = (char**) game_malloc( gameflow.num_levels*sizeof(char*), SCRIPT_DATA);
	if (!GF_Secret3Strings)
	{
 		jprintf("GF:	Could not allocate memory for GF_Secret3Strings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Secret3Strings, &GF_Secret3Strings_buffer, file ))
		return(0);

	CHECK_ALIGN("Secret4 Strings\n");

	// Secret4 Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Secret4 Strings\n");
#endif
	GF_Secret4Strings = (char**) game_malloc( gameflow.num_levels*sizeof(char*), SCRIPT_DATA);
	if (!GF_Secret4Strings)
	{
 		jprintf("GF:	Could not allocate memory for GF_Secret4Strings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Secret4Strings, &GF_Secret4Strings_buffer, file ))
		return(0);

	CHECK_ALIGN("Special1 Strings\n");

	// Special1 Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Special1 Strings\n");
#endif
	GF_Special1Strings = (char**) game_malloc( gameflow.num_levels*sizeof(char*), SCRIPT_DATA);
	if (!GF_Special1Strings)
	{
 		jprintf("GF:	Could not allocate memory for GF_Special1Strings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Special1Strings, &GF_Special1Strings_buffer, file ))
		return(0);

	CHECK_ALIGN("Special2 Strings\n");

	// Special2 Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Special2 Strings\n");
#endif
	GF_Special2Strings = (char**) game_malloc( gameflow.num_levels*sizeof(char*), SCRIPT_DATA);
	if (!GF_Special2Strings)
	{
 		jprintf("GF:	Could not allocate memory for GF_Special2Strings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Special2Strings, &GF_Special2Strings_buffer, file ))
		return(0);

*/







	CHECK_ALIGN("Pickup1 Strings\n");

	// Pickup1 Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Pickup1 Strings\n");
#endif
	GF_Pickup1Strings = (char**) game_malloc( gameflow.num_levels*sizeof(char*), SCRIPT_DATA);
	if (!GF_Pickup1Strings)
	{
 		jprintf("GF:	Could not allocate memory for GF_Pickup1Strings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Pickup1Strings, &GF_Pickup1Strings_buffer, file ))
		return(0);

	CHECK_ALIGN("Pickup2 Strings\n");

	// Pickup2 Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Pickup2 Strings\n");
#endif
	GF_Pickup2Strings = (char**) game_malloc( gameflow.num_levels*sizeof(char*), SCRIPT_DATA);
	if (!GF_Pickup2Strings)
	{
 		jprintf("GF:	Could not allocate memory for GF_Pickup2Strings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Pickup2Strings, &GF_Pickup2Strings_buffer, file ))
		return(0);


	CHECK_ALIGN("Key1 Strings\n");

	// Key1 Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Key1 Strings\n");
#endif
	GF_Key1Strings = (char**) game_malloc( gameflow.num_levels*sizeof(char*), SCRIPT_DATA);
	if (!GF_Key1Strings)
	{
 		jprintf("GF:	Could not allocate memory for GF_Key1Strings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Key1Strings, &GF_Key1Strings_buffer, file ))
		return(0);

	CHECK_ALIGN("Key2 Strings\n");

	// Key2 Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Key2 Strings\n");
#endif
	GF_Key2Strings = (char**) game_malloc( gameflow.num_levels*sizeof(char*), SCRIPT_DATA);
	if (!GF_Key2Strings)
	{
 		jprintf("GF:	Could not allocate memory for GF_Key2Strings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Key2Strings, &GF_Key2Strings_buffer, file ))
		return(0);

	CHECK_ALIGN("Key3 Strings\n");

	// Key3 Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Key3 Strings\n");
#endif
	GF_Key3Strings = (char**) game_malloc( gameflow.num_levels*sizeof(char*), SCRIPT_DATA);
	if (!GF_Key3Strings)
	{
 		jprintf("GF:	Could not allocate memory for GF_Key3Strings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Key3Strings, &GF_Key3Strings_buffer, file ))
		return(0);

	CHECK_ALIGN("Key4 Strings\n");

	// Key4 Strings
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
 	jprintf("GF:	Loading Key4 Strings\n");
#endif
	GF_Key4Strings = (char**) game_malloc( gameflow.num_levels*sizeof(char*), SCRIPT_DATA);
	if (!GF_Key4Strings)
	{
 		jprintf("GF:	Could not allocate memory for GF_Key4Strings ptrs(%d bytes)\n", size);
		return (0);
	}
	if (!Read_Strings( gameflow.num_levels, GF_Key4Strings, &GF_Key4Strings_buffer, file ))
		return(0);

	CHECK_ALIGN("Data End\n");

	FILE_Close(file);

	// Setup permenant script buffer in game_malloc buffer
	script_malloc_size = malloc_used;
#if defined(GAMEDEBUG) && defined(SCRIPT_INFO)
	jprintf("\nScript Data Size: %d bytes\n\n", script_malloc_size);
#endif
	init_game_malloc();
	return (1);
}


void	build_ext( char *fname, char *ext )
{
	while ( *fname!='.' && *fname!=0 )
		fname++;

	*(fname++) = '.';
	*(fname++) = *(ext++);
	*(fname++) = *(ext++);
	*(fname++) = *(ext++);
	*(fname++) = 0;
}

