/******************************************************************************************
	CRTEST PS   (c) 1999-2001 ISL

	fireworks.c:			Fireworks subgame code
******************************************************************************************/

#include "fireworks.h"

#include "global.h"
#include "main.h"
#include "menu.h"
#include "map_draw.h"
#include "bff_load.h"
#include "collide.h"
#include "debris.h"
#include "lights.h"
#include "timer.h"
#include "maths.h"
#include "overlays.h"
#include "fx.h"
#include "powerbar.h"

#include "puzzles.h"
#include "map_view.h"
#include "fixed.h"
#include "dualshock.h"
#include "subgame.h"
#include "demo.h"
#include "gametext.h"
#include "deth.h"
#include "map_play.h"
#include "card.h"
#include "sound.h"
#include "startup.h"
#include "pause.h"
#include "dcinc.h"


FIREWORK_DATA fwStruct;


#define FW_RUNOFF_YROT   2732

//debug
#ifdef FW_VIEW_STATES
char fwCollString[64] = "";
#endif


#define FW_COUNTDOWN_TIME	     80

#define FW_NUM_CHICKENS_BRONZE_SUCCESS  20
#define FW_NUM_CHICKENS_SILVER_SUCCESS  30
#define FW_NUM_CHICKENS_GOLD_SUCCESS    40



#ifdef DREAMCAST

int fireworksBoxDepth = 1000;
int fireworksWorldDepth = 500;
int fireworksFowlerBump = -1600;

#if PALMODE==1
int FW_CRICKET_X = -228;
int FW_CRICKET_Y = -110;
#else
int FW_CRICKET_X = -226;
int FW_CRICKET_Y = -98;
#endif

#else

#define fireworksBoxDepth 2

#if PALMODE==1
#define FW_CRICKET_X -228
#define FW_CRICKET_Y -110
#else
#define FW_CRICKET_X -226
#define FW_CRICKET_Y -98
#endif

#endif

 

VECTOR flapPos[FW_NUM_FLAPS] = 
{
	{10069, -2228, -6747},//FW_FLAP_DOOR
	{5645, -3204, -11121},//FW_FLAP_WINDOW_LEFT
	{592, -2984, -10986},//FW_FLAP_WINDOW_RIGHT
	{2108, -6072, -7756},//FW_FLAP_ROOF_RIGHT
	{7928, -5697, 1009},//FW_FLAP_ROOF_LEFT
	{-4568, -2213, -9111},//FW_FLAP_TYRE
};
	
#ifdef DEBUG


#endif

#define FW_FLAP1_XPOS -3126
#define FW_FLAP1_YPOS  0
#define FW_FLAP1_ZPOS  2255

#define FW_FLAP2_XPOS  5841
#define FW_FLAP2_YPOS  -45
#define FW_FLAP2_ZPOS  -11974

#define FW_FLAP3_XPOS  754
#define FW_FLAP3_YPOS  0
#define FW_FLAP3_ZPOS  -11235

#define FW_FLAP4_XPOS  -3284
#define FW_FLAP4_YPOS  0
#define FW_FLAP4_ZPOS  2307

#define FW_FLAP5_XPOS  -3011
#define FW_FLAP5_YPOS  60
#define FW_FLAP5_ZPOS  2212


#define FW_FLAP6_XPOS  -1901
#define FW_FLAP6_YPOS  360
#define FW_FLAP6_ZPOS  651


FIREWORK_DATA *fw;


#define FIRE_CAM_XPOS -5357
#define FIRE_CAM_YPOS -1397
#define FIRE_CAM_ZPOS  13563

//#define FIRE_GAR_XPOS -4974
//#define FIRE_GAR_YPOS -1510
//#define FIRE_GAR_ZPOS  12865

#define FW_START_YROT  280
#define FW_START_XROT  -650

#define FW_LAUNCH_START_YROT  280
#define FW_LAUNCH_START_XROT  80



//int FW_DRONE_START_XROT	= -650;


#define FW_DRONE_START_YROT  -340
#define FW_DRONE_START_XROT  0
#define FW_DRONE_INACTIVE_XROT  900



#define FW_START_XPOS  -4592
#define FW_START_YPOS  -797
#define FW_START_ZPOS  12369

extern int pause_levelplaying;

VECTOR fireworkGarib = {0, 0, 800};// {(FIRE_GAR_XPOS-FIRE_CAM_XPOS), (FIRE_GAR_YPOS-FIRE_CAM_YPOS), (FIRE_GAR_ZPOS-FIRE_CAM_ZPOS)};//  {405, -95, -682};

#define AIM_XROT_START	78
#define AIM_YROT_START	349

#ifdef DREAMCAST
#define FIREFOV            1000
#else
#define FIREFOV            800
#endif

#define FIRE_CAM_MAX_XROT  80
#define FIRE_CAM_MAX_YROT  300
#define FIRE_CAM_XINERTIA  54
#define FIRE_CAM_YINERTIA  58

#define FIRE_CAM_INV_POWER_FACTOR	356
#define FW_DRONE_GARIB_YPOS			1800
#define FW_DRONE_GARIB_ZPOS			1800
#define FW_GRAVITY					10
#define FW_DRONE_START_ZVEL			-900
#define FW_DRONE_START_YVEL			-150


short fwFlapTimers[FW_NUM_FLAPS] = {70, 79, 78, 77, 76, 75};

#define FW_FLAP_OPEN_TIME  100

#define FW_SPLAT_GRAVITY     12
#define FW_GROUND_LEVEL       0
#define FW_DRONE_RUNAWAY_VEL  1000



#define FLASH_COUNT_START	4
#define FW_FLASH_X			-28
#define FW_FLASH_Y			110
#define FW_FLASH_DEPTH		fireworksBoxDepth + 8


#define FIRE_CAM_DIGITAL_ACC  10

//ACTOR *myactor;

// ===================================================================================================
// ===================================================================== Controller related stuff ====

char *fireworksSounds[NUM_FIREWORKS_SAMPLES] =
{
	"fireworkfizz1", 		//SFX_FIREWORKS_LAUNCH	      	
	"fireworkpop2",  		//SFX_FIREWORKS_HIT				
	"firewrktravels",		//SFX_FIREWORKS_RUNBACK			
	"wind1",         		//SFX_FIREWORKS_WIND			
	"dropweights1",  		//SFX_FIREWORKS_THUD			
															
	"ing_argh_06",			//SFX_FIREWORKS_HIT1			
	"ing_ooph_01",			//SFX_FIREWORKS_HIT2			
	"ing_ooph_03",			//SFX_FIREWORKS_HIT3			
	"ing_ouch_03",			//SFX_FIREWORKS_HIT4			
	"ing_ouch_07",			//SFX_FIREWORKS_HIT5			
	"ing_wee_02a",			//SFX_FIREWORKS_WEE1			
	"ing_wee_06c",			//SFX_FIREWORKS_WEE2			
	"ing_wee_06i",			//SFX_FIREWORKS_WEE3			
	"ing_wee_10a",			//SFX_FIREWORKS_WEE4			
	"ing_wee_12c",			//SFX_FIREWORKS_WEE5			
	"ing_wee_16a",			//SFX_FIREWORKS_WEE6			
	"ing_wee_17a",			//SFX_FIREWORKS_WEE7			
															
	"whoosh01",				//SFX_FIREWORKS_WHOOSH1,		
	"whoosh02",				//SFX_FIREWORKS_WHOOSH2,		
	"whoosh03",				//SFX_FIREWORKS_WHOOSH3,		
	"whoosh04",				//SFX_FIREWORKS_WHOOSH4,		
	"whoosh05",				//SFX_FIREWORKS_WHOOSH5,		
	"yipee04",				//SFX_FIREWORKS_YIPEE,  		
															
	"crash03",				//SFX_FIREWORKS_CRASH1			
	"crash04",				//SFX_FIREWORKS_CRASH2			
//	"crash03",				//SFX_FIREWORKS_CRASH3			
//	"crash04",				//SFX_FIREWORKS_CRASH4			
//	"crash05",				//SFX_FIREWORKS_CRASH5			                      

};



void fireworksLoadsnd(int levelNum, SfxSampleType **pSamples, int arraySize)
{
	int i;

	ASSERT(pSamples);

	for(i=0; i<arraySize; i++)
		pSamples[i] = NULL;



	ASSERT(arraySize >= NUM_FIREWORKS_SAMPLES);

	for(i=0; i<NUM_FIREWORKS_SAMPLES; i++)
	{
		pSamples[i]	= sfxFindSampleInAllBanks(fireworksSounds[i]);

#ifdef DEBUG
		if(pSamples[i] == NULL)
			DB("fireworks pSamples[%d] not found\n",i);
#endif
		ASSERT(pSamples[i]);
	}


	fowlerSubGameSample[SFX_FOWLER_BRONZE] = sfxFindSampleInAllBanks("sub_fireworks_bronze");
	ASSERT(fowlerSubGameSample[SFX_FOWLER_BRONZE]);

	fowlerSubGameSample[SFX_FOWLER_SILVER] = sfxFindSampleInAllBanks("sub_fireworks_silver");
	ASSERT(fowlerSubGameSample[SFX_FOWLER_SILVER]);

	fowlerSubGameSample[SFX_FOWLER_GOLD] = sfxFindSampleInAllBanks("sub_fireworks_gold");
	ASSERT(fowlerSubGameSample[SFX_FOWLER_GOLD]);

	fowlerSubGameSample[SFX_FOWLER_FAIL] = sfxFindSampleInAllBanks("sub_fireworks_fail");
	ASSERT(fowlerSubGameSample[SFX_FOWLER_FAIL]);
}



// ===================================================================================================

void fireworksControls(void)
{					  
	VECTOR v;

/*
	if(pReadPad->digital[0] & PAD_R1)
	{
//		v.vx=0;
//		v.vy=0;
//		v.vz=-800;
		
//		i=-pReadPad->analogXS[0] >> 4;
//		j=pReadPad->analogYS[0]  >> 4;
		

		if(pReadPad->digital[0] & PAD_TRIANGLE)
			mycamera.vpy -= 40;

		if(pReadPad->digital[0] & PAD_CIRCLE)
			mycamera.vpy += 40;


//		fireworks.aimXRot += (j)/40;
//		fireworks.aimYRot += (i)/40;


//		RotateVector2DXYZ(&v, &v, fireworks.aimXRot, 0);		// then rotate around the X Axis
//		RotateVector2DXYZ(&v, &v, fireworks.aimYRot, 1);		// First rotate around the Y Axis

		
		if(pReadPad->digital[0] & PAD_SQUARE)
		{
			SCALEVECTOR(&v, 380);
			mycamera.vpx += v.vx;
			mycamera.vpy += v.vy;
			mycamera.vpz += v.vz;
		}

		if(pReadPad->digital[0] & PAD_CROSS)
		{
			SCALEVECTOR(&v, 380);
			mycamera.vpx -= v.vx;
			mycamera.vpy -= v.vy;
			mycamera.vpz -= v.vz;
		}
		
		
//		mycamera.vrx = mycamera.vpx + v.vx;						// Set the look-at point, relative
//		mycamera.vry = mycamera.vpy + v.vy;						// to the camera's position.
//		mycamera.vrz = mycamera.vpz + v.vz;						//

	}
	else if(pReadPad->digital[0] & PAD_R2)
	{


		if(pReadPad->analogYS[0] < -100)
		{
			myactor->position.vz -= pReadPad->analogYS[0]/40;
		}

		if(pReadPad->analogYS[0] > 100)
		{
			myactor->position.vz -= pReadPad->analogYS[0]/40;
		}

		if(pReadPad->analogXS[0] > 100)
		{	
			myactor->position.vx += pReadPad->analogXS[0]/40;
		}

		if(pReadPad->analogXS[0] < -100)
		{	
			myactor->position.vx += pReadPad->analogXS[0]/40;
		}

		if(pReadPad->digital[0] & PAD_TRIANGLE)
		{
			myactor->position.vy -= 60;
		}
		
		if(pReadPad->digital[0] & PAD_SQUARE)
		{
			myactor->position.vy += 60;
		}

		if(pReadPad->digital[0] & PAD_CIRCLE)
		{
			myactor->psiData.object->rotate.vy += 30;
		}

		if(pReadPad->digital[0] & PAD_CROSS)
		{
			myactor->psiData.object->rotate.vy -= 30;
		}
		
	}
	else
*/

		if(pReadPad->digital[0] & PAD_UP)
		{
			fw->camXRotSpeed -=	FIRE_CAM_DIGITAL_ACC;
		}
		else if(pReadPad->digital[0] & PAD_DOWN)
		{
			fw->camXRotSpeed += FIRE_CAM_DIGITAL_ACC;
		}
		else
		{
			fw->camXRotSpeed += pReadPad->analogYS[0] / FIRE_CAM_INV_POWER_FACTOR;
		}
		
		
		
		if(pReadPad->digital[0] & PAD_LEFT)
		{
			fw->camYRotSpeed -= FIRE_CAM_DIGITAL_ACC;
		}
		else if(pReadPad->digital[0] & PAD_RIGHT)
		{
			fw->camYRotSpeed += FIRE_CAM_DIGITAL_ACC;
		}
		else
		{
			fw->camYRotSpeed += pReadPad->analogXS[0] / FIRE_CAM_INV_POWER_FACTOR;
		}

		if(pReadPad->debounce[0] & PAD_CROSS)
			fwLaunchDrone();

}


// windy wobble. . .. . . . .
#define FW_CAM_X_WOBBLE_FREQ  60
#define FW_CAM_Y_WOBBLE_FREQ  80

#define FW_CAM_X_WOBBLE_SIZE  16
#define FW_CAM_Y_WOBBLE_SIZE  40


