/**********************************************************************

	Title :                 Futuristic City Main
	Filename :              future.c
	Author :                Thomas Szirtes
	Revision :              1.0

	Notes :                 

	Copyright :             (C) SEGA Europe 1998

  **********************************************************************/
 
/*---------------------------------------------------------------------------

	CONTROLS :

	(PAD)

	Directional Left/Right                  Turn Left/Right
	Directional Up/Down                             Turn Up/Down
	
	C (c)                                                   Thrust
	X (a)                                                   Internal View
	Y (s)                                                   Fixed View
	X+Y (as)                                                External View
	Z (d)                                                   Follow View
	
  ---------------------------------------------------------------------------*/


/*
 *      Compiler control
 */



/*
 * Include files.
 */

#include        "ftypes.h"
#define         STANDALONE

#ifndef         USING_SET4
 #define         ENABLE_LEVEDIT
#endif


#ifdef  USING_SET4
 #include        <shinobi.h>
#else
 #include        <ninja.h>
 #include        <ninjawin.h>
#endif

#ifdef  SOUND_ENABLE
 #include       "sound.h"
#endif

#include        "camera.h"
#include        "debug.h"
#include        "particle.h"
#include        "display.h"
#include        "levedit.h"
#include        "movement.h"
#include        "action.h"
#include        "tools.h"
#include        "map.h"
#include        "future.h"
#include        "task.h"
#include        "collide.h"
#include        "procs.h"

/*
 * #defines and macros.
 */

/* Maximum number of vertices - for Ninja */
#define         MAX_VERTEX              (1024*16)
#define         MAX_ALPHA               1024
#define         MAX_MATRIX              128
#define         MAX_TEXTURE             128
#define         MAX_LAG                 2
#define         FRONT_CLIP              -1.0f
#define         BACK_CLIP               -29000.0f

#ifdef  USING_SET4
 extern NJS_MATRIX       matrix[32];
 extern NJS_VERTEX_BUF   vbuf[4096];
#else
 NJS_MATRIX      matrix[32];
 NJS_VERTEX_BUF  vbuf[4096];
#endif


/*
 * Structure definitions.
 */

struct myglobals {
	NJS_TEXMEMLIST          tex[MAX_TEXTURE];
	NJS_VIEW                view;
	NJS_LIGHT               light;
	PERIPH_DATA             per;
	int                     user_mode;
	int                     viewmode;
} myglobals;



/* Temporary Global variables - these will be removed eventually */

NJS_TEXANIM             ll_texanim[] = 
{       { 64,64,32,32,0,0,255, 255,3,0 }};

NJS_SPRITE      sprite;
NJS_MATRIX      mtest;
NJS_ARGB        argb;


/*
 * External Dependancies
 */

/* Import Object Data */

/* ships */
extern  NJS_OBJECT      OBJSHIP1[];
extern  NJS_OBJECT      OBJSHIP2[];
extern  NJS_OBJECT      OBJSHIP3[];
extern  NJS_OBJECT      OBJSHIP4[];
extern  NJS_OBJECT      OBJSHIP5[];

/* ships */
extern  NJS_TEXLIST     TEXSHIP1;
extern  NJS_TEXLIST     TEXSHIP2;
extern  NJS_TEXLIST     TEXSHIP3;
extern  NJS_TEXLIST     TEXSHIP4;
extern  NJS_TEXLIST     TEXSHIP5;

/* misc objects */
extern  NJS_OBJECT      object_building_L_1_spin[];
extern  NJS_OBJECT      object_buildingK_buildingK_spin1[];
extern  NJS_OBJECT      object_test_stand_stand[];




/*********************************************************************************/
/************************* D A T A   A R E A *************************************/
/*********************************************************************************/

/*
 *      Module variables.
 */

/* can be externally referenced */
CAMERA                  mycam;                                  /* the main camera */
MAP                     map;                                    /* the MAP */
PDATABASE               particle_database;

static                  future_has_not_been_initialised = TRUE;
int                     instance_count  =       0;				/* instance count */

/*--------------- ATTRIBUTES FOR USER SHIP ----------------------// */
ATTRSHIP                attrship_user   =       {
										8.0f,                                                   /* maximum velocity */
										0.0f,                                                   /* minimum velocity */
										0.2f,                                                   /* acceleration */
										(1.0f/PERIPHERAL_SCALE),                /* deacceleration */
										(2.0f/PERIPHERAL_SCALE),                /* max yaw */
										(1.0f/PERIPHERAL_SCALE),                /* max pitch */
										0.05f,                                                  /* responsiveness yaw */
										0.03f                                                   /* responsiveness pitch */
									};


/*-------------- ALL THE DATA FOR LEVEL 1 ----------------------// */
#include                "lev1.c"
 

/* MISC TEXTURE LIST - other odd bits of textures for effects etc.. */
NJS_TEXNAME     misc_texname[] = {
		{"flare1", 0, 0 },				
		{"smoke1", 0, 0 },				
		{"extex", 0, 0 },
		{"lazflare", 0, 0 },
		{"lazball", 0, 0 },
		{"exhaust",0,0 },
		{"spark",0,0 },
		{"tail",0,0 },
};