void fireworksUpdateCamera()
{
	int lastXRot, lastYRot;
	int xWobble, yWobble;
	VECTOR v;

	fw->cameraCount++;
	fw->cameraCount &= 4095;


	xWobble = rsin((fw->cameraCount * 4096)/FW_CAM_X_WOBBLE_FREQ);
	yWobble = rsin((fw->cameraCount * 4096)/FW_CAM_Y_WOBBLE_FREQ);

	xWobble = (FW_CAM_X_WOBBLE_SIZE * xWobble)>>12;
	yWobble = (FW_CAM_Y_WOBBLE_SIZE * yWobble)>>12;

	
	
	fw->camXRotSpeed = fw->camXRotSpeed * (FIRE_CAM_XINERTIA) /100;
	fw->camYRotSpeed = fw->camYRotSpeed * (FIRE_CAM_YINERTIA) /100;


	lastXRot = fw->camXRot;
	lastYRot = fw->camYRot;


	fw->camXRot += fw->camXRotSpeed;
	fw->camYRot -= fw->camYRotSpeed;


	if(fw->camXRot > FIRE_CAM_MAX_XROT)
		fw->camXRot = (FIRE_CAM_MAX_XROT + lastXRot)/2;
	if(fw->camXRot < -FIRE_CAM_MAX_XROT)
		fw->camXRot = (-FIRE_CAM_MAX_XROT + lastXRot)/2;

	if(fw->camYRot > FIRE_CAM_MAX_YROT)
		fw->camYRot = (FIRE_CAM_MAX_YROT + lastYRot)/2;

	if(fw->camYRot < -FIRE_CAM_MAX_YROT)
		fw->camYRot = (-FIRE_CAM_MAX_YROT + lastYRot)/2;
	
//#ifdef _WINDOWS // RFW, undoing the dreaded Healey "comment it out" PC conversion technique
	//RotateVector2DXYZ(&v, &fireworkGarib, /*xWobble + */fw->camXRot + FW_START_XROT, 0);
	//RotateVector2DXYZ(&v, &v, fw->camYRot /*+ yWobble*/ + FW_START_YROT, 1);
//#else
	RotateVector2DXYZ(&v, &fireworkGarib, xWobble + fw->camXRot + FW_START_XROT, 0);
	RotateVector2DXYZ(&v, &v, fw->camYRot + yWobble + FW_START_YROT, 1);
//#endif

//	RotateVector2DXYZ(&v, &fireworkGarib, fw->camYRot + FW_START_YROT, 1);
//	RotateVector2DXYZ(&v, &v, fw->camXRot + FW_START_XROT, 0);

//	mycamera.vrx = mycamera.vpx + v.vx;
//	mycamera.vry = mycamera.vpy + v.vy;
//	mycamera.vrz = mycamera.vpz + v.vz;

	mycamera.vrx = FW_START_XPOS + v.vx;
	mycamera.vry = FW_START_YPOS + v.vy;
	mycamera.vrz = FW_START_ZPOS + v.vz;


	//temp
	v.vx = 0;//FIRE_CAM_XPOS - FW_START_XPOS;
	v.vy = FW_DRONE_GARIB_YPOS;//FIRE_CAM_YPOS - FW_START_YPOS;
	v.vz = FW_DRONE_GARIB_ZPOS;//FIRE_CAM_ZPOS - FW_START_ZPOS;

	RotateVector2DXYZ(&v, &v, fw->camXRot + FW_START_XROT, 0);
	RotateVector2DXYZ(&v, &v, fw->camYRot + FW_START_YROT, 1);


	mycamera.vpx = FW_START_XPOS + v.vx;
	mycamera.vpy = FW_START_YPOS + v.vy;
	mycamera.vpz = FW_START_ZPOS + v.vz;

}


// ====================================================================================================
#define FW_RUN_START_YDELTA  1400
#define FW_DRONE_MAX_SPEED   120
#define FW_DRONE_RUNOFF_MAX_SPEED  90

void fireworksCycle(void)
{
	int i;
//	launchGame_Controls(&fireworks);
//	launchGame_MoveAim(&fireworks);
//	fireworksControls();


	// for pause
//	if(sfxGetSampleStatus(fw->pSamples[SFX_FIREWORKS_WIND]) == 0)
//	{
//		fw->windChannel = soundPlaySample(fw->pSamples[SFX_FIREWORKS_WIND], 0x8080, 0);
//	}

	sfxSetChannelVolume(fw->windChannel, 0x80, 0x80);


	fireworksUpdateCamera();



	dsEvent_Update();
	EXLIGHT_Update();


	if(fw->state != FW_STATE_FADEOUT)
		fireworksDronesUpdate();

	fireworksFlapsUpdate();
	fireworksUpdateEffects();

	fw->frameCount++;


	switch(fw->state)
	{
		case FW_STATE_FADEIN:
			break;

		case FW_STATE_RUNNING:

			fw->countdown--;

			fireworksControls();
		
			if(pReadPad->debounce[0] & PAD_START)
			{
				pause_levelplaying = LEVNUMBER_A2_FIREWORKS;
				pauseStart();
				return;
			}


#ifdef DEBUG
			if(SwimCheatCycle())
			{
				fw->countdown = 0;
				if(padData.digital[0] & PAD_L1)	// "L" is for "Lose"
				{
				}
				else if(padData.digital[0] & PAD_R1)	// "R" is for, ummm, "Really good win"
				{
					fw->numChickensSaved = FW_NUM_CHICKENS_GOLD_SUCCESS;
				}
				else
				{
					fw->numChickensSaved = FW_NUM_CHICKENS_BRONZE_SUCCESS;
				}
			}
#endif



			if(fw->countdown == 0)
			{
				fw->state = FW_STATE_FINISH;
				fwMakeDroneMoveAway();
			}

			if(fw->nextDrone < 0)
			{
				for(i=0; i<FW_NUM_DRONES; i++)
				{
					if(fw->drones[i].state == FW_DRONE_INACTIVE)
					{
					  fw->nextDrone = i;
					  break;
					}
				}
			}

			if((fw->drone < 0) && (fw->nextDrone >= 0))
			{
				fw->drone = fw->nextDrone;
				fw->drones[fw->nextDrone].state = FW_DRONE_JUMPINGON;

#ifdef _WINDOWS // RFW, undoing the dreaded Healey "comment it out" PC conversion technique
				//fw->drones[fw->nextDrone].xRotAim = FW_DRONE_START_XROT;// + FW_CHICK_XROT_FACTOR;
#else
				fw->drones[fw->nextDrone].xRotAim = FW_DRONE_START_XROT;// + FW_CHICK_XROT_FACTOR;
#endif


				actorAnimate(fw->drones[fw->nextDrone].actor, DRONE_DOWN_FLAPPING, FALSE, FALSE, 256, FALSE, 0);     
				actorAnimate(fw->drones[fw->nextDrone].actor, DRONE_LAND_ON_SEESAW, FALSE, TRUE, 256, FALSE, 0);     
				actorAnimate(fw->drones[fw->nextDrone].actor, DRONE_SEESAW_GULP, FALSE, TRUE, 256, FALSE, 0);        
				actorAnimate(fw->drones[fw->nextDrone].actor, DRONE_SEESAW_COVER_EYES, FALSE, TRUE, 256, FALSE, 0);  

				fw->drones[fw->nextDrone].actor->position.vx = FW_START_XPOS;
				fw->drones[fw->nextDrone].actor->position.vy = FW_START_YPOS + FW_RUN_START_YDELTA;
				fw->drones[fw->nextDrone].actor->position.vz = FW_START_ZPOS;


				fw->drones[fw->nextDrone].target.vx = FW_START_XPOS;
				fw->drones[fw->nextDrone].target.vy = FW_START_YPOS; 
				fw->drones[fw->nextDrone].target.vz = FW_START_ZPOS;

				fw->nextDrone = -1;
			}
			break;

		case FW_STATE_INTRO:
			if(pReadPad->debounce[0] & PAD_CROSS)
			{
				fw->state = FW_STATE_RUNNING;
					subGameRestart = FALSE;
			}
#ifdef DREAMCAST	
			else if(pReadPad->debounce[0] & PAD_CIRCLE)
#else
			else if(pReadPad->debounce[0] & PAD_TRIANGLE)
#endif
			{
				fw->frameCount = 1;
				fw->state = FW_STATE_FADEOUT;
				subGameRestart = FALSE;
				return;
			}


			break;

		case FW_STATE_FINISH:
			
			for(i=0; i<FW_NUM_DRONES; i++)
			{
				// slack but works
				if(fw->drones[i].state == FW_DRONE_ONDEVICE)
				{
					fwMakeDroneMoveAway();
				}

				
				if(fw->drones[i].state != FW_DRONE_INACTIVE)
					break;
			}

			if(i < FW_NUM_DRONES)
				break;

			if(fw->numChickensSaved >= FW_NUM_CHICKENS_BRONZE_SUCCESS)
			{
				if(gameCalledFrom != GAMECALLEDFROM_DEBUG)
				{
					gamePlayData->SubGameStates[SUBGAME_FIREWORKS] = REPLAY_BEATEN;
					gameSaveData.levels_available[REPLAY_AVAILABLE_FIREWORKS] = REPLAY_BEATEN;
				}
				// If you want to give the player some rewards give them here
				if(fw->numChickensSaved >= FW_NUM_CHICKENS_GOLD_SUCCESS)
				{
//					fowlerSetMedalSfx(SFX_FOWLER_GOLD);
					gameSaveData.medals_won[MEDAL_WON_FIREWORKS] = 3; 
					fw->state = FW_STATE_GOLD_SUCCESS;
					startFowler(GOLD);
					sound_XA_Start(TUNE_3_COMPLETE + SOUND_XA_NOLOOP);


				}
				else if(fw->numChickensSaved >= FW_NUM_CHICKENS_SILVER_SUCCESS)
				{
//					fowlerSetMedalSfx(SFX_FOWLER_SILVER);

					if(gameSaveData.medals_won[MEDAL_WON_FIREWORKS] < 2)
						gameSaveData.medals_won[MEDAL_WON_FIREWORKS] = 2; 
					fw->state = FW_STATE_SILVER_SUCCESS;
					startFowler(SILVER);
					sound_XA_Start(TUNE_3_COMPLETE + SOUND_XA_NOLOOP);
				}
				else if(fw->numChickensSaved >= FW_NUM_CHICKENS_BRONZE_SUCCESS)
				{
//					fowlerSetMedalSfx(SFX_FOWLER_BRONZE);
					if(gameSaveData.medals_won[MEDAL_WON_FIREWORKS] < 1) 
						gameSaveData.medals_won[MEDAL_WON_FIREWORKS] = 1; 
					fw->state = FW_STATE_BRONZE_SUCCESS;
					startFowler(BRONZE);
					sound_XA_Start(TUNE_3_COMPLETE + SOUND_XA_NOLOOP);
				}
			}
			else
			{
//				fowlerSetMedalSfx(SFX_FOWLER_FAIL);
				fw->state = FW_STATE_FAIL;
				startFowler(FAIL);
				sound_XA_Start(TUNE_4_FAILED + SOUND_XA_NOLOOP);
			}

			fw->frameCount = 2;


			break;

		case FW_STATE_BRONZE_SUCCESS:
		case FW_STATE_SILVER_SUCCESS:
		case FW_STATE_GOLD_SUCCESS:
		case FW_STATE_FAIL:

			makeFowlerSpeak();

			if(fw->frameCount > 30)
			{
				if(pReadPad->debounce[0] & PAD_CROSS)
				{
					fw->state = FW_STATE_FADEOUT;
					fw->frameCount = 1;
					subGameRestart = TRUE;

				}
#ifdef DREAMCAST
				else if(pReadPad->debounce[0] & PAD_CIRCLE)
#else
				else if(pReadPad->debounce[0] & PAD_TRIANGLE)
#endif
				{
					fw->state = FW_STATE_FADEOUT;
					fw->frameCount = 1;
					subGameRestart = FALSE;
				}
			}

			break;
		case FW_STATE_FADEOUT:
			if(subGameRestart == TRUE)
			{

				i= (fw->frameCount)*20;
				if(i >=255)
				{
					fireworksEnd();
					return;
				}
			}
			else
			{
				fireworksEnd();
				return;
			}
			break;
	}



	updateStopWatch();


	fireworksUpdateAnims();



}


void fireworksUpdateAnims()
{
	int i;

	for(i=0; i<FW_NUM_DRONES; i++)
	{
		if(fw->drones[i].state != FW_DRONE_INACTIVE)
		{
			actorMaintainAnimation(fw->drones[i].actor);
			actorMaintainAnimation(fw->drones[i].backPackActor);
		}
	}

	actorMaintainAnimation(fw->flaps[0].actor);
	actorMaintainAnimation(fw->flaps[1].actor);
	actorMaintainAnimation(fw->flaps[2].actor);
	actorMaintainAnimation(fw->flaps[3].actor);
	actorMaintainAnimation(fw->flaps[4].actor);
	actorMaintainAnimation(fw->flaps[5].actor);
}


#define  FW_RUNAWAY_XDELTA  2000
#define FW_RUNAWAY_YDELTA   400
#define FW_RUNAWAY_ZDELTA   300

// ====================================================================================================
void fwMakeDroneMoveAway()
{

	int i;

	for(i=0; i<FW_NUM_DRONES; i++)
	{
		if((fw->drones[i].state == FW_DRONE_ONDEVICE))
		{
			
			fw->drones[i].state = FW_DRONE_JUMPINGOFF;


			fw->drones[i].xRotAim = 0;//FW_DRONE_INACTIVE_XROT;// + FW_CHICK_XROT_FACTOR;
			fw->drones[i].yRotAim = FW_RUNOFF_YROT;//3072;

			//actorAnimate(fw->drones[i].actor, DRONE_DOWN_FLAPPING, TRUE, FALSE, 256, FALSE, 600);     
			actorAnimate(fw->drones[i].actor, DRONE_RUN_OFF_SCREAMING, TRUE, FALSE, 500, FALSE, 600);     

			fw->drones[i].target.vx = FW_START_XPOS + FW_RUNAWAY_XDELTA; 
			fw->drones[i].target.vy = FW_START_YPOS + FW_RUNAWAY_YDELTA;//_RUN_START_YDELTA; 
			fw->drones[i].target.vz = FW_START_ZPOS + FW_RUNAWAY_ZDELTA;
			return;
		}
	}
	// if no drone is on device add to countdown until one is on device

	fw->countdown = 1;

}