NJS_TEXLIST     misc_texlist = { misc_texname, 8 };			/* don't forget to update count! */

BUILDING_INSTANCE build_inst[MAX_INSTANCE];


/*
 *              TEMPORARY VARIABLES - these are for test purposes
 */

NJS_LIGHT                       tlight;					/* ambient */
NJS_LIGHT                       flight;					/* spot light 1 */
NJS_LIGHT                       f2light;				/* spot light 2 */
NJS_PERIPHERAL					*per1;
Uint32                          time;					/* debug timer */
int                             frame           =       0;
int                             wframe          =       0;
float							light_int       =       0.0f;
float							light_int_d     =       .02f;
float							r;						


/*              Ship firing */

#define                         USER_FIRE_SPEED                 15
#define                         USER_FIRE_RECHARGE_TIME			7
#define                         USER_FIRE_LIFE_TIME             70
#define                         USER_FIRE_MAX                   (USER_FIRE_LIFE_TIME/USER_FIRE_RECHARGE_TIME)
int                             user_fire_side          =       0;                      /* which side to fire - left/right */
int                             user_fire_recharge      =       0;                      /* fire recharge time */
int                             user_fire_index         =       0;
FIRE                            fire[USER_FIRE_MAX];

/* top task pointer for explosions etc */
TASK                            *explode_tasks;



/*********************************************************************************/
/************************* P R O G R A M   A R E A *******************************/
/*********************************************************************************/

/*---------------------------------- PRIVATE FUNCTIONS ----------------------------------------*/

/*--------------------------------------------------------------------------

  static int     Fire_CheckShip(FIRE *fire, Uint8 shipid, NJS_VECTOR *coll)

  Parameters:
			fire	fire to check
			shipid	ship identifier to check against
			coll	collision vector pointer

  Returns:
			0		no collision
			1		collision (coll is modified)

  Notes:
			Checks collision with a lazer with a ship
  
  --------------------------------------------------------------------------*/
static int  Fire_CheckShip(FIRE *fire, Uint8 shipid, NJS_VECTOR *coll)
{
	SHIP	*sh;
	int      rtn    =       -1;
	static	COLOBJ_SPHERE colobj;
	NJS_VECTOR	*p;

	p	=	&fire->pos;

	while (shipid != 0xff && rtn == -1)
	{
		if (shipid==0) break;
		sh              =       shipdb[shipid];
		colobj.centre.x =       sh->move.position.x;
		colobj.centre.y =       sh->move.position.y;
		colobj.centre.z =       sh->move.position.z;
		colobj.rad      =       sh->radius;

		if(COLLIDE_Sphere(p, &colobj, coll, 6.f)!=0)    rtn     =       shipid;
		shipid  =       sh->next_ship;
	}

	return rtn;

}


/*--------------------------------------------------------------------------

  static	void	Fire_CheckBuilding(FIRE *fire)

  Parameters:
			fire	pointer to fire object

  Returns:
			none

  Notes:
			Checks fire collision with a building, if there is one
			then explosion task is started

  --------------------------------------------------------------------------*/
static void	Fire_CheckBuilding(FIRE *fire)
{
	int     i,j,rtn;
	NJS_VECTOR      coll;
	TASK    *t;
	EXPLODE_TASK_DATA       *etd;
	TRANSPORT_TASK_DATA     *ttd;
	
	rtn     =       0;

	/* convert position to grid */
	i       =       P2GRID( fire->pos.x+64.f );
	j       =       P2GRID( fire->pos.z+64.f );

	/* check for building collision */
	if (map.map[i][j].inst != 0xffff)
	{
		rtn     =       COLLIDE_Building ( &fire->pos, map.map[i][j].inst ,&coll);
		if (rtn != 0)
		{
			/* do building explosion */
			t       =       TASK_Insert(explode_tasks);             /* create task */
#ifdef  SOUND_ENABLE
			SOUND_Boom();
#endif

#ifdef USING_SET4
			etd     =       (EXPLODE_TASK_DATA *)syMalloc(sizeof(EXPLODE_TASK_DATA));
#else
			etd     =       (EXPLODE_TASK_DATA *)malloc(sizeof(EXPLODE_TASK_DATA));
#endif
			SET_TASK        ( t, ProcExplode, etd )
			t->life         =       20;
			etd->centre     =       fire->pos;                              /* store source */
			etd->size       =       0.f;
			fire->flag      =       0;
			return;
		}
	}

	/* check for ship collision */
	rtn     = Fire_CheckShip( fire, map.map[i][j].ship, &coll);
	if (rtn!=-1)
	{
		/* do building explosion */
		t       =       TASK_Insert(explode_tasks);             /* create task */
#ifdef SOUND_ENABLE
		SOUND_Ahh();
#endif
#ifdef USING_SET4
		ttd  =   (TRANSPORT_TASK_DATA *)syMalloc(sizeof(TRANSPORT_TASK_DATA));
#else
		ttd     =       (TRANSPORT_TASK_DATA *)malloc(sizeof(TRANSPORT_TASK_DATA));
#endif
		SET_TASK (t,ProcTransport,ttd)
		t->life			=       -1;
		ttd->centre     =       shipdb[rtn]->move.position;                             /* store source */
		ttd->size       =       shipdb[rtn]->radius/3.f;
		ttd->cursize	=		ttd->size;
		fire->flag      =       0;
		shipdb[rtn]->move.position.x    =       0.f;
		shipdb[rtn]->move.position.y    =       0.f;
		shipdb[rtn]->move.position.z    =       0.f;
		shipdb[rtn]->flags      |= SHIP_FLAG_DISABLE;
		shipdb[rtn]->misc_count                 =       0;
		return;
	}
}