// ====================================================================================================
void fwLaunchDrone()
{
	// RFW - Random Poke fix, 4 Oct 00. "-1" happens if you fire lots of drones in a hurry.
	if(fw->drone == -1)
		return;

	if((fw->drones[fw->drone].state == FW_DRONE_ONDEVICE) && (fw->flyingDrone == -1))
	{
		fw->flashCount = FLASH_COUNT_START;

		fw->drones[fw->drone].state = FW_DRONE_LAUNCHING; // let droneupdate take care of vel etc
		fw->drone = -1;
	}
}



// ====================================================================================================

void fireworksDrawAimValues(void)
{
char strBuff[128];


#ifdef FW_VIEW_POS
	sprintf(strBuff, "cam pos: %d  %d  %d", mycamera.vpx, mycamera.vpy, mycamera.vpz);
	fontPrint(font, -250, -90, strBuff, 128, 128, 0);
	sprintf(strBuff, "garib  : %d %d %d", mycamera.vrx, mycamera.vry, mycamera.vrz);
	fontPrint(font, -250, -80, strBuff, 128, 128, 0);
	sprintf(strBuff, "actorPos: %d %d %d rot %d", myactor->position.vx, myactor->position.vy, myactor->position.vz, myactor->psiData.object->rotate.vy);
	fontPrint(font, -250, -70, strBuff, 128, 128, 0);

#endif

#ifdef FW_VIEW_STATES
	sprintf(strBuff, "drone1: %d %d, f%d", fw->drones[0].state, fw->drones[0].actor->psiData.object->rotate.vx, fw->drones[0].flap);
	fontPrint(font, -250, -90, strBuff, 128, 128, 0);

	sprintf(strBuff, "drone2: %d, f%d", fw->drones[1].state, fw->drones[1].flap);
	fontPrint(font, -250, -80, strBuff, 128, 128, 0);

	sprintf(strBuff, "drone3: %d, f%d", fw->drones[2].state, fw->drones[2].flap);
	fontPrint(font, -250, -70, strBuff, 128, 128, 0);

	sprintf(strBuff, "drone4: %d, f%d", fw->drones[3].state, fw->drones[3].flap);
	fontPrint(font, -250, -60, strBuff, 128, 128, 0);

	sprintf(strBuff, "drone %d, nextdrone %d",fw->drone, fw->nextDrone);
	fontPrint(font, -250, -50, strBuff, 128, 128, 0);

//	sprintf(strBuff, "colls %d",fwNumColls);
//	fontPrint(font, -250, -40, strBuff, 128, 128, 0);

	fontPrint(font, -250, -40, fwCollString, 128, 128, 0);


#endif				   


//	sprintf(strBuff, "Y Rotation : %i", fireworks.aimYRot);
//	fontPrint(font, -250, -50, strBuff, 128, 128, 0);
//	sprintf(strBuff, "X Rotation : %i", fireworks.aimXRot);
//	fontPrint(font, -250, -60, strBuff, 128, 128, 0);

//	sprintf(strBuff, "Analog XS : %i", padData.analogXS[0]);
//	fontPrint(font, -250, -30, strBuff, 128, 128, 0);
//	sprintf(strBuff, "Analog YS : %i", padData.analogYS[0]);
//	fontPrint(font, -250, -20, strBuff, 128, 128, 0);
}


#define FW_INRO_TEXT_XPOS  -130
#define FW_WINDOWFLAP_DRAWDISTANCE  7110

#define FW_WICK_DY		220
#define FW_WICK_SCALE	1024
#define FW_WICK_DCAM	200
//int FW_TYRE_DEPTH = 100;

#ifdef _WINDOWS	// RFW, I can't figure out what this variable's been added for.
	int var = 10000;
#endif

void fireworksDraw(void)
{
	int prev_lighting, i, temp;
	PSIMODELCTRL		*modctrl = &PSImodelctrl;

//	GsSetProjection(FIREFOV);

#ifdef DREAMCAST
	depthBump = fireworksWorldDepth;
#endif

	mapCamSetRefView2L(&mycamera);
	MapDraw_DrawFMA_World((FMA_WORLD2 *)mapview_fma_world);

	fireworksDrawAimValues();

	for(i=0; i<FW_NUM_DRONES; i++)
	{
		if(fw->drones[i].state != FW_DRONE_INACTIVE)
		{
			EXLIGHT_SetupActorLights(fw->drones[i].actor);
#ifdef _WINDOWS
			d2mActorDraw ( fw->drones[i].actor );
#else
			actorDraw(fw->drones[i].actor);
#endif
		}
	}




	//Gourad models
	prev_lighting = PSImodelctrl.lighting;
	PSImodelctrl.lighting = NOLIGHTING;



#ifdef DREAMCAST
	depthBump = fireworksWorldDepth - 1000;
	actorDraw(fw->flaps[0].actor);

	if(!fw->flaps[1].state)
		depthBump = fireworksWorldDepth - 2500;
	else
		depthBump = fireworksWorldDepth;
	actorDraw(fw->flaps[1].actor);			

	if(!fw->flaps[2].state)
		depthBump = fireworksWorldDepth - 2500;
	else
		depthBump = fireworksWorldDepth;
	actorDraw(fw->flaps[2].actor);
	depthBump = fireworksWorldDepth;
#else

	#ifdef _WINDOWS
		d2mActorDraw(fw->flaps[0].actor);

		temp = modctrl->depthoverride;
		modctrl->depthoverride = FW_WINDOWFLAP_DRAWDISTANCE;
		d2mActorDraw(fw->flaps[1].actor);
		d2mActorDraw(fw->flaps[2].actor);
		modctrl->depthoverride = temp;

	#else

		actorDraw(fw->flaps[0].actor);

		temp = modctrl->depthoverride;
		modctrl->depthoverride = FW_WINDOWFLAP_DRAWDISTANCE;
		actorDraw(fw->flaps[1].actor);
		actorDraw(fw->flaps[2].actor);
		modctrl->depthoverride = temp;
	#endif
#endif
#ifdef _WINDOWS
	d2mActorDraw(fw->flaps[3].actor);
	d2mActorDraw(fw->flaps[4].actor);
	d2mActorDraw(fw->flaps[5].actor);
#else
	actorDraw(fw->flaps[3].actor);
	actorDraw(fw->flaps[4].actor);
	actorDraw(fw->flaps[5].actor);
#endif


	temp = modctrl->depthoverride;

	// dodgy wheel
//	modctrl->depthoverride = FW_TYRE_DEPTH;
//	actorDraw(fw->flaps[5].actor);
//	modctrl->depthoverride = temp;

//	modctrl->depthoverride = 0;	// we're setting it for every drone anyway

	//fw->drones[0].backPackActor->position.vx = -4592;
	//fw->drones[0].backPackActor->position.vy = -797;
//	fw->drones[0].backPackActor->position.vz = -15000;
	//fw->drones[0].backPackActor->position.vz = (-fw->drones[0].actor->position.vz) - 3000;

	//fw->drones[0].backPackActor->position.vx = fw->drones[0].actor->position.vx;
	//fw->drones[0].backPackActor->position.vy = fw->drones[0].actor->position.vy;
	//fw->drones[0].backPackActor->position.vz = fw->drones[0].actor->position.vz;

/*	fw->drones[0].backPackActor->position.vx = 0;
	fw->drones[0].backPackActor->position.vy = -2000;
	fw->drones[0].backPackActor->position.vz = 7000;

	fw->drones[0].backPackActor->psiData.object->rotate.vx = 0;
	fw->drones[0].backPackActor->psiData.object->rotate.vy = 0;
	fw->drones[0].backPackActor->psiData.object->rotate.vz = 0;


	fw->drones[0].actor->position.vx = 0;
	fw->drones[0].actor->position.vy = -1000;
	fw->drones[0].actor->position.vz = 3000;
	fw->drones[0].actor->psiData.object->rotate.vx = 0;
	fw->drones[0].actor->psiData.object->rotate.vy = 100;
	fw->drones[0].actor->psiData.object->rotate.vz = 0;
*/
//		fw->drones[0].backPackActor->position.vz = (fw->drones[0].actor->position.vz) - 2100;
//		fw->drones[0].backPackActor->position.vy = (fw->drones[0].actor->position.vy) - 1000;

  	//d2mActorDraw(fw->drones[0].backPackActor);


	


	for(i=0; i<FW_NUM_DRONES; i++)
	{
		if((fw->drones[i].state == FW_DRONE_ONDEVICE)||(fw->drones[i].state == FW_DRONE_LAUNCHING)||(fw->drones[i].state == FW_DRONE_JUMPINGON))
		{
#ifdef DREAMCAST
			modctrl->depthoverride = 0;
#else
  #ifdef _WINDOWS // RFW, undoing the dreaded Healey "comment it out" PC conversion technique
			modctrl->depthoverride = 0;
  #else
			modctrl->depthoverride = 30;
  #endif
#endif


#ifdef _WINDOWS

			fw->drones[i].backPackActor->psiData.object->rotate.vx = 0;
			fw->drones[i].backPackActor->psiData.object->rotate.vy = 0;
			fw->drones[i].backPackActor->psiData.object->rotate.vz = 0;

			d2mActorDraw(fw->drones[i].backPackActor);
#else
			actorDraw(fw->drones[i].backPackActor);
#endif
			modctrl->depthoverride = temp;
		}
		else if((fw->drones[i].state != FW_DRONE_INACTIVE) && (fw->drones[i].state != FW_DRONE_BOUNCING))
		{
#if defined(_WINDOWS) || defined(DREAMCAST)
// This wasn't in the PSX version the last time a PSX programmer touched it. RFW, 5-oct-00
			modctrl->depthoverride = 0;
#endif

#ifdef _WINDOWS
			fw->drones[i].backPackActor->psiData.object->rotate.vx = 0;
			fw->drones[i].backPackActor->psiData.object->rotate.vy = 0;
			fw->drones[i].backPackActor->psiData.object->rotate.vz = 0;

			d2mActorDraw(fw->drones[i].backPackActor);
#else
			actorDraw(fw->drones[i].backPackActor);
#endif
		}
	}


	PSImodelctrl.lighting = prev_lighting;


#ifdef _WINDOWS
	{
		int oldXPos = stopWatchXPos;
		int oldYPos = stopWatchYPos;

		stopWatchXPos = 420;
		stopWatchYPos = 50;

		stopWatchXPosBack = 130;
		stopWatchYPosBack = -110;

		IDirect3DDevice7_SetRenderState ( g_pd3dDevice, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE );
		IDirect3DDevice7_SetRenderState ( g_pd3dDevice, D3DRENDERSTATE_ZWRITEENABLE, FALSE  );
		IDirect3DDevice7_SetRenderState ( g_pd3dDevice, D3DRENDERSTATE_ZFUNC, D3DCMP_NEVER  );
#endif

	if(fw->state == FW_STATE_RUNNING)
		drawStopWatch(4096 - ((4096*fw->countdown)/(FW_COUNTDOWN_TIME * FRAMESEC)));
	else							//*/
		drawStopWatch(0);

#ifdef _WINDOWS
		stopWatchXPos = oldXPos;
		stopWatchYPos = oldYPos;
	}
#endif

/*	if(fw->state == FW_STATE_RUNNING)
		drawStopWatch(4096 - ((4096*fw->countdown)/(FW_COUNTDOWN_TIME * FRAMESEC)));
	else
		drawStopWatch(0);*/


	switch(fw->state)
	{

		case FW_STATE_FADEIN:
			if(subGameRestart == TRUE)
			{
				i= 255 - (fw->frameCount)*20;
				if(i <= 0)
					fw->state = FW_STATE_INTRO;
				else
					deathScreenAdd(i, i, i, SEMITRANS_SUB, 2);
			}
			else
				fw->state = FW_STATE_INTRO;
			break;

		case FW_STATE_FINISH:
			fontPrint(font, FW_INRO_TEXT_XPOS + 60, 0, TEXTSTR(TEXTSTR_SUB_TIMES_UP), 128, 128 , 128);
			//carry on.. 
		
		case FW_STATE_RUNNING:
			drawCricketScores(FW_CRICKET_X, FW_CRICKET_Y, fw->numChickensSaved);
			break;

		case FW_STATE_INTRO:			
			fwDrawIntro();
			break;




		case FW_STATE_BRONZE_SUCCESS:
#ifdef _WINDOWS			// JH: Nice and simple fix, draw them the other way around and they work.
			fowlerDraw();
			fwDrawBronzeSuccess();
#else

			fwDrawBronzeSuccess();
  #ifdef DREAMCAST
			depthBump = fireworksFowlerBump;
  #endif
			fowlerDraw();
#endif

			break;




		case FW_STATE_SILVER_SUCCESS:

#ifdef _WINDOWS			// JH: Nice and simple fix, draw them the other way around and they work.
			fowlerDraw();
			fwDrawSilverSuccess();
#else

			fwDrawSilverSuccess();
  #ifdef DREAMCAST
			depthBump = fireworksFowlerBump;
  #endif
			fowlerDraw();
#endif

			break;



		case FW_STATE_GOLD_SUCCESS:
#ifdef _WINDOWS			// JH: Nice and simple fix, draw them the other way around and they work.
			fowlerDraw();
			fwDrawGoldSuccess();
#else

			fwDrawGoldSuccess();
  #ifdef DREAMCAST
			depthBump = fireworksFowlerBump;
  #endif
			fowlerDraw();
#endif
			break;



		case FW_STATE_FAIL:
#ifdef _WINDOWS			// JH: Nice and simple fix, draw them the other way around and they work.
			fowlerDraw();
			fwDrawFail();
#else

			fwDrawFail();
  #ifdef DREAMCAST
			depthBump = fireworksFowlerBump;
  #endif
			fowlerDraw();
#endif

			break;
		
//		case FW_STATE_FINISH:
//			fontPrint(font, FW_INRO_TEXT_XPOS + 60, 0, TEXTSTR(TEXTSTR_SUB_TIMES_UP), 128, 128 , 128);
//			break;

		case FW_STATE_FADEOUT:

			if(subGameRestart == TRUE)
			{

				i= (fw->frameCount)*20;
				if(i > 230)
					deathScreenAdd(255, 255, 255, SEMITRANS_SUB, 0);
				else
					deathScreenAdd(i, i, i, SEMITRANS_SUB, 0);
			}
			break;
	}
	
#ifdef DREAMCAST
	depthBump = 0;
#endif

	fireworksDrawEffects();


	for(i=0; i<FW_NUM_DRONES; i++)
	{
		if((fw->drones[i].state == FW_DRONE_ONDEVICE)||(fw->drones[i].state == FW_DRONE_JUMPINGON))
		{
			//draw wick
			VERT tempVert;

			tempVert.vx = fw->drones[i].backPackActor->position.vx - mycamera.vpx;
			tempVert.vy = fw->drones[i].backPackActor->position.vy - mycamera.vpy + FW_WICK_DY;
			tempVert.vz = fw->drones[i].backPackActor->position.vz - mycamera.vpz;


			fwMoveVertTowardsCamera2D(&tempVert, FW_WICK_DCAM);

			PrintFixedDepth3DSprite(fw->wick,&tempVert,FW_WICK_SCALE, 0x808080, 40);

		}
	}




#ifdef DEBUG
	
	if(padData.debounce[4] & PAD_CROSS)
		overlay_show_collision = (overlay_show_collision + 1) % N_DEBUG_OVERLAYS;

	if(padData.debounce[4] & PAD_TRIANGLE)
		overlay_show_collision = 0;


		overlayShowCollision();

#endif

		//debug


		if(fw->flashCount > 0)
		{
			unsigned int alpha;
			alpha =  ((0x101)*((fw->flashCount*200)/FLASH_COUNT_START));
			overlayAlphaSprite(fw->flash, FW_FLASH_X,FW_FLASH_Y- 2*(FLASH_COUNT_START - fw->flashCount), FW_FLASH_DEPTH,alpha);

			alpha =  ((0x10100)*((fw->flashCount*200)/FLASH_COUNT_START));
			overlayAlphaSprite(fw->flash, FW_FLASH_X - 5*(1+FLASH_COUNT_START - fw->flashCount) ,FW_FLASH_Y, FW_FLASH_DEPTH,alpha);

			alpha =  ((0x10000)*((fw->flashCount*200)/FLASH_COUNT_START));
			overlayAlphaSprite(fw->flash, FW_FLASH_X + 5*(1+FLASH_COUNT_START - fw->flashCount),FW_FLASH_Y, FW_FLASH_DEPTH,alpha);


			fw->flashCount--;
		}
//	}
}



//int FW_CHICK_XROT_FACTOR = 0;

#define FW_MAX_DRONE_THROUGHCOUNT 7

// ====================================================================================================
void fireworksFlapsUpdate()
{							     
	int i;

	
	for(i=0; i<FW_NUM_FLAPS; i++)
	{
	
		if(fw->flaps[i].actor == 0)
			continue;

		if(((fw->flaps[i].throughCount >= FW_MAX_DRONE_THROUGHCOUNT)||(i == fw->lastFlap)) && (fw->flaps[i].state == FW_FLAP_STATE_CLOSED))
			continue;


		if(fw->flaps[i].count-- <= 0)
		{

			if(fw->flaps[i].state == FW_FLAP_STATE_OPEN)
			{
				fw->flaps[i].state = FW_FLAP_STATE_CLOSED;
				actorAnimate(fw->flaps[i].actor, FW_FLAPS_CLOSE, FALSE, FALSE, 300, 0, 0);


				if(fw->flaps[i].throughCount >= FW_MAX_DRONE_THROUGHCOUNT)
					actorAnimate(fw->flaps[i].actor, FW_FLAPS_CLOSE_IDLE, FALSE, TRUE, 300, 0, 0);
				else
					actorAnimate(fw->flaps[i].actor, FW_FLAPS_CLOSE_IDLE, TRUE, TRUE, 300, 0, 0);

				fw->flaps[i].count = fwFlapTimers[i];
			}
			else //if(fw->flaps[i].state == FW_FLAP_STATE_CLOSED)
			{
				fw->flaps[i].state = FW_FLAP_STATE_OPEN;
				actorAnimate(fw->flaps[i].actor, FW_FLAPS_OPEN, FALSE, FALSE, 300, 0, 0);
				actorAnimate(fw->flaps[i].actor, FW_FLAPS_OPEN_IDLE, TRUE, TRUE, 300, 0, 0);

				fw->flaps[i].count = FW_FLAP_OPEN_TIME;
			}
		}
	
		
/*
		switch(fw->flaps[i].type)
		{
			
			case FW_FLAP_TYRE:
				break;

			case FW_FLAP_ROOF_RIGHT:
				break;

			case FW_FLAP_ROOF_LEFT:
				break;

			case FW_FLAP_WINDOW_RIGHT:
				break;

			case FW_FLAP_WINDOW_LEFT:
				break;

			case FW_FLAP_DOOR:
				break;

		}
*/
	}
}