/*--------------------------------------------------------------------------

  static void Fire_fire(SHIP *ship)

  Parameters:
			ship	pointer to ship firing

  Returns:
			none

  Notes:
			Starts a fire task for that ship (Really only works on user ship
			at present - only slight modification needed though)
  --------------------------------------------------------------------------*/

static void Fire_fire(SHIP *ship)
{
	static  NJS_POINT3      v = {5.20f,0.0f,-17.4f};

	if (user_fire_recharge>0) return;

	user_fire_recharge = USER_FIRE_RECHARGE_TIME;

#ifdef SOUND_ENABLE
	SOUND_Fire();
#endif

	user_fire_side  =       (user_fire_side+1)&1;

	if (user_fire_side==0)
		v.x     =       6.40f;
	else
		v.x     =       -6.40f;

	/* calc start position - not very nice */
	njPushMatrix		( NULL );
		njSetMatrix			( NULL, &_unit_matrix_);
		njTranslate			( NULL, ship->move.position.x, ship->move.position.y, ship->move.position.z );
		njRotateY			( NULL, NJM_DEG_ANG(180.f+ship->move.yaw) );
		njRotateZ			( NULL, NJM_DEG_ANG(ship->move.roll) );
		njRotateX			( NULL, NJM_DEG_ANG(ship->move.pitch) );
		njCalcPoint			( NULL, &v, &fire[user_fire_index].pos);
	njPopMatrix			( 1 );

	fire[user_fire_index].dir.x             =       njSin(NJM_DEG_ANG(ship->move.yaw))*(USER_FIRE_SPEED+ship->move.velmag);
	fire[user_fire_index].dir.y             =       njSin(NJM_DEG_ANG(ship->move.pitch))*(USER_FIRE_SPEED+ship->move.velmag);
	fire[user_fire_index].dir.z             =       njCos(NJM_DEG_ANG(ship->move.yaw)) * njCos(NJM_DEG_ANG(ship->move.pitch))*(USER_FIRE_SPEED+ship->move.velmag);

	fire[user_fire_index].flag              =       1;              /* alive */
	fire[user_fire_index].life              =       0;

	user_fire_index++;
	if (user_fire_index>=USER_FIRE_MAX) user_fire_index = 0;


}


/*--------------------------------------------------------------------------

  static void Fire_update()

  Parameters:

  Returns:
			none

  Notes:
		Updates fire positions and display
  --------------------------------------------------------------------------*/

static void Fire_update()
{
	int             n;

	if (user_fire_recharge>0) user_fire_recharge--;

	for(n=0;n<USER_FIRE_MAX;n++)
	{
		if (fire[n].flag        ==      1)
		{
			/* draw */
			DISPLAY_Fire(&fire[n]); 
			
			Fire_CheckBuilding(&fire[n]);

			fire[n].pos.x   +=      fire[n].dir.x;
			fire[n].pos.y   +=      fire[n].dir.y;
			fire[n].pos.z   +=      fire[n].dir.z;
			
			fire[n].life    ++;
			if (fire[n].life==USER_FIRE_LIFE_TIME) fire[n].flag     =       0;
		}
	}

}




/*--------------------------------------------------------------------------

  static void FUTURE_Init(void)
 
  Parameters:
 
  Returns:
 
  Notes:
		Initializes the future module
 
  --------------------------------------------------------------------------*/

static void FUTURE_Init(void)
{

#ifdef SOUND_ENABLE
	SOUND_Init();
#endif
	
	/*------------------- COLLISION Initialization -------------------// */
	/* This will be replaced by binary file loading routine and performed offline */

	collide_build_m_1.collide       =       COLLIDE_NjtoPolyh( model_m_clsn_Mbase1, testpl );
	collide_build_m_2.collide       =       COLLIDE_NjtoPolyh( model_m_clsn_Mbase2, testpl );
	collide_build_m_3.collide       =       COLLIDE_NjtoPolyh( model_m_clsn_Mmid1, testpl );
	collide_build_m_4.collide       =       COLLIDE_NjtoPolyh( model_m_clsn_Mmid2, testpl );
	collide_build_m_5.collide       =       COLLIDE_NjtoPolyh( model_m_clsn_Mtop, testpl );

	collide_build_l_1.collide       =       COLLIDE_NjtoPolyh( model_Lclns_clsn_Lbase1, testpl );
	collide_build_l_2.collide       =       COLLIDE_NjtoPolyh( model_Lclns_clsn_Lbase2, testpl );
	collide_build_l_3.collide       =       COLLIDE_NjtoPolyh( model_Lclns_clsn_Lbase3, testpl );

	collide_build_k_1.collide       =       COLLIDE_NjtoPolyh( model_Kclsn_Kclsn_Kpart1, testpl );
	collide_build_k_2.collide       =       COLLIDE_NjtoPolyh( model_Kclsn_Kclsn_Kpart2, testpl );
	collide_build_k_3.collide       =       COLLIDE_NjtoPolyh( model_Kclsn_Kclsn_Kpart3, testpl );

	collide_build_b_1.collide       =       COLLIDE_NjtoPolyh( model__Bcln_Btop1, testpl );
	collide_build_b_2.collide       =       collide_build_b_3.collide       =       collide_build_b_4.collide       =       collide_build_b_5.collide       =       collide_build_b_6.collide       =       collide_build_b_7.collide       = collide_build_b_1.collide;
	collide_build_b_8.collide       =       COLLIDE_NjtoPolyh( model__Bcln_Bpart1, testpl );
	
	collide_build_c.collide         =       COLLIDE_NjtoPolyh( model_Cclsn_Cclsn_Cpart1     , testpl );
	collide_build_c_1.collide       =       COLLIDE_NjtoPolyh( model_Cclsn_Cclsn_Cpart2     , testpl );
	collide_build_c_2.collide       =       COLLIDE_NjtoPolyh( model_Cclsn_Cclsn_Cpart3     , testpl );
	
	/* NINJA Initialization  */
#ifdef USING_SET4
	njInitTextureBuffer((Sint8 *)vbuf,0x40800);
#endif

	njInitVertexBuffer      ( 500000, 0, 500000, 0 );
	njInitMatrix            ( matrix, 32 , 1);
	njInit3D                ( vbuf, MAX_VERTEX );
	njInitView              ( &myglobals.view );
	njSetView               ( &myglobals.view );
	njInitTexture           ( myglobals.tex, MAX_TEXTURE );
	njSetConstantAttr       ( 0xffffffff, NJD_FILTER_BILINEAR); 
	njControl3D             ( NJD_CONTROL_3D_CONSTANT_ATTR |
						      NJD_CONTROL_3D_ENABLE_ALPHA );


#ifndef USING_SET4
	njSetTexturePath("d:\\future\\image\\");
#endif

	/* MAP INITIALIZATION */
	MAP_Init();
#ifdef USING_SET4
	MAP_Load                        ( "test.bin" );
#else   
	MAP_Load                        ( "d:\\future\\image\\empty.bin" );
#endif

	/* DISPLAY INITIALIZATION */
	DISPLAY_Init();

	/* Load in textures */
	njLoadTexture   ( &TEXSHIP1 );
	njLoadTexture   ( &TEXSHIP4 );
	njLoadTexture   ( &TEXSHIP5 );
	njLoadTexture   ( &TEXSHIP3 );
	njLoadTexture   ( &misc_texlist );
	njLoadTexture   ( &flame_texlist);

	njTextureShadingMode(  NJD_TEX_SHADING_MODE_MODULATEALPHA );

	/* Create first a directional light */
	njCreateLight           ( &myglobals.light, NJD_DIR_LIGHT );
	njSetLightDirection     ( &myglobals.light, -0.4f, -0.2f, 0.6f );
	njSetLightColor         ( &myglobals.light, 1.0f, 1.0f, 1.0f);
	njSetLightIntensity     ( &myglobals.light, 0.9f, 0.9f, 0.9f);
	njLightOn                       ( &myglobals.light );

	/* Ambient light */
	njCreateLight           ( &tlight, NJD_AMBIENT);
	njSetLightColor         ( &tlight, 1.0f, 0.0f, 0.0f);
	njSetLightIntensity     ( &tlight, 0.0f, 1.0f, 1.00f); 
	njLightOn                       ( &tlight );

	/* These are temporary - these will be replaced by my dynamic
	   lighting module (not for release) */

	/* Temporary - range light */
	njCreateLight           ( &flight, NJD_POINT_LIGHT);
	njSetLightRange         ( &flight, 200.f, 400.f );
	njSetLightLocation      ( &flight, (33.f*128.f), 180.f, (54.f*128.f));
	njSetLightColor         ( &flight, 0.0f, 0.4f, 1.0f);
	njSetLightIntensity     ( &flight, 1.0f, 1.0f, 1.0f); 
	njLightOn                       ( &flight );

	/* Temporary - range light */
	njCreateLight           ( &f2light, NJD_POINT_LIGHT);
	njSetLightRange         ( &f2light, 200.f, 400.f );
	njSetLightLocation      ( &f2light, (27.f*128.f), 180.f, (61.f*128.f));
	njSetLightColor         ( &f2light, 1.0f, 0.8f, 0.0f);
	njSetLightIntensity     ( &f2light, 1.0f, 1.0f, 1.0f);
	njLightOn                       ( &f2light );


	/* level editor not supplied */
#ifdef  ENABLE_LEVEDIT
	LEVELEDIT_Init();
#endif

	/* Initialize a ship object - USER SHIP */
	ship1.type                      =       0;
	ship1.state                     =       0;
	ship1.shield                    =       0;
	ship1.weapon                    =       0;
	ship1.flags						=       SHIP_FLAG_VIEW|SHIP_FLAG_USER;
	ship1.obj						=       (NJS_OBJECT *)&OBJSHIP1; 
	ship1.tex                       =       (NJS_TEXLIST *)&TEXSHIP1; 
	ship1.loobj                     =       NULL;		/* haven't supplied lo-generation objects in this build*/ 
	ship1.lotex                     =       NULL; 
	ship1.reload                    =       USER_FIRE_RECHARGE_TIME;
	ship1.radius                    =       6.f;

	ship1.ai.type                   =       SHIPAI_TYPE_SCRIPT;		/* ai data */
	ship1.ai.timI                   =       0;
	ship1.ai.script.index			=       0;
	ship1.ai.script.data			=       (unsigned char *)&scr_test;
	
	MOVE_Reset(&ship1);
	ship1.move.position.x			=       GRID2P(33);		/* start position */
	ship1.move.position.z			=       GRID2P(33);
	ship1.move.position.y			=       210;

	ship1.attr                      =       &attrship_user;
	ship1.next_ship                 =       NO_SHIP_ID;

	shipdb[0]                       =       &ship1;

	
	/* Initialize a ship object - COMPUTER CONTROLLED */
	ship2.type                      =       0;
	ship2.state                     =       0;
	ship2.shield                    =       0;
	ship2.weapon                    =       0;
	ship2.flags                     =       0;
	ship2.obj                       =       (NJS_OBJECT *)&OBJSHIP4; 
	ship2.tex                       =       (NJS_TEXLIST *)&TEXSHIP4;
	ship2.loobj                     =       NULL;	/* no lo-data available */
	ship2.lotex                     =       NULL;
	ship2.reload                    =       12;
	ship2.radius                    =       15.f;
	
	ship2.ai.type                   =       SHIPAI_TYPE_SCRIPT;
	ship2.ai.timI                   =       0;
	ship2.ai.script.index			=       0;
	ship2.ai.script.data			=       (unsigned char *)&scr_test;

	MOVE_Reset(&ship2);
	ship2.move.position.x			=       GRID2P(38);
	ship2.move.position.z			=       GRID2P(36);
	ship2.move.position.y			=       240;
	
	ship2.attr                      =       &attrship_comp2;
	ship2.next_ship                 =       NO_SHIP_ID;

	shipdb[1]                       =       &ship2;


	/* Initialize a ship object - computer controlled */
	ship3.type                      =       0;
	ship3.state                     =       0;
	ship3.shield                    =       0;
	ship3.weapon                    =       0;
	ship3.flags                     =       0;
	ship3.obj                       =       (NJS_OBJECT *)&OBJSHIP5; 
	ship3.tex                       =       (NJS_TEXLIST *)&TEXSHIP5;
	ship3.loobj                     =       NULL;
	ship3.lotex                     =       NULL;
	ship3.reload                    =       20;
	ship3.radius                    =       15.f;

	ship3.ai.type                   =       SHIPAI_TYPE_SCRIPT;
	ship3.ai.timI                   =       0;
	ship3.ai.script.index			=       0;
	ship3.ai.script.data			=       (unsigned char *)&scr_test2;

	MOVE_Reset(&ship3);
	ship3.move.position.x			=       GRID2P(38);
	ship3.move.position.z			=       GRID2P(36);
	ship3.move.position.y			=       240;
	
	ship3.attr                      =       &attrship_comp1;
	ship3.next_ship                 =       NO_SHIP_ID;

	shipdb[2]                       =       &ship3;

	/* Initialize a ship object - computer controlled */
	ship4.type                      =       0;
	ship4.state                     =       0;
	ship4.shield                    =       0;
	ship4.weapon                    =       0;
	ship4.flags                     =       0;
	ship4.obj                       =       (NJS_OBJECT *)&OBJSHIP3;
	ship4.tex                       =       (NJS_TEXLIST *)&TEXSHIP3;
	ship4.loobj                     =       NULL; 
	ship4.lotex                     =       NULL; 
	ship4.reload                    =       12;
	ship4.radius                    =       30.f;

	ship4.ai.type                   =       SHIPAI_TYPE_SCRIPT;
	ship4.ai.timI                   =       0;
	ship4.ai.script.index			=       0;
	ship4.ai.script.data			=       (unsigned char *)&scr_test4;

	MOVE_Reset(&ship4);
	ship4.move.position.x			=       GRID2P(26);
	ship4.move.position.z			=       GRID2P(42);
	ship4.move.position.y			=       250;
	
	ship4.attr                      =       &attrship_comp2;
	ship4.next_ship                 =       NO_SHIP_ID;

	shipdb[3]                       =       &ship4;

	/* Initialize a ship object - last ship object */
	ship5.type                      =       0;
	ship5.state                     =       0;
	ship5.shield                    =       0;
	ship5.weapon                    =       0;
	ship5.flags                     =       0;
	ship5.obj                       =       (NJS_OBJECT *)&OBJSHIP3; 
	ship5.tex                       =       (NJS_TEXLIST *)&TEXSHIP3; 
	ship5.loobj                     =       NULL; 
	ship5.lotex                     =       NULL; 
	ship5.reload                    =       12;
	ship5.radius                    =       30.f;
	
	ship5.ai.type                   =       SHIPAI_TYPE_SCRIPT;
	ship5.ai.timI                   =       0;
	ship5.ai.script.index			=       0;
	ship5.ai.script.data			=       (unsigned char *)&scr_test5;

	MOVE_Reset(&ship5);
	ship5.move.position.x			=       GRID2P(30);
	ship5.move.position.z			=       GRID2P(44);
	ship5.move.position.y			=       190;
	
	ship5.attr                      =       &attrship_comp2;
	ship5.next_ship                 =       NO_SHIP_ID;

	shipdb[4]                       =       &ship5;

	/* Initialize a ship object - last ship object */
	ship6.type                      =       0;
	ship6.state                     =       0;
	ship6.shield                    =       0;
	ship6.weapon                    =       0;
	ship6.flags                     =       0;
	ship6.obj                       =       (NJS_OBJECT *)&OBJSHIP3; 
	ship6.tex                       =       (NJS_TEXLIST *)&TEXSHIP3; 
	ship6.loobj                     =       NULL; 
	ship6.lotex                     =       NULL; 
	ship6.reload                    =       12;
	ship6.radius                    =       30.f;
	
	ship6.ai.type                   =       SHIPAI_TYPE_SCRIPT;
	ship6.ai.timI                   =       0;
	ship6.ai.script.index			=       0;
	ship6.ai.script.data			=       (unsigned char *)&scr_test6;

	MOVE_Reset(&ship6);
 	ship6.move.position.x			=       GRID2P(30);
	ship6.move.position.z			=       GRID2P(44);
	ship6.move.position.y			=       210;
  	
	ship6.attr                      =       &attrship_comp2;
	ship6.next_ship                 =       NO_SHIP_ID;

	shipdb[5]                       =       &ship6;

	/* default camera mode */
	myglobals.viewmode              =       VIEWMODE_FOLLOW;

	/* CAMERA INITIALIZATION */
	camera_Init             ( &mycam );
	camera_BackColour       ( &mycam, 60.f, 30.f, 10.f );
	camera_FogInstant       ( &mycam, -400.f, -3000.f );  /* 600,2200 */
	camera_FogColour        ( &mycam, 60.f, 30.f, 10.f );
	camera_FogOn            ( &mycam );
	
#ifndef USING_SET4
	/* debug only */
	time                                    =       GetCurrentTime();
#endif

	BLDLIGHTS_AnalysisMap();

	PDATABASE_AnalysisMap( &particle_database );

	/* initialize top of task list */
	explode_tasks			=       TASK_New();
	explode_tasks->life     =       -1;

    future_has_not_been_initialised = FALSE;

}