#define FW_SPLAT_POPBACK	2000
#define FW_SHOOT_OFF_HEIGHT 100 //down
#define FW_BOUNCE_VEL_SCALE 50
#define FW_BOUNCE_VERTICAL  -8000
#define FW_BOUNCE_RANDOM_VEL  8000
#define FW_FLAP_OPENOFFSET   9500
#define FW_FLAP_CLOSEOFFSET  60000
int fireworksZReset = -17000;
// ====================================================================================================
void fireworksDronesUpdate()
{
	int i, dist, tempInt;
	VECTOR v;
	ANIM_ANIMATION *animation;

//	fwNumColls = 0;

	for(i=0; i<FW_NUM_DRONES; i++)
	{
		switch(fw->drones[i].state)
		{
			case FW_DRONE_INACTIVE:
				break;

			case FW_DRONE_JUMPINGON:

				SUBVECTOR(&v, &fw->drones[i].target, &fw->drones[i].actor->position);

				SCALEVECTOR(&v, 1000);
				dist = Magnitude(&v);

				if(dist < 64)
				{
					fw->drones[i].actor->position.vx = FW_START_XPOS;
					fw->drones[i].actor->position.vy = FW_START_YPOS;
					fw->drones[i].actor->position.vz = FW_START_ZPOS;
					fw->drones[i].state = FW_DRONE_ONDEVICE;
					break;
				}

				if(dist > FW_DRONE_MAX_SPEED)
				{
					SCALEVECTOR(&v, 4096*FW_DRONE_MAX_SPEED/dist);
				}

				ADDTOVECTOR(&fw->drones[i].actor->position, &v);
				break;

			case FW_DRONE_JUMPINGOFF:
				
				if(fw->drones[i].actor->psiData.object->rotate.vy != FW_RUNOFF_YROT)
					break;
				
				SUBVECTOR(&v, &fw->drones[i].target, &fw->drones[i].actor->position);

				SCALEVECTOR(&v, 1000);
				dist = Magnitude(&v);
				//DB("dist = %d\n", dist);

				if(dist < 64)
				{
					fw->drones[i].state = FW_DRONE_INACTIVE;
					break;
				}

				if(dist > (FW_DRONE_RUNOFF_MAX_SPEED))
				{
					SCALEVECTOR(&v, 2048*FW_DRONE_RUNOFF_MAX_SPEED/dist);
				}

				ADDTOVECTOR(&fw->drones[i].actor->position, &v);
				break;

			case FW_DRONE_ONDEVICE:
//				fw->drones[i].actor->psiData.object->rotate.vy = -fw->camYRot + FW_DRONE_START_YROT;
//				fw->drones[i].actor->psiData.object->rotate.vx = FW_DRONE_START_XROT;

				fw->drones[i].yRotAim = -fw->camYRot + FW_DRONE_START_YROT;
				fw->drones[i].actor->psiData.object->rotate.vy = -fw->camYRot + FW_DRONE_START_YROT;
				fw->drones[i].xRotAim = FW_DRONE_START_XROT;// + FW_CHICK_XROT_FACTOR;
				break;

			case FW_DRONE_LAUNCHING:
				v.vz = FW_DRONE_START_ZVEL;
				v.vy = FW_DRONE_START_YVEL;
				v.vx = 0;
				RotateVector2DXYZ(&v, &v, fw->camXRot + FW_LAUNCH_START_XROT, 0);
				RotateVector2DXYZ(&v, &v, fw->camYRot + FW_LAUNCH_START_YROT, 1);

				fw->drones[i].vel = v;

				ADDTOVECTOR(&fw->drones[i].actor->position, &fw->drones[i].vel);
				fw->drones[i].state = FW_DRONE_FLYING;

				//actorAnimate(fw->drones[i].actor, DRONE_MID_AIR_CYCLE,FALSE, FALSE, 400, 0, 800);
				actorAnimate(fw->drones[i].actor, DRONE_RUN_OFF_SCREAMING,TRUE, FALSE, 500, 0, 0);
				fw->flyingDrone = i;


				dsEvent_Add(1, 1, 1, 145, 0, 15, FALSE);
				//soundPlaySample(fw->pSamples[SFX_FIREWORKS_LAUNCH], 0xaaaa, 0);

				tempInt = SFX_FIREWORKS_WHOOSH1 + utilRandomInt(4);
				soundPlaySample(fw->pSamples[tempInt], 0xffff, 0);



				fw->drones[i].weeSample = -1;

				break;

			case FW_DRONE_FLYING:

				if(fw->drones[i].weeSample == -1)
				{
					fw->drones[i].weeSample	= utilRandomInt(6) + SFX_FIREWORKS_WEE1;
					soundPlaySample(fw->pSamples[fw->drones[i].weeSample], 0x9090, 0);
				}

				fw->drones[i].vel.vy += FW_GRAVITY;
				ADDTOVECTOR(&fw->drones[i].actor->position, &fw->drones[i].vel);

				if(fw->drones[i].vel.vy > 200)
				{
					DB("drone didn't collide with anything!!!\n");
					fw->drones[i].state = FW_DRONE_INACTIVE;
					fw->flyingDrone = -1;
					break;
				}


				dist = Magnitude2D(fw->drones[i].vel.vx, fw->drones[i].vel.vz);
				fw->drones[i].xRotAim = calc_angle(dist, -fw->drones[i].vel.vy)&4095;
				//fw->drones[i].xRotAim += FW_CHICK_XROT_FACTOR;
				
				if(fw->drones[i].xRotAim > 2047)
					fw->drones[i].xRotAim -= 4096;
			    
//				fwNumColls +
				if((dist = fireworksCollision(&fw->drones[i])) != FW_COLL_NONE)
				{

					// stop chicken weeeing
					sfxStopSample(fw->pSamples[fw->drones[i].weeSample], -1);
					//reset weeSample
					fw->drones[i].weeSample = -1;


					fw->flyingDrone = -1;
					switch(dist)
					{
						case FW_COLL_SPLAT:
							actorAnimate(fw->drones[i].actor, DRONE_SPLAT_ON_WALL, FALSE, FALSE, 300, 0, 1024);
							actorAnimate(fw->drones[i].actor, DRONE_DRIP_DOWN_WALL,FALSE, TRUE, 300, 0, 0);
							//actorAnimate(fw->drones[i].actor, DRONE_FALL_ON_BACK,FALSE, TRUE, 300, 0, 0);
							fw->drones[i].state = FW_DRONE_SPLATTING;
							fw->drones[i].vel.vx = 0;
							fw->drones[i].vel.vy = 0;
							fw->drones[i].vel.vz = 0;
							fw->drones[i].xRotAim = 0;
							//move actor back towards camera a bit
							fwMoveActorTowardsCamera(fw->drones[i].actor, FW_SPLAT_POPBACK);
							dsEvent_Add(0, 0, 1, 175, 0, 6, FALSE);
							soundPlaySample(fw->pSamples[SFX_FIREWORKS_HIT], 0xaaaa, 0);

   							break;
						case FW_COLL_BOUNCE:
							fw->drones[i].state = FW_DRONE_BOUNCING;
							dsEvent_Add(0, 0, 1, 175, 0, 5, FALSE);
							soundPlaySample(fw->pSamples[SFX_FIREWORKS_HIT], 0x9090, 0);
							fw->frameCount=0;
							fw->drones[i].weeSample = -1;

   							break;


						case FW_COLL_WINDOW:
							//fw->drones[i].state = FW_DRONE_LANDING;
							fw->drones[i].flap = fwFindWhichFlap(&fw->drones[i].actor->position);
//							fw->lastFlap = fw->drones[i].flap;
				
							animation = &fw->flaps[fw->drones[i].flap].actor->animation;

#ifdef FW_OUTPUT_FLAP_INFO


							DB("\n");
							switch(fw->drones[i].flap)
							{
								case FW_FLAP_DOOR:
									DB("DOOR\n");
									break;		  
								case FW_FLAP_WINDOW_LEFT:			  
									DB("WIN L\n");
									break;		  
								case FW_FLAP_WINDOW_RIGHT:		
									DB("WIN_R\n");
									break;		         
								case FW_FLAP_ROOF_RIGHT:
									DB("ROOF R\n");
									break;
								case FW_FLAP_ROOF_LEFT:
									DB("ROOF L\n");
									break;
								case FW_FLAP_TYRE:
									DB("TYRE\n");
									break;
							}




							if((fw->flaps[fw->drones[i].flap].actor->animation.animData[0].segment == FW_FLAPS_CLOSE))
							{
								DB(	"close frame offset %d\n", 256*animation->animData[0].scaledFrameOffset/animation->pSegments[FW_FLAPS_CLOSE].actualAnimLength);
							}

							if((fw->flaps[fw->drones[i].flap].actor->animation.animData[0].segment == FW_FLAPS_OPEN) )
							{
								DB(	"open frame offset %d\n", 256*animation->animData[0].scaledFrameOffset/animation->pSegments[FW_FLAPS_OPEN].actualAnimLength);
							}

							if((fw->flaps[fw->drones[i].flap].actor->animation.animData[0].segment == FW_FLAPS_OPEN_IDLE) )
							{
								DB(	"openidle frame offset %d\n", 256*animation->animData[0].scaledFrameOffset/animation->pSegments[FW_FLAPS_OPEN_IDLE].actualAnimLength);
							}

							if((fw->flaps[fw->drones[i].flap].actor->animation.animData[0].segment == FW_FLAPS_CLOSE_IDLE) )
							{
								DB(	"closeidle frame offset %d\n", 256*animation->animData[0].scaledFrameOffset/animation->pSegments[FW_FLAPS_CLOSE_IDLE].actualAnimLength);
							}

							if((fw->flaps[fw->drones[i].flap].actor->animation.animData[0].segment == -1))
							{
								DB("-1 segment\n");
							}


#endif
							if((animation->animData[0].segment == FW_FLAPS_CLOSE_IDLE)
								||((animation->animData[0].segment == FW_FLAPS_CLOSE) && ((256*animation->animData[0].scaledFrameOffset/animation->pSegments[FW_FLAPS_CLOSE].actualAnimLength) > FW_FLAP_CLOSEOFFSET))
								||((animation->animData[0].segment == FW_FLAPS_OPEN) &&	((256*animation->animData[0].scaledFrameOffset/animation->pSegments[FW_FLAPS_OPEN].actualAnimLength) < FW_FLAP_OPENOFFSET))
								)																							 
							{

								//not going through but allow this to reset lastFlap
								if(fw->lastFlap != fw->drones[i].flap)
									fw->lastFlap = -1;

								if((fw->drones[i].flap <= FW_FLAP_WINDOW_RIGHT) || (fw->drones[i].flap == FW_FLAP_TYRE))
								{
									actorAnimate(fw->drones[i].actor, DRONE_SPLAT_ON_WALL, FALSE, FALSE, 300, 0, 1024);
									actorAnimate(fw->drones[i].actor, DRONE_DRIP_DOWN_WALL,FALSE, TRUE, 300, 0, 0);
									//actorAnimate(fw->drones[i].actor, DRONE_FALL_ON_BACK,FALSE, TRUE, 300, 0, 0);
									fw->drones[i].state = FW_DRONE_SPLATTING;
									fw->drones[i].vel.vx = 0;
									fw->drones[i].vel.vy = 0;
									fw->drones[i].vel.vz = 0;
									fw->drones[i].xRotAim = 0;
								//move actor back towards camera a bit
									fwMoveActorTowardsCamera(fw->drones[i].actor, FW_SPLAT_POPBACK);
									dsEvent_Add(0, 0, 1, 175, 0, 6, FALSE);
									soundPlaySample(fw->pSamples[SFX_FIREWORKS_HIT], 0x9090, 0);


								}
								else
								{
									fw->drones[i].state = FW_DRONE_BOUNCING;
									fw->frameCount = 0;
								}
							}
							else		 // going through
							{


								fw->lastFlap = fw->drones[i].flap;

								fw->flaps[fw->drones[i].flap].throughCount++;

								// this to make sure the window stops flapping if it's closed for good
								if((animation->animData[0].segment == FW_FLAPS_CLOSE)&&(fw->flaps[fw->drones[i].flap].throughCount >= FW_MAX_DRONE_THROUGHCOUNT))
									actorAnimate(fw->flaps[fw->drones[i].flap].actor, FW_FLAPS_CLOSE_IDLE, FALSE, TRUE, 300, 0, 0);

								soundPlaySample(fw->pSamples[SFX_FIREWORKS_YIPEE], 0x7070, 0);
							
								dsEvent_Add(0, 0, 1, 100, 0, 7, FALSE);
								//soundPlaySample(fw->pSamples[SFX_FIREWORKS_HIT], 150, 0);

								fw->drones[i].state = FW_DRONE_LANDING;
								fw->numChickensSaved++;
							}
							break;
					}
					if(fw->drones[i].state == FW_DRONE_BOUNCING)
					{
						actorAnimate(fw->drones[i].actor, DRONE_SPLAT_ON_WALL, FALSE, FALSE, 300, 0, 1024);
						actorAnimate(fw->drones[i].actor, DRONE_DRIP_DOWN_WALL,FALSE, TRUE, 300, 0, 0);
						//actorAnimate(fw->drones[i].actor, DRONE_FALL_ON_BACK,FALSE, TRUE, 300, 0, 0);
						//fw->drones[i].state = FW_DRONE_SPLATTING;
						fw->drones[i].vel.vx = -fw->drones[i].actor->position.vx + random(FW_BOUNCE_RANDOM_VEL) - (FW_BOUNCE_RANDOM_VEL>>1);
						fw->drones[i].vel.vy = FW_BOUNCE_VERTICAL + random(FW_BOUNCE_RANDOM_VEL) - (FW_BOUNCE_RANDOM_VEL>>1);
						fw->drones[i].vel.vz = -fw->drones[i].actor->position.vz + random(FW_BOUNCE_RANDOM_VEL) - (FW_BOUNCE_RANDOM_VEL>>1);
						fw->drones[i].xRotAim = 0;
						//move actor back towards camera a bit
						fwMoveActorTowardsCamera(fw->drones[i].actor, FW_SPLAT_POPBACK);

						fw->drones[i].vel.vx += mycamera.vpx;//fw->drones[i].actor->position.vx;
						//fw->drones[i].vel.vy = 0;
						fw->drones[i].vel.vz += mycamera.vpz;//fw->drones[i].actor->position.vz;

						SCALEVECTOR(&fw->drones[i].vel, FW_BOUNCE_VEL_SCALE);
						
						fw->drones[i].vel.vx *= 2;
						fw->drones[i].vel.vz *= 2;

						fw->drones[i].actor->psiData.object->rotate.vy = fw->drones[i].yRotAim = calc_angle((-fw->drones[i].vel.vx), (-fw->drones[i].vel.vz))&4095;
						dsEvent_Add(0, 0, 1, 175, 0, 6, FALSE);
						soundPlaySample(fw->pSamples[SFX_FIREWORKS_HIT], 0x9090, 0);

						fw->drones[i].weeSample = -1;


					}
				}

				fireworksAddEffect(&fw->drones[i]);
				fireworksAddEffect(&fw->drones[i]);
				fireworksAddEffect(&fw->drones[i]);

				//DB("d=%d, y=%d, xRot = %d\n",dist, -fw->drones[i].vel.vy, fw->drones[i].xRotAim);
				break;


			case FW_DRONE_SPLATTING:

				if(fw->drones[i].weeSample == -1)
				{
					fw->drones[i].weeSample	= utilRandomInt(4) + SFX_FIREWORKS_HIT1;
					soundPlaySample(fw->pSamples[fw->drones[i].weeSample], 0x9090, 0);
				}


				fw->drones[i].vel.vy += FW_SPLAT_GRAVITY;
				fw->drones[i].actor->position.vy += fw->drones[i].vel.vy;

				if(fw->drones[i].actor->position.vy >= FW_GROUND_LEVEL)
				{
					fw->drones[i].actor->position.vy = FW_GROUND_LEVEL;
					actorAnimate(fw->drones[i].actor, DRONE_FALL_ON_BACK,FALSE, FALSE, 600, 0, 0);
					actorAnimate(fw->drones[i].actor, DRONE_GET_UP,FALSE, TRUE, 600, 0, 0);
					actorAnimate(fw->drones[i].actor, DRONE_RUN_OFF_SCREAMING, TRUE, TRUE, 300, 0, 0);

					soundPlaySample(fw->pSamples[SFX_FIREWORKS_THUD], 0x8080, 0);

					fw->drones[i].weeSample = -1;
					fw->drones[i].state = FW_DRONE_CRASHING;
				}
				break;


			case FW_DRONE_CRASHING:

				if(fw->drones[i].weeSample == -1)
				{
					fw->drones[i].weeSample	= utilRandomInt(4) + SFX_FIREWORKS_HIT1;
					soundPlaySample(fw->pSamples[fw->drones[i].weeSample], 0x9090, 0);
				}


				if(fw->drones[i].actor->animation.animData[0].segment == DRONE_RUN_OFF_SCREAMING)
				{
					fw->drones[i].state = FW_DRONE_RUNAWAY;
					fw->frameCount = 0;
					// set target pos here also?
					fw->drones[i].target.vx = FW_START_XPOS;
					fw->drones[i].target.vy = FW_GROUND_LEVEL + FW_SHOOT_OFF_HEIGHT;;
					fw->drones[i].target.vz = FW_START_ZPOS;

					SUBVECTOR(&fw->drones[i].vel, &fw->drones[i].target, &fw->drones[i].actor->position);
//					DB("\ndist %d %d %d\n", fw->drones[i].vel.vx, fw->drones[i].vel.vy, fw->drones[i].vel.vz);
					dist = Magnitude(&fw->drones[i].vel);
//					DB("dist=%d\n", dist);

//					DB(" x=%d z=%d\n",fw->drones[i].vel.vx, fw->drones[i].vel.vz);

					fw->drones[i].yRotAim = calc_angle((-fw->drones[i].vel.vx), (-fw->drones[i].vel.vz))&4095;//- -
					
					SCALEVECTOR(&fw->drones[i].vel, ((4096*FW_DRONE_RUNAWAY_VEL)/dist));

//					DB("rot =%d\n", fw->drones[i].yRotAim);
//					DB("vel %d %d %d\n", fw->drones[i].vel.vx, fw->drones[i].vel.vy, fw->drones[i].vel.vz);

				}
				break;

			case FW_DRONE_BOUNCING:
//			case FW_DRONE_CRASHING:

				if(fw->drones[i].weeSample == -1)
				{
					fw->drones[i].weeSample	= utilRandomInt(4) + SFX_FIREWORKS_HIT1;
					soundPlaySample(fw->pSamples[fw->drones[i].weeSample], 0x9090, 0);
				}


				if(fw->frameCount == 2)
				{
					//DB("bouncing\n");

					soundPlaySample(fw->pSamples[SFX_FIREWORKS_RUNBACK], 0x8080, 0);
				}

				fw->drones[i].vel.vy += FW_SPLAT_GRAVITY;
				ADDTOVECTOR(&fw->drones[i].actor->position, &fw->drones[i].vel);

				dist = Magnitude2D(fw->drones[i].vel.vx, fw->drones[i].vel.vz);
				fw->drones[i].xRotAim = (calc_angle(dist, -fw->drones[i].vel.vy)&4095)>>1;

				fireworksAddEffect(&fw->drones[i]);
				fireworksAddEffect(&fw->drones[i]);



				if(fw->drones[i].actor->position.vy >= FW_GROUND_LEVEL)
				{
//					fw->drones[i].actor->position.vy = FW_GROUND_LEVEL;
//					actorAnimate(fw->drones[i].actor, DRONE_FALL_ON_BACK,FALSE, FALSE, 600, 0, 0);
//					actorAnimate(fw->drones[i].actor, DRONE_GET_UP,FALSE, TRUE, 600, 0, 0);
//					actorAnimate(fw->drones[i].actor, DRONE_RUN_OFF_SCREAMING, TRUE, TRUE, 300, 0, 0);

	//				fw->drones[i].state = FW_DRONE_CRASHING;
					fw->drones[i].state = FW_DRONE_INACTIVE;

					tempInt = i % 2;

					switch(tempInt)
					{
						case 0:
							soundPlaySamplePanFade(fw->pSamples[SFX_FIREWORKS_CRASH1], 200, 0, &(fw->drones[i].actor->position));
							break;
						case 1:
							soundPlaySamplePanFade(fw->pSamples[SFX_FIREWORKS_CRASH2], 200, 0, &(fw->drones[i].actor->position));
							break;
					}
				}
				break;
			case FW_DRONE_LANDING:
				fw->drones[i].vel.vy += (3*FW_GRAVITY)/2;
				ADDTOVECTOR(&fw->drones[i].actor->position, &fw->drones[i].vel);

			//	DB("pos %d, %d\n", fw->drones[i].actor->position.vx, fw->drones[i].actor->position.vz);

				if((fw->drones[i].vel.vy > 200)||(fw->drones[i].actor->position.vz < fireworksZReset))
				//if(fw->drones[i].actor->position.vy > 500)
				{

//					fontPrint(font, 0, 0, "now", 200, 200, 200);
					fw->drones[i].actor->position.vx = FW_START_XPOS + 1000;
					fw->drones[i].actor->position.vy = FW_START_YPOS + FW_RUN_START_YDELTA;
					fw->drones[i].actor->position.vz = FW_START_ZPOS + 1000;


					fw->drones[i].state = FW_DRONE_INACTIVE;
					fw->drones[i].flap = -1;
				}
				break;

			case FW_DRONE_RUNAWAY:

				if(fw->frameCount == 1)
				{
					
					//DB("runaway\n");

					soundPlaySample(fw->pSamples[SFX_FIREWORKS_RUNBACK], 0x8080, 0);
				}

				fireworksAddEffect(&fw->drones[i]);
				fireworksAddEffect(&fw->drones[i]);

				ADDTOVECTOR(&fw->drones[i].actor->position, &fw->drones[i].vel);

//				dist = Magnitude2D(fw->drones[i].vel.vx, fw->drones[i].vel.vz);
//				fw->drones[i].xRotAim = (calc_angle(dist, -fw->drones[i].vel.vy)&4095)>>1;


				//DB("ra %d >? %d\n");
				if(fw->drones[i].actor->position.vz > fw->drones[i].target.vz)
				{
					fw->drones[i].state = FW_DRONE_INACTIVE;
					fw->drones[i].xRotAim = fw->drones[i].actor->psiData.object->rotate.vx = FW_DRONE_INACTIVE_XROT;
					//DB("ra end\n");
				}
				break;


			case FW_DRONE_STUMBLEAWAY:
				break;
		}


		if(fw->drones[i].state != FW_DRONE_INACTIVE)
		{

			if(fw->drones[i].actor->psiData.object->rotate.vy != fw->drones[i].yRotAim)
			{

				dist = fw->drones[i].yRotAim - fw->drones[i].actor->psiData.object->rotate.vy;
				fw->drones[i].actor->psiData.object->rotate.vy += (dist)/4;
				if((dist < 6) && (dist > -6))
				{
					fw->drones[i].actor->psiData.object->rotate.vy = fw->drones[i].yRotAim;
				}
			}

			if(fw->drones[i].actor->psiData.object->rotate.vx!= fw->drones[i].xRotAim)
			{
				dist = fw->drones[i].xRotAim - fw->drones[i].actor->psiData.object->rotate.vx;
				fw->drones[i].actor->psiData.object->rotate.vx += (dist)/4;
				if((dist < 6) && (dist > -6))
				{
					fw->drones[i].actor->psiData.object->rotate.vx = fw->drones[i].xRotAim;
				}
			}
		}

		// Set the rocket's position
		getWorldPosOfBone(fw->drones[i].actor, "UPPER TORSO", &fw->drones[i].backPackActor->position);

		fw->drones[i].backPackActor->psiData.object->rotate = fw->drones[i].actor->psiData.object->rotate;
		//fw->drones[i].backPackActor->psiData.object->rotate.vx -=  FW_CHICK_XROT_FACTOR;


		//fw->drones[i].backPackActor->position = fw->drones[i].actor->position;

//		if(fw->drones[i].rocket >= 0)
//			fw->rockets[fw->drones[i].rocket].actor->position = fw->drones[i].actor->position;

	}
}