/*--------------------------------------------------------------------------

  static void     FUTURE_Kill(void)
 
  Parameters:
 
  Returns:
 
  Notes:
		Releases memory allocated, kills Ninja
  
  --------------------------------------------------------------------------*/

static void     FUTURE_Kill(void)
{
	int n;  
	
	njReleaseTextureAll();

	PDATABASE_Kill ( &particle_database );

	for (n=0;n<12;n++)
	{
		COLLIDE_Free(buildings[n].collide);
	}

	TASK_DeleteAll(explode_tasks);

	BLDLIGHTS_Kill(); 

}



/*--------------------------------------------------------------------------

  static void future_GetPeripheral(PERIPH_DATA *per)
 
  Parameters:
	per                     -               peripheral data definition
			this is legacy code from another project/programmer - not
			very good... using -100 to 100 range is not logical, captain...
  
  Returns:
	
  Notes:
	Takes the perfectly good peripheral data from Ninja and converts to
	a less good data structure...
 
  --------------------------------------------------------------------------*/

static void future_GetPeripheral(PERIPH_DATA *per)
{

	per->fire=0;
	per->pitch_up_down=0;
	per->yaw_left_right=0;
	per->strafe_left_right=0;
	per->open=0;

	if (per1->on & NJD_DGT_KL)      per->yaw_left_right=-100;
	if (per1->on & NJD_DGT_KR)      per->yaw_left_right=100;

	if (per1->on & NJD_DGT_KU)      per->pitch_up_down=-100;
	if (per1->on & NJD_DGT_KD)      per->pitch_up_down=100;

	if (per1->on & NJD_DGT_TB)      
	{
		per->fire=100;				/* why am I using fire for thrust?? */
#ifdef SOUND_ENABLE
		SOUND_ShipOn();
#endif
	}
	else
	{ 
#ifdef SOUND_ENABLE
		SOUND_ShipOff(); 
#endif  
	}
		
	if (per1->on & NJD_DGT_TC)
	{
		per->open=100;				/* why am I using open for fire??? */
	}
}