// ====================================================================================================
int fwFindWhichFlap(VECTOR *pos)
{
	VECTOR v;
	int i, bestFlap=0;
	long dist, bestDistance = 99999999;

	for(i=0; i<FW_NUM_FLAPS; i++)
	{
		SUBVECTOR(&v, &flapPos[i], pos);
		dist = (v.vx*v.vx) + (v.vy*v.vy) + (v.vz*v.vz);

		if(dist<bestDistance)
		{
			bestDistance = dist;
			bestFlap = i;
		}
	}

	return bestFlap;
}

// ====================================================================================================
void fwMoveActorTowardsCamera(ACTOR* actor, int dist)
{
	VECTOR v;
	long m;

	v.vx =  mycamera.vpx - actor->position.vx;
	v.vy =  mycamera.vpy - actor->position.vy;
	v.vz =  mycamera.vpz - actor->position.vz;

	m = Magnitude(&v);
	SCALEVECTOR(&v, 4096*dist/m);
	ADDTOVECTOR(&actor->position, &v);
}


// =====================================================================================================
// cam is at 0 0 0
void fwMoveVertTowardsCamera2D(VERT *vert, int dist)
{
	VECTOR v;
	long m;

	v.vx =  - vert->vx;
	v.vy =  0;
	v.vz =  - vert->vz;

	m = Magnitude2D(vert->vx, vert->vz);
	SCALEVECTOR(&v, ((4096*dist)/m));
	
	vert->vx += v.vx;
	vert->vz += v.vz;
}

//------

#define FW_SPARKS_LIFETIME  10
#define FW_SPARKS_GRAVITY  5


#define FW_SPARKS_STARTSCALE  200
#define FW_SPARKS_ENDSCALE  200

#define FW_SPARK_VEL_FACTOR 4000
#define FW_SPARK_XRANDOM  100
#define FW_SPARK_YRANDOM  200

//VECTOR myspark = {-2317, -2162, 6622};

// ====================================================================================================
//void fireworksInitEffects()
//{
//
//}

// ====================================================================================================

void fireworksUpdateEffects()
{
	int i, tempInt;

	i= fw->sparks.oldestSpark;

	while(i!= fw->sparks.newSparkNum)
	{

		if(fw->sparks.lifetime[i]-- <= 0)
		{
			fw->sparks.oldestSpark = (i==(FW_NUMSPARKS-1)) ?  0:i+1;
		}
  		tempInt = 255 * fw->sparks.lifetime[i] / FW_SPARKS_LIFETIME;

		fw->sparks.colour[i] = tempInt;
		fw->sparks.colour[i] |= tempInt<<8;//((tempInt < 64) ? tempInt:64) << 8;
		fw->sparks.colour[i] |=  ((tempInt < 64) ? tempInt:64) << 16;
		fw->sparks.colour[i] |= (tempInt) << 24;

		fw->sparks.scale[i] = FW_SPARKS_ENDSCALE + tempInt * (FW_SPARKS_STARTSCALE - FW_SPARKS_ENDSCALE)/255;
		
		ADDTOVECTOR(&fw->sparks.pos[i], &fw->sparks.vel[i]);
		fw->sparks.vel[i].vy += FW_SPARKS_GRAVITY;


		i++;
		if(i==FW_NUMSPARKS) i=0;
	}
}


// ====================================================================================================
void fireworksDrawEffects()
{
	int i, j;
	VERT v;

	i= fw->sparks.oldestSpark;

	gte_SetRotMatrix(&GsWSMATRIX);
	gte_SetTransMatrix(&GsWSMATRIX);


	while(i!= fw->sparks.newSparkNum)
	{
		//overlayAlphaPoly(fw->sparks.texture, VECTOR *worldvecs, int n_verts, unsigned int bgr, int flags);
//		DB("%d, %d, %d\n", fw->sparks.pos[i].vx, fw->sparks.pos[i].vy, fw->sparks.pos[i].vz);

		v.vx = fw->sparks.pos[i].vx - mycamera.vpx;
		v.vy = fw->sparks.pos[i].vy - mycamera.vpy;
		v.vz = fw->sparks.pos[i].vz - mycamera.vpz;


		j = fw->frameCount % FW_SPARK_NUM_FRAMES;

		Print3DSelfAlphaSprite(fw->sparks.texture[j], &v, fw->sparks.scale[i], fw->sparks.colour[i]);///?
		i++;
		if(i==FW_NUMSPARKS) i=0;
	}
}
				 
// ====================================================================================================
void fireworksAddEffect(fireDrone *drone)
{
	int i = fw->sparks.newSparkNum;

	fw->sparks.pos[i].vx = (drone->backPackActor->position.vx) + random(FW_SPARK_XRANDOM) - FW_SPARK_XRANDOM/2;
	fw->sparks.pos[i].vy = (drone->backPackActor->position.vy) - random(FW_SPARK_YRANDOM);
	fw->sparks.pos[i].vz = (drone->backPackActor->position.vz) ;


//	fw->sparks.pos[i] = myspark;

	fw->sparks.vel[i].vx = -drone->vel.vx * FW_SPARK_VEL_FACTOR / 4096;
	fw->sparks.vel[i].vy = -drone->vel.vy * FW_SPARK_VEL_FACTOR / 4096;
	fw->sparks.vel[i].vz = -drone->vel.vz * FW_SPARK_VEL_FACTOR / 4096;

	fw->sparks.lifetime[i] = FW_SPARKS_LIFETIME;
	fw->sparks.scale[i] = FW_SPARKS_STARTSCALE;
	
	fw->sparks.newSparkNum++;
	if(fw->sparks.newSparkNum==FW_NUMSPARKS) fw->sparks.newSparkNum=0;
}



// ====================================================================================================
int fireworksCollision(fireDrone *drone)
{	
	int items_hit, i;
	VECTOR store, emptyvec;
	unsigned long flags;

#ifdef DREAMCAST
	drone->collision.pCollBox = enemyGlobals.pCollBoxes;
#endif

//	tweedy.collision_centre = -540;
	//drone.actor->position.vy -= FIREWORK_COLL_YOFFSET;

	drone->collision.pPos = &drone->actor->position;
	
	drone->collision.pVel = &emptyvec;//drone->vel;

	drone->collision.bounce = 0;
	drone->collision.radius = 4096 * 40;
	drone->collision.nBoxes = numCollBoxes;

	store = drone->actor->position;

	drone->actor->position.vy<<=9;				// scale the positions up by 512 
	drone->actor->position.vx<<=9;				// for the collision stuff to work
	drone->actor->position.vz<<=9;		


	drone->collision.oldPos = drone->actor->position;
	items_hit = collboxCheckSphere(&drone->collision);

	drone->actor->position.vy>>=9;				// scale the positions back down again
	drone->actor->position.vx>>=9; 
	drone->actor->position.vz>>=9;
	
	drone->actor->position = store;


//	tweedy.actor->position.vy+=tweedy.collision_centre;

	if(items_hit)
	{	
		flags = pHitData[0].pCollBox->flags;

		if(items_hit > 1)
		{
			for(i=1; i<items_hit; i++)
			{
				if( (((pHitData[i].pCollBox->flags) & ((1<<29)|(1<<28)))== 0))
				{
					//DB("HO\n");
					flags = pHitData[i].pCollBox->flags;
				}
			}
		}
		
		
		if((flags) & (1<<29))//left = vertical wall
		{


#ifdef FW_VIEW_STATES

			sprintf(fwCollString, "SPLAT .........SPLAT");
#endif
			return 	FW_COLL_SPLAT;

		}
		else if((flags) & (1<<28))//right	= roof/tree etc
		{
#ifdef FW_VIEW_STATES
			sprintf(fwCollString, ".......BOUNCE ....");
#endif
			return FW_COLL_BOUNCE;
		}
		else
		{
#ifdef FW_VIEW_STATES
			sprintf(fwCollString, "..FREEDOM................"); // noflag = window
#endif

			//DB("pos %d, %d, %d\n", drone->actor->position.vx, drone->actor->position.vy, drone->actor->position.vz);
			return FW_COLL_WINDOW;
		}
	}

	return FW_COLL_NONE;
}






// ====================================================================================================
/*
void fireWorksDrawSky()
{

	POLY_G4 *sky;				// A quad gouraud for the sky

	BEGINPRIM(sky, POLY_G4);
	setPolyG4(sky);				
	sky->x0 = -256;				
	sky->y0 = -128;
	
	sky->x1 = 256;
	sky->y1 = -128;
	
	sky->x2 = -256;
	sky->y2 = 128;
	
	sky->x3 = 256;
	sky->y3 = 128;

	sky->r0 = 10;
	sky->g0 = 20;
	sky->b0 = 70;

	sky->r1 = 10;
	sky->g1 = 20;
	sky->b1 = 70;

	sky->r2 = 120;
	sky->g2 = 100;
	sky->b2 = 40;

	sky->r3 = 120;
	sky->g3 = 100;
	sky->b3 = 40; 
	
	ENDPRIM(sky, 1023, POLY_G4);

}
*/

#define FW_CHICKENS_FREED_XPOS  -236

#ifdef DREAMCAST

#if PALMODE == 1
int FW_CHICKENS_FREED_YPOS = -116;
#else
int FW_CHICKENS_FREED_YPOS = -105;
#endif

#else

#if PALMODE == 1
  #define FW_CHICKENS_FREED_YPOS  -116
#else
  #define FW_CHICKENS_FREED_YPOS  -105
#endif

#endif



void fwDrawIntro()
{
	char string[400];

	sprintf(string, "%s\n\n%s\n\n%s\n%s\n\n%s",
		fontUpper((char*)TEXTSTR(TEXTSTR_NAME_OF_FIREWORKS)),

		(char*)TEXTSTR(TEXTSTR_SUB_FW_FIRE_CHICK),
		(char*)TEXTSTR(TEXTSTR_SUB_FIRE_CHICK),   
		(char*)TEXTSTR(TEXTSTR_SUB_SEESAW_AIM),   
		(char*)TEXTSTR(TEXTSTR_SUB_XSTART) 
	);

	fontPrintMultiLineBox(font, 0, 40, 340, string, 20, 30, 30);
}


//#define FW_OUTRO_TEXT_XPOS  -200
//#define FW_OUTRO_TEXT_MARGIN  20
//#define FW_OUTRO_TEXT_WIDTH  410

//------------------------------------------------
void fwDrawBronzeSuccess()
{

	char string[400];

	sprintf(string, "%s %d %s %s\n%s", (char*)TEXTSTR(TEXTSTR_SUB_SUBGAME_SAVED), fw->numChickensSaved, (char*)TEXTSTR(TEXTSTR_SUB_SUBGAME_CHICKENS), (char*)TEXTSTR(TEXTSTR_SUB_FIREWORKS_BRONZE), (char*)TEXTSTR(TEXTSTR_SUB_GAME_EXIT_RESTART));
	fontPrintMultiLineBoxSetDepth(font, 0, 0, 340, string, 20, 30, 30,fireworksBoxDepth);

}

//------------------------------------------------
void fwDrawSilverSuccess()
{

	char string[400];

	sprintf(string, "%s %d %s %s\n%s", (char*)TEXTSTR(TEXTSTR_SUB_SUBGAME_SAVED), fw->numChickensSaved, (char*)TEXTSTR(TEXTSTR_SUB_SUBGAME_CHICKENS), (char*)TEXTSTR(TEXTSTR_SUB_FIREWORKS_SILVER), (char*)TEXTSTR(TEXTSTR_SUB_GAME_EXIT_RESTART));
	fontPrintMultiLineBoxSetDepth(font, 0, 0, 340, string, 20, 30, 30,fireworksBoxDepth);

}