/*--------------------------------------------------------------------------

  Bool FUTURE_ProcessFutureWorld(void)
 
  Parameters:
	None
 
  Returns:
	TRUE    - This process has finished
	FALSE   - This process has NOT finished
 
  Notes:
		THIS IS OUR MAIN LOOP!!!
  --------------------------------------------------------------------------*/

Bool FUTURE_ProcessFutureWorld(void)
{
	int                             n;
	SHIP                    *ship;
	PERIPH_DATA             per;
	static          int lag         =       0;
	static          int     nlag    =       MAX_LAG;

	/* If this routine has not been run then initialize future world */
	if (future_has_not_been_initialised)
	{
		FUTURE_Init();
		return  FALSE;
	}
 
#ifdef ENABLE_LEVEDIT
	if (myglobals.user_mode==LEVEL_EDIT) myglobals.user_mode=LEVELEDIT_Main();
	else
	{
#endif

#ifdef ENABLE_DEBUG
		njPrintC(NJM_LOCATION(2,1),"FUTURISTIC : T. SZIRTES + I. NICHOLLS / SEGA EUROPE  (debug mode)");
#endif


		/* ---------------- UPDATE USER ----------------// */
#ifdef USING_SET4
		per1 = pdGetPeripheral(NJD_PORT_A0);
#else
		per1 = njGetPeripheral(NJD_PORT_SYSKEYBOARD);
#endif

#ifdef  ENABLE_LEVEDIT
		if (per1->on & NJD_DGT_TC) myglobals.user_mode=LEVEL_EDIT;
#endif

		TASK_ProcessAll(explode_tasks);
		
		/* Go through ship database */
		for (n=0;n<MAX_SHIPS;n++)
		{
			ship    =       shipdb[n];
			if (!(ship->flags&SHIP_FLAG_DISABLE))
			{
				/* Is ship controlled by user or by computer? */
				if (ship->flags&SHIP_FLAG_USER)
				{
					/* Get peripheral control from user */
					future_GetPeripheral(&per);
					
					if (per1->on & NJD_DGT_TX)                                                              
						myglobals.viewmode      =       VIEWMODE_INTERNAL;
					
					if (per1->on & NJD_DGT_TY)                                                              
						myglobals.viewmode      =       VIEWMODE_FIXED; 
					
					if ((per1->on & NJD_DGT_TX) && (per1->on & NJD_DGT_TY)) 
						myglobals.viewmode      =       VIEWMODE_EXTERNAL; 
					
					if (per1->on & NJD_DGT_TZ)                                                              
						myglobals.viewmode      =       VIEWMODE_FOLLOW; 
					
				}
				else
				{
					/* Get peripheral control from AI module */
					ACTION_Ship(ship, &per);
				}

				/* Apply peripheral control */
				MOVE_Calculate  (&per, ship);

				/* Check for collisions */
				ship->shield    =       MOVE_CheckCollision( ship );
				if (ship->shield!=0) ship->shield_anim=200;

				/* Check if shields are down */
				if ( ship->flags&SHIP_FLAG_SHIELDDOWN )                 ship->shield=0;

				/* Update position */
				MOVE_Update     (ship,(Uint8)n);
				
				/* defer fire detection till we have update alignment */
				if (ship->flags&SHIP_FLAG_USER)
				{
					if (per1->on & NJD_DGT_TA)
					{
						if (ship->fire_count > ship->reload)    
							ship->fire_count=0;
						Fire_fire(ship);
					}
				}
				
				/* ---------------- DRAW FROM USERS PERSPECTIVE -----------------// */

				if (ship->flags&SHIP_FLAG_VIEW)
				{
					
					/* ---------------- CALL PARTICLE GENERATORS ----------------// */
					

					/* --------------- CALCULATE CAMERA -------------------// */
					switch(myglobals.viewmode)
					{
					case (VIEWMODE_INTERNAL) :
					/* INTERNAL VIEW - the camera rolls, pans and moves with ship */
						camera_Pan                      (&mycam, NJM_DEG_ANG(ship->move.pitch), NJM_DEG_ANG(ship->move.yaw));
						camera_Roll                     (&mycam, NJM_DEG_ANG(-ship->move.roll));
						camera_MoveTo           (&mycam, ship->move.position.x, ship->move.position.y, ship->move.position.z );
						camera_Perspective      (60);  
						break;

					case (VIEWMODE_FIXED) :
					/* FIXED VIEW - the camera stay stationary and tracks the ship */
						camera_LookAt           (&mycam, ship->move.position.x, ship->move.position.y, ship->move.position.z );
						camera_Perspective      (80);  
						break;

					case (VIEWMODE_EXTERNAL) :
					/* EXTERNAL VIEW - the camera remain fixed slightly above and behind ship */
						camera_MoveTo           (&mycam, ship->move.position.x-(njSin(NJM_DEG_ANG(ship->move.yaw))*64.0f), 
						ship->move.position.y+12.f, ship->move.position.z-(njCos(NJM_DEG_ANG(ship->move.yaw))*64.0f));
						break;
/*22*/
					case (VIEWMODE_FOLLOW) :
					/* FOLLOW VIEW - the camera follows behind ship - following ships pass */
						camera_MoveTo           (&mycam, 
											ship->move.position.x-(njSin(NJM_DEG_ANG(ship->move.yaw+(ship->move.vel_yaw*12.0f)))*22.0f),
											ship->move.position.y+(njSin(NJM_DEG_ANG(-ship->move.pitch))*22.0f)+13.f,
											ship->move.position.z-(njCos(NJM_DEG_ANG(ship->move.yaw+(ship->move.vel_yaw*12.0f)))*22.0f) );
						camera_LookAt           (&mycam, 
											ship->move.position.x, 
											ship->move.position.y+6.f, 
											ship->move.position.z );
						camera_Perspective      (80);                           
						break;
					}
			
					/* use whatever view we have setup */

					camera_View                     (&mycam);
					Fire_update();
				
					DISPLAY_Map                     ( &map, 0 );


				}
				else
				{
				}
			}

		}

		/* Cheap and nasty effects - just thrown in - this is a spot light */
		r       =       1.f - ((float)(GenerateRandom()%45735))/65535.f;
		njSetLightIntensity     ( &flight, r, r, r); /*0.35f */
		argb.a          =       (float)r;
		argb.r          =       (float)(0.2f);
		argb.g          =       (float)(0.7f);
		argb.b          =       (float)(1.0f);
		njSetConstantMaterial( &argb );
		njPushMatrix(NULL);
			njTranslate(NULL,(33*128.f),0.f,(54*128.f));
			njDrawObject(object_test_stand_stand);
			sprite.tlist    =       &misc_texlist;
			sprite.tanim    =       ll_texanim;
			sprite.ang              =       0;
			sprite.p.x      =       0.f; 
			sprite.p.y      =       185.f; 
			sprite.p.z      =       0.f; 
			sprite.sx       =       r*(1.5f);
			sprite.sy       =       r*(1.5f);
			njDrawSprite3D( &sprite, 0, NJD_SPRITE_ANGLE | NJD_SPRITE_SCALE | NJD_SPRITE_COLOR | NJD_SPRITE_ALPHA );
		njPopMatrix(1);

		/* Cheap and nasty effects - just thrown in this is another spot light */
		njSetLightIntensity     ( &f2light, r, r, r); /*0.35f */
		argb.a          =       (float)r;
		argb.r          =       (float)(1.0f);
		argb.g          =       (float)(0.8f);
		argb.b          =       (float)(0.0f);
		njSetConstantMaterial( &argb );
		njPushMatrix(NULL);
			njTranslate(NULL,(27*128.f),0.f,(61*128.f));
			njDrawObject(object_test_stand_stand);
			sprite.tlist    =       &misc_texlist;
			sprite.tanim    =       ll_texanim;
			sprite.ang              =       0;
			sprite.p.x      =       0.f; 
			sprite.p.y      =       185.f; 
			sprite.p.z      =       0.f; 
			sprite.sx       =       r*(1.5f);
			sprite.sy       =       r*(1.5f);
			njDrawSprite3D( &sprite, 0, NJD_SPRITE_ANGLE | NJD_SPRITE_SCALE | NJD_SPRITE_COLOR | NJD_SPRITE_ALPHA );
		njPopMatrix(1);

		/* ---------------- UPDATE ENVIRONMENT -----------------// */
		
		/* Update lights */
		BLDLIGHTS_Update();

		light_int       +=      light_int_d;
		if (light_int >= 0.5f) light_int_d      =       -.005f;
		if (light_int <= 0.1f)  light_int_d     =       .005f;
		njSetLightIntensity( &tlight, 0.f, 0.f, light_int );

		
		/* Spin light? */
		njRotateLightY( &myglobals.light, NJM_DEG_ANG(0.2f) );
		/* Spin the building tops - don't forget to set EVAL flags enable rotation (bit 1 off) */
		object_building_L_1_spin[0].ang[1]              +=      NJM_DEG_ANG(3.0f);
		object_buildingK_buildingK_spin1[0].ang[1]      -=      NJM_DEG_ANG(1.0f);
		object_vehicles_shiphi3_shiphi3[0].ang[1]       += NJM_DEG_ANG(5.0f);
			
		/* draw backdrop */
		DISPLAY_Backdrop        ( &mycam );


#ifdef ENABLE_LEVEDIT
	}       
#endif

	/* ------------------ DEBUG INFORMATION ---------------------// */
#ifdef  ENABLE_DEBUG    
	njPrintD(NJM_LOCATION(2,57),_nj_calc_polygon_,8);
	njPrintC(NJM_LOCATION(12,57),"polygon");
    wframe++;
	if( GetCurrentTime() > (time + 5000) ) 
	{
		frame= wframe/5;
		wframe = 0;
		time = GetCurrentTime();
	}
	njPrintD(NJM_LOCATION(21,57),frame,2);
	njPrintC(NJM_LOCATION(24,57),"fps");
#endif  


	/* ------------------ EXIT CONDITION -----------------------// */

	if (per1->on & NJD_DGT_ST)
	{
		FUTURE_Kill();
		future_has_not_been_initialised = TRUE;
		return TRUE;
	}
	else
		return FALSE;
}