//------------------------------------------------
void fwDrawGoldSuccess()
{
	char string[400];

	sprintf(string, "%s %d %s %s\n%s", (char*)TEXTSTR(TEXTSTR_SUB_SUBGAME_SAVED), fw->numChickensSaved, (char*)TEXTSTR(TEXTSTR_SUB_SUBGAME_CHICKENS), (char*)TEXTSTR(TEXTSTR_SUB_FIREWORKS_GOLD), (char*)TEXTSTR(TEXTSTR_SUB_GAME_EXIT_RESTART));
	fontPrintMultiLineBoxSetDepth(font, 0, 0, 340, string, 20, 30, 30,fireworksBoxDepth);

}



//------------------------------------------------
void fwDrawFail()
{

	char string[400];

	if(fw->numChickensSaved == 40)				
			sprintf(string, "%s\n%s\n%s", (char*)TEXTSTR(TEXTSTR_SUB_FIREWORKS_NONE), (char*)TEXTSTR(TEXTSTR_SUB_FIREWORKS_FAIL), (char*)TEXTSTR(TEXTSTR_SUB_GAME_EXIT_RESTART));
	else if(fw->numChickensSaved == 1)
			sprintf(string, "%s\n%s\n%s", (char*)TEXTSTR(TEXTSTR_SUB_FIREWORKS_ONE), (char*)TEXTSTR(TEXTSTR_SUB_FIREWORKS_FAIL), (char*)TEXTSTR(TEXTSTR_SUB_GAME_EXIT_RESTART));
	else 									 
		sprintf(string, "%s %d %s %s\n%s", (char*)TEXTSTR(TEXTSTR_SUB_SUBGAME_SAVED), fw->numChickensSaved, (char*)TEXTSTR(TEXTSTR_SUB_SUBGAME_CHICKENS), (char*)TEXTSTR(TEXTSTR_SUB_FIREWORKS_FAIL), (char*)TEXTSTR(TEXTSTR_SUB_GAME_EXIT_RESTART));

	fontPrintMultiLineBoxSetDepth(font, 0, 0, 340, string, 20, 30, 30,fireworksBoxDepth);

}




// ====================================================================================================
void fireworksEnd(void)
{
	int i;

	sound_XA_Stop();
	sfxStopChannel(-1);


	if (fw->numChickensSaved > gameSaveData.best_chickens_rescued[RESCUELEVEL_FIREWORKS])
		gameSaveData.best_chickens_rescued[RESCUELEVEL_FIREWORKS]=fw->numChickensSaved;

	if (fw->numChickensSaved > gamePlayData->best_chickens_rescued_this_act[RESCUELEVEL_FIREWORKS])
		gamePlayData->best_chickens_rescued_this_act[RESCUELEVEL_FIREWORKS]=fw->numChickensSaved;



	if(subGameRestart == TRUE)
	{
		DB("*\n*\nreset called\n");
		fireworksReset();
	}
	else
	{

		fireworksFree();

		//DB("cat %d fire %d see %d\n",gameSaveData.best_chickens_rescued[RESCUELEVEL_CATAPULT],gameSaveData.best_chickens_rescued[RESCUELEVEL_FIREWORKS],gameSaveData.best_chickens_rescued[RESCUELEVEL_SEESAW]);

		memoryShowStats();
		memoryShow();

		act2SubgameComplete("A2_WORKHUT1");
	}


//	if(subGameRestart == TRUE)
//	{
//		fireworksStart();
//	}
//	else
//	{
//		act2SubgameComplete("A2_WORKHUT1");
//	}
}


void fireworksFree(void)
{
	int i;

	sfxStopChannel(fw->windChannel);

	mapviewReleaseMap();
	dsEvent_Init();

	for(i=0; i<FW_NUM_FLAPS; i++)
		actorFree(fw->flaps[i].actor);

	for(i=0; i<FW_NUM_DRONES; i++)
	{
		actorFree(fw->drones[i].actor);
		actorFree(fw->drones[i].backPackActor);
	}

	freeStopWatch();
	freeFowler();

//	FREE(fw);

	sound_XA_Stop();
	sound_LoadLanguageBank(gameTextLang);


}


#ifdef DREAMCAST

#if PALMODE==1
int FW_STOPWATCH_X = 164;
int FW_STOPWATCH_Y = -68;
#else
int FW_STOPWATCH_X = 164;
int FW_STOPWATCH_Y = -64;
#endif

#else

#if PALMODE==1
#define FW_STOPWATCH_X  164
#define FW_STOPWATCH_Y  -68
#else
#define FW_STOPWATCH_X  164
#define FW_STOPWATCH_Y  -64
#endif

#endif


/*	--------------------------------------------------------------------------------
	Function 	: 
	Purpose 	: 
	Parameters 	: 
	Returns 	: 
	Info 		:
*/
void fireworksStart()
{
	int i;
	subGameRestart = FALSE;

	overlayLoadingBegin(1);

#ifdef DEBUG
	memoryShowStats();
	memoryShow();
#endif


	//DB("1\n");



	fw = &fwStruct;//(FIREWORK_DATA*)MALLOC(sizeof(FIREWORK_DATA));
	memset(fw, 0, sizeof(FIREWORK_DATA));


	//DB("2\n");

	if(gameCalledFrom != GAMECALLEDFROM_DEBUG)
	{
		if(!gameSaveData.levels_available[REPLAY_AVAILABLE_FIREWORKS])
		{
			gameSaveData.levels_available[REPLAY_AVAILABLE_FIREWORKS] = REPLAY_NOTBEATEN;
		}
	}


	fw->flyingDrone = -1;

	fw->nextDrone = 3;


//	pReadPad->shockEnable=1;	// Need to go from the options screen now. Sorry. Fred
	dsEvent_Init();


	// ====
	// Setup the cycle and draw routines
	// ===
	draw_routine = fireworksDraw;
	cycle_routine = fireworksCycle;


	fw->countdown = FW_COUNTDOWN_TIME * FRAMESEC;


	//for reset
	for(i=0; i<FW_NUM_FLAPS; i++)
	{
		fw->flaps[i].throughCount = 0;
	}




	// ============
	// Load the world map that we'll be using
	// ============
	sound_FreeLanguageBank();
//	loadsndLoadBank("A2_FIREWORKS");
	sound_LoadLanguageBankBody(gameTextLang, "A2_FIREWORKS");	// Loads "a2_fireworks\\a2_fireworks_eng.sbb" (or other language versions)

	mapviewLoadMap("A2_FIREWORKS");			// Load the map we're going to use
#ifdef DREAMCAST
	// JIM : I've added this as the tune number in the level info seems to be wrong......
	sound_XA_Stop();
#endif

	//DB("3\n");


	setupCollision("A2_FIREWORKS");			// Setup the collision for the level map
	EXLIGHT_PostBFF();

//	dsEvent_Init();


//	loadsndSubGames(LEVNUMBER_A2_FIREWORKS, fw->pSamples, NUM_FIREWORKS_SAMPLES);
	fireworksLoadsnd(LEVNUMBER_A2_FIREWORKS, fw->pSamples, NUM_FIREWORKS_SAMPLES);

	//("4\n");


	overlayLoadingEnd();

	//DB("5\n");


	PSImodelctrl.farclip =  1023;
	max_map_ot_depth = 1023;


	mycamera.vpx = FIRE_CAM_XPOS;
	mycamera.vpy = FIRE_CAM_YPOS;
	mycamera.vpz = FIRE_CAM_ZPOS;

//	mycamera.vrx = FIRE_GAR_XPOS;
//	mycamera.vry = FIRE_GAR_YPOS;
//	mycamera.vrz = FIRE_GAR_ZPOS;


//	fw->troughModel	= BFF_IsModelLoaded("LAUNCHTROUGH");
//	ASSERT(fw->troughModel);
//	fw->troughActor = actorCreate(fw->troughModel);
//	ASSERT(fw->troughActor);


	//DB("6\n");


// -------- BACKPACK -------------------------------------

	fw->drones[0].backPackModel = BFF_IsModelLoaded("BAKPAK");
	ASSERT(fw->drones[0].backPackModel);
	fw->drones[0].backPackActor = actorCreate(fw->drones[0].backPackModel);
	ASSERT(fw->drones[0].backPackActor);

	fw->drones[1].backPackModel = BFF_IsModelLoaded("BAKPAK2");
	ASSERT(fw->drones[1].backPackModel);
	fw->drones[1].backPackActor = actorCreate(fw->drones[1].backPackModel);
	ASSERT(fw->drones[1].backPackActor);

	fw->drones[2].backPackModel = BFF_IsModelLoaded("BAKPAK");
	ASSERT(fw->drones[2].backPackModel);
	fw->drones[2].backPackActor = actorCreate(fw->drones[2].backPackModel);
	ASSERT(fw->drones[2].backPackActor);

	fw->drones[3].backPackModel = BFF_IsModelLoaded("BAKPAK2");
	ASSERT(fw->drones[3].backPackModel);
	fw->drones[3].backPackActor = actorCreate(fw->drones[3].backPackModel);
	ASSERT(fw->drones[3].backPackActor);

	
	//DB("7\n");


//-----------------


// -------- FLAPS ----------------------------------------


	//DB("a\n");

	fw->flaps[0].model = BFF_IsModelLoaded("DOOR01");
	ASSERT(fw->flaps[0].model);
	fw->flaps[0].actor = actorCreate(fw->flaps[0].model);
	ASSERT(fw->flaps[0].actor);

	
	fw->flaps[0].actor->position.vx = FW_FLAP1_XPOS;
	fw->flaps[0].actor->position.vy = FW_FLAP1_YPOS;
	fw->flaps[0].actor->position.vz = FW_FLAP1_ZPOS;
	fw->flaps[0].count = 10;

	fw->flaps[0].state = FW_FLAP_STATE_CLOSED;
	actorAnimate(fw->flaps[0].actor, FW_FLAPS_CLOSE, FALSE, FALSE, 300, 0, 0);
	actorAnimate(fw->flaps[0].actor, FW_FLAPS_CLOSE_IDLE, TRUE, TRUE, 300, 0, 0);


	//DB("b\n");


	fw->flaps[1].model = BFF_IsModelLoaded("WINDOW1");
	ASSERT(fw->flaps[1].model);
	fw->flaps[1].actor = actorCreate(fw->flaps[1].model);
	ASSERT(fw->flaps[1].actor);


	fw->flaps[1].actor->position.vx = FW_FLAP2_XPOS; 
	fw->flaps[1].actor->position.vy = FW_FLAP2_YPOS;
	fw->flaps[1].actor->position.vz = FW_FLAP2_ZPOS;
	fw->flaps[1].count = 45;


	fw->flaps[1].state = FW_FLAP_STATE_OPEN;
	actorAnimate(fw->flaps[1].actor, FW_FLAPS_OPEN, FALSE, FALSE, 300, 0, 0);
	actorAnimate(fw->flaps[1].actor, FW_FLAPS_OPEN_IDLE, TRUE, TRUE, 300, 0, 0);


	//DB("c\n");




	fw->flaps[2].model = BFF_IsModelLoaded("WINDOW1");
	ASSERT(fw->flaps[2].model);
	fw->flaps[2].actor = actorCreate(fw->flaps[2].model);
	ASSERT(fw->flaps[2].actor);

	fw->flaps[2].actor->position.vx = FW_FLAP3_XPOS; 
	fw->flaps[2].actor->position.vy = FW_FLAP3_YPOS;
	fw->flaps[2].actor->position.vz = FW_FLAP3_ZPOS;
	fw->flaps[2].count = 79;

	fw->flaps[2].state = FW_FLAP_STATE_CLOSED;
	actorAnimate(fw->flaps[2].actor, FW_FLAPS_CLOSE, FALSE, FALSE, 300, 0, 0);
	actorAnimate(fw->flaps[2].actor, FW_FLAPS_CLOSE_IDLE, TRUE, TRUE, 300, 0, 0);

	//DB("d\n");


	fw->flaps[3].model = BFF_IsModelLoaded("ROOFFLAP01");
	ASSERT(fw->flaps[3].model);
	fw->flaps[3].actor = actorCreate(fw->flaps[3].model);
	ASSERT(fw->flaps[3].actor);

	fw->flaps[3].actor->position.vx = FW_FLAP4_XPOS; 
	fw->flaps[3].actor->position.vy = FW_FLAP4_YPOS;
	fw->flaps[3].actor->position.vz = FW_FLAP4_ZPOS;
	fw->flaps[3].count = 90;


	fw->flaps[3].state = FW_FLAP_STATE_OPEN;
	actorAnimate(fw->flaps[3].actor, FW_FLAPS_OPEN, FALSE, FALSE, 300, 0, 0);
	actorAnimate(fw->flaps[3].actor, FW_FLAPS_OPEN_IDLE, TRUE, TRUE, 300, 0, 0);

	//DB("e\n");


	fw->flaps[4].model = BFF_IsModelLoaded("ROOFHATC01");
	ASSERT(fw->flaps[4].model);
	fw->flaps[4].actor = actorCreate(fw->flaps[4].model);
	ASSERT(fw->flaps[4].actor);

	fw->flaps[4].actor->position.vx = FW_FLAP5_XPOS; 
	fw->flaps[4].actor->position.vy = FW_FLAP5_YPOS;
	fw->flaps[4].actor->position.vz = FW_FLAP5_ZPOS;
	fw->flaps[4].count = 104;

	fw->flaps[4].state = FW_FLAP_STATE_CLOSED;
	actorAnimate(fw->flaps[4].actor, FW_FLAPS_CLOSE, FALSE, FALSE, 300, 0, 0);
	actorAnimate(fw->flaps[4].actor, FW_FLAPS_CLOSE_IDLE, TRUE, TRUE, 300, 0, 0);

	//DB("f\n");



	fw->flaps[5].model = BFF_IsModelLoaded("TYRE");
	ASSERT(fw->flaps[5].model);
	fw->flaps[5].actor = actorCreate(fw->flaps[5].model);
	ASSERT(fw->flaps[5].actor);

	fw->flaps[5].actor->position.vx = FW_FLAP6_XPOS; 
	fw->flaps[5].actor->position.vy = FW_FLAP6_YPOS;
	fw->flaps[5].actor->position.vz = FW_FLAP6_ZPOS;
	fw->flaps[5].count = 104;


	fw->flaps[5].state = FW_FLAP_STATE_OPEN;
	actorAnimate(fw->flaps[5].actor, FW_FLAPS_OPEN, FALSE, FALSE, 300, 0, 0);
	actorAnimate(fw->flaps[5].actor, FW_FLAPS_OPEN_IDLE, TRUE, TRUE, 300, 0, 0);

	//DB("g\n");


	
	
// -------- ROCKETS ---------------------------------------

/*
	fw->rockets[0].model = BFF_IsModelLoaded("ROCKET1");
	ASSERT(fw->rockets[0].model);
	fw->rockets[0].actor = actorCreate(fw->rockets[0].model);
	ASSERT(fw->rockets[0].actor);
	fw->rockets[0].drone = -1;

	fw->rockets[1].model = BFF_IsModelLoaded("ROCKET2");
	ASSERT(fw->rockets[1].model);
	fw->rockets[1].actor = actorCreate(fw->rockets[0].model);
	ASSERT(fw->rockets[1].actor);
	fw->rockets[1].drone = -1;


	fw->rockets[2].model = BFF_IsModelLoaded("ROCKET3");
	ASSERT(fw->rockets[2].model);
	fw->rockets[2].actor = actorCreate(fw->rockets[0].model);
	ASSERT(fw->rockets[2].actor);
	fw->rockets[2].drone = -1;

	fw->rockets[3].model = BFF_IsModelLoaded("ROCKET1");
	ASSERT(fw->rockets[3].model);
	fw->rockets[3].actor = actorCreate(fw->rockets[0].model);
	ASSERT(fw->rockets[3].actor);
	fw->rockets[3].drone = -1;
	
	fw->rockets[4].model = BFF_IsModelLoaded("ROCKET2");
	ASSERT(fw->rockets[4].model);
	fw->rockets[4].actor = actorCreate(fw->rockets[0].model);
	ASSERT(fw->rockets[4].actor);
	fw->rockets[4].drone = -1;
	
	fw->rockets[5].model = BFF_IsModelLoaded("ROCKET3");
	ASSERT(fw->rockets[5].model);
	fw->rockets[5].actor = actorCreate(fw->rockets[0].model);
	ASSERT(fw->rockets[5].actor);
	fw->rockets[5].drone = -1;

*/

// -------- DRONES  ----------------------------------------

	//DB("8\n");



	fw->drones[0].model = BFF_IsModelLoaded("DRONE1");
	ASSERT(fw->drones[0].model);
	fw->drones[0].actor = actorCreate(fw->drones[0].model);
	ASSERT(fw->drones[0].actor);
	actorInitAnim(fw->drones[0].actor);	
	ASSERT(fw->drones[0].actor);

	fw->drones[0].state = FW_DRONE_ONDEVICE;

	actorAnimate(fw->drones[0].actor, DRONE_DOWN_FLAPPING, FALSE, FALSE, 256, FALSE, 0);     
	actorAnimate(fw->drones[0].actor, DRONE_LAND_ON_SEESAW, FALSE, TRUE, 256, FALSE, 0);     
	actorAnimate(fw->drones[0].actor, DRONE_SEESAW_GULP, FALSE, TRUE, 256, FALSE, 0);        
	actorAnimate(fw->drones[0].actor, DRONE_SEESAW_COVER_EYES, FALSE, TRUE, 256, FALSE, 0);  


	fw->drones[0].actor->position.vx = FW_START_XPOS;
	fw->drones[0].actor->position.vy = FW_START_YPOS;
	fw->drones[0].actor->position.vz = FW_START_ZPOS;

	fw->drones[0].rocket = -1;



	fw->drones[1].model = BFF_IsModelLoaded("DRONE2");
	ASSERT(fw->drones[1].model);
	fw->drones[1].actor = actorCreate(fw->drones[1].model);
	ASSERT(fw->drones[1].actor);
	actorInitAnim(fw->drones[1].actor);	
	ASSERT(fw->drones[1].actor);

	fw->drones[1].state = FW_DRONE_INACTIVE;
	fw->drones[1].rocket = -1;


	fw->drones[2].model = BFF_IsModelLoaded("DRONE2");
	ASSERT(fw->drones[2].model);
	fw->drones[2].actor = actorCreate(fw->drones[2].model);
	ASSERT(fw->drones[2].actor);
	actorInitAnim(fw->drones[2].actor);	
	ASSERT(fw->drones[2].actor);
	fw->drones[2].state = FW_DRONE_INACTIVE;
	fw->drones[2].rocket = -1;


	fw->drones[3].model = BFF_IsModelLoaded("DRONE3");
	ASSERT(fw->drones[3].model);
	fw->drones[3].actor = actorCreate(fw->drones[3].model);
	ASSERT(fw->drones[3].actor);
	actorInitAnim(fw->drones[3].actor);	
	ASSERT(fw->drones[3].actor);

	fw->drones[3].state = FW_DRONE_INACTIVE;
	fw->drones[3].rocket = -1;



//	DB("9\n");


// ---------- TEXTURES  --------------------------------------

	fw->sparks.texture[0] = textureFindInAllBanks("SPARK1");
	ASSERT(fw->sparks.texture[0]);

	fw->sparks.texture[1] = textureFindInAllBanks("SPARK2");
	ASSERT(fw->sparks.texture[1]);

	fw->sparks.texture[2] = textureFindInAllBanks("SPARK3");
	ASSERT(fw->sparks.texture[2]);


	initStopWatch(FW_STOPWATCH_X, FW_STOPWATCH_Y, FIREFOV);
	initFowler(FIREFOV, SG_FIREWORKS);

	//DB("10\n");


//	nmeDogEnsureHourglass();
 	initCricketScores(FW_CRICKET_X, FW_CRICKET_Y, FW_NUM_CHICKENS_BRONZE_SUCCESS, FW_NUM_CHICKENS_SILVER_SUCCESS, FW_NUM_CHICKENS_GOLD_SUCCESS, 2);
		
	
	//("11\n");


	myactor = fw->flaps[5].actor;
//	myactor = fw->drones[0].actor;
//	myactor = fw->troughActor;

	fw->windChannel = soundPlaySample(fw->pSamples[SFX_FIREWORKS_WIND], 0x8080, 0);

	fw->wick = textureFindInAllBanks("WICK");
	ASSERT(fw->wick);
	fw->flash = textureFindInAllBanks("FW_FLASH");
	ASSERT(fw->flash);

	DEBRISDISTANCE = SUBGAME_DEBRISDISTANCE;

	GsSetProjection(FIREFOV);


#ifdef DREAMCAST
	// JIM : I've added this as the tune number in the level info seems to be wrong......
	sound_XA_Resume(TUNE_8_GOLF);
#endif

}
				  

/*	--------------------------------------------------------------------------------
	Function 	: 
	Purpose 	: resets all subgame parameters for restart
	Parameters 	: 
	Returns 	: 
	Info 		:
*/
void fireworksReset()
{
	int i;

#ifdef DREAMCAST
	// JIM : I've added this as the tune number in the level info seems to be wrong......
	sound_XA_Resume(TUNE_8_GOLF);
#endif


	fw->state = FW_STATE_FADEIN;
	fw->frameCount = 1;

	fw->flyingDrone = -1;
	fw->camXRot = fw->camXRotSpeed = fw->camYRot = fw->camYRotSpeed = 0;

	fw->nextDrone = 3;
	fw->numChickensSaved = 0;
	fw->cameraCount = 0;
	fw->drone = 0;

	dsEvent_Init();


	fw->countdown = FW_COUNTDOWN_TIME * FRAMESEC;

	//for reset
	for(i=0; i<FW_NUM_FLAPS; i++)
	{
		fw->flaps[i].throughCount = 0;
	}



	mycamera.vpx = FIRE_CAM_XPOS;
	mycamera.vpy = FIRE_CAM_YPOS;
	mycamera.vpz = FIRE_CAM_ZPOS;




// -------- FLAPS ----------------------------------------


	
	fw->flaps[0].actor->position.vx = FW_FLAP1_XPOS;
	fw->flaps[0].actor->position.vy = FW_FLAP1_YPOS;
	fw->flaps[0].actor->position.vz = FW_FLAP1_ZPOS;
	fw->flaps[0].count = 10;

	fw->flaps[0].state = FW_FLAP_STATE_CLOSED;
	actorAnimate(fw->flaps[0].actor, FW_FLAPS_CLOSE, FALSE, FALSE, 300, 0, 0);
	actorAnimate(fw->flaps[0].actor, FW_FLAPS_CLOSE_IDLE, TRUE, TRUE, 300, 0, 0);



	fw->flaps[1].actor->position.vx = FW_FLAP2_XPOS; 
	fw->flaps[1].actor->position.vy = FW_FLAP2_YPOS;
	fw->flaps[1].actor->position.vz = FW_FLAP2_ZPOS;
	fw->flaps[1].count = 45;


	fw->flaps[1].state = FW_FLAP_STATE_OPEN;
	actorAnimate(fw->flaps[1].actor, FW_FLAPS_OPEN, FALSE, FALSE, 300, 0, 0);
	actorAnimate(fw->flaps[1].actor, FW_FLAPS_OPEN_IDLE, TRUE, TRUE, 300, 0, 0);


	fw->flaps[2].actor->position.vx = FW_FLAP3_XPOS; 
	fw->flaps[2].actor->position.vy = FW_FLAP3_YPOS;
	fw->flaps[2].actor->position.vz = FW_FLAP3_ZPOS;
	fw->flaps[2].count = 79;

	fw->flaps[2].state = FW_FLAP_STATE_CLOSED;
	actorAnimate(fw->flaps[2].actor, FW_FLAPS_CLOSE, FALSE, FALSE, 300, 0, 0);
	actorAnimate(fw->flaps[2].actor, FW_FLAPS_CLOSE_IDLE, TRUE, TRUE, 300, 0, 0);

	fw->flaps[3].actor->position.vx = FW_FLAP4_XPOS; 
	fw->flaps[3].actor->position.vy = FW_FLAP4_YPOS;
	fw->flaps[3].actor->position.vz = FW_FLAP4_ZPOS;
	fw->flaps[3].count = 90;


	fw->flaps[3].state = FW_FLAP_STATE_OPEN;
	actorAnimate(fw->flaps[3].actor, FW_FLAPS_OPEN, FALSE, FALSE, 300, 0, 0);
	actorAnimate(fw->flaps[3].actor, FW_FLAPS_OPEN_IDLE, TRUE, TRUE, 300, 0, 0);


	fw->flaps[4].actor->position.vx = FW_FLAP5_XPOS; 
	fw->flaps[4].actor->position.vy = FW_FLAP5_YPOS;
	fw->flaps[4].actor->position.vz = FW_FLAP5_ZPOS;
	fw->flaps[4].count = 104;

	fw->flaps[4].state = FW_FLAP_STATE_CLOSED;
	actorAnimate(fw->flaps[4].actor, FW_FLAPS_CLOSE, FALSE, FALSE, 300, 0, 0);
	actorAnimate(fw->flaps[4].actor, FW_FLAPS_CLOSE_IDLE, TRUE, TRUE, 300, 0, 0);


	fw->flaps[5].actor->position.vx = FW_FLAP6_XPOS; 
	fw->flaps[5].actor->position.vy = FW_FLAP6_YPOS;
	fw->flaps[5].actor->position.vz = FW_FLAP6_ZPOS;
	fw->flaps[5].count = 104;


	fw->flaps[5].state = FW_FLAP_STATE_OPEN;
	actorAnimate(fw->flaps[5].actor, FW_FLAPS_OPEN, FALSE, FALSE, 300, 0, 0);
	actorAnimate(fw->flaps[5].actor, FW_FLAPS_OPEN_IDLE, TRUE, TRUE, 300, 0, 0);



	

// -------- DRONES  ----------------------------------------

	fw->drones[0].state = FW_DRONE_ONDEVICE;

	fw->drones[0].actor->position.vx = FW_START_XPOS;
	fw->drones[0].actor->position.vy = FW_START_YPOS;
	fw->drones[0].actor->position.vz = FW_START_ZPOS;

	fw->drones[0].rocket = -1;

	actorAnimate(fw->drones[0].actor, DRONE_SEESAW_GULP, FALSE, TRUE, 256, FALSE, 0);        
	actorAnimate(fw->drones[0].actor, DRONE_SEESAW_COVER_EYES, FALSE, TRUE, 256, FALSE, 0);  



	fw->drones[1].state = FW_DRONE_INACTIVE;
	fw->drones[1].rocket = -1;


	fw->drones[2].state = FW_DRONE_INACTIVE;
	fw->drones[2].rocket = -1;


	fw->drones[3].state = FW_DRONE_INACTIVE;
	fw->drones[3].rocket = -1;


//	myactor = fw->drones[0].actor;
//	myactor = fw->troughActor;

//never stops playing	fw->windChannel = soundPlaySample(fw->pSamples[SFX_FIREWORKS_WIND], 100, 0);

	DEBRISDISTANCE = SUBGAME_DEBRISDISTANCE;

    resetCricketScores();
	resetStopWatch();

	sound_XA_Start(levinfo->tune_number);

	fw->windChannel = soundPlaySample(fw->pSamples[SFX_FIREWORKS_WIND], 0x8080, 0);




}


/*	--------------------------------------------------------------------------------
	Function 	: 
	Purpose 	: 
	Parameters 	: 
	Returns 	: 
	Info 		:
*/
void fireworksRestart()
{
	subGameRestart = TRUE;
	fw->frameCount = 1;
	fw->state = FW_STATE_FADEOUT;
}


/*	--------------------------------------------------------------------------------
	Function 	: 
	Purpose 	: 
	Parameters 	: 
	Returns 	: 
	Info 		:
*/
void fireworksExit()
{
	fw->state = FW_STATE_FADEOUT;
	fw->frameCount = 1;
	subGameRestart = FALSE;
}