

#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 "engine.h"
#include "deth.h"
#include "demo.h"
#include "gametext.h"
#include "enemies.h"
#include "dualshock.h"
#include "map_view.h"
#include "card.h"
#include "map_play.h"
#include "sound.h"
#include "wings.h"
#include "subgame.h"
#include "startup.h"
#include "pause.h"

#include <islsfx2.h>
#include "sound.h"
#include "pause.h"

#ifdef _WINDOWS
	#include "pckeys.h"
#endif

extern int pause_levelplaying;

//#define ENG_DEBUGGING
#define ENG_COUNTDOWN_TIME 60


//#define ENG_VIEW_STATES
//#define ENG_VIEW_OILER


#define ENGINE_TIME_FOR_GOLD   500
#define ENGINE_TIME_FOR_SILVER 250

#ifdef DREAMCAST
int engineBoxDepth = 1000;
int engineWorldDepth = 500;
int engineFowlerBump = -1600;
#else
#define engineBoxDepth 2
#endif

// ==========================================================================================
FMA_WORLD	*engine_fma_world;
PSIMODEL	*model;
ACTOR		*cogbike,*pumper,*oiler,*rockytub,*cogs,*shaft,*engine;

ACTOR		*actPtr[4];
VECTOR		camlook,campos;

PSIOBJECT	*wheel,*cog1,*cog2,*cog3;

ENGINECTRL	engineCtrl;
TextureType	*woodBackDrop;
TextureType	*woodBackDropSelected;

TextureType	*mainGuage;
TextureType	*mainGuageAmount;
TextureType	*needle;
// ==========================================================================================



char *engineSounds[NUM_ENGINE_SAMPLES] =
{
	"bikesqueaks",		//	SFX_ENGINE_SQUEAKS	
	"levelfailed",		//	SFX_ENGINE_FAILED	
	"oilblob",			//	SFX_ENGINE_OIL		
	"pumper1",			//	SFX_ENGINE_PUMPER	
	"rocky_aaah",		//	SFX_ENGINE_AH		
	"running1",			//	SFX_ENGINE_RUNNING	
	"metsqueak03",		//	SFX_ENGINE_BADSQUEAK
	"swpoof",			//  SFX_ENGINE_CAMERA
};





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

	ASSERT(pSamples);

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

	ASSERT(arraySize >= NUM_ENGINE_SAMPLES);

	for(i=0; i<NUM_ENGINE_SAMPLES; i++)
	{
		pSamples[i]	= sfxFindSampleInAllBanks(engineSounds[i]);

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





//			pSamples[SFX_ENGINE_SQUEAKS]	= sfxFindSampleInAllBanks("bikesqueaks");
//			ASSERT(pSamples[SFX_ENGINE_SQUEAKS]);
//			pSamples[SFX_ENGINE_FAILED]		= sfxFindSampleInAllBanks("levelfailed");
//			ASSERT(pSamples[SFX_ENGINE_FAILED]);
//			pSamples[SFX_ENGINE_OIL]		= sfxFindSampleInAllBanks("oilblob");
//			ASSERT(pSamples[SFX_ENGINE_OIL]);
//			pSamples[SFX_ENGINE_PUMPER]		= sfxFindSampleInAllBanks("pumper1");
//			ASSERT(pSamples[SFX_ENGINE_PUMPER]);
//			pSamples[SFX_ENGINE_AH]			= sfxFindSampleInAllBanks("rocky_aaah");
//			ASSERT(pSamples[SFX_ENGINE_AH]);
//			pSamples[SFX_ENGINE_RUNNING]	= sfxFindSampleInAllBanks("running1");
//			ASSERT(pSamples[SFX_ENGINE_RUNNING]);

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

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

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

	fowlerSubGameSample[SFX_FOWLER_FAIL] = sfxFindSampleInAllBanks("sub_engine_fail");
	ASSERT(fowlerSubGameSample[SFX_FOWLER_FAIL]);

}

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

#define SAMPLE_VOL_MIN  100
#define SAMPLE_VOL_MAX  160
#define SAMPLE_PIT_MIN  100
#define SAMPLE_PIT_MAX  15000



#define ENGINE_X  -600
#define ENGINE_Y  -50 
#define ENGINE_Z   385


//int		testangle=0;

int		engineTicker=0;

//int		engineFOV=600;

VECTOR	targetPos[3]=
{
	{1170, -1000, 1019},
	{405, -1000, -478},
	{892, -1000, -1225},
};

VECTOR	targetLook[3]=
{
	{-56, -512, 477},
	{248, -512, -2064},
	{-515, -512, -1091},
};

#define ENGINE_FOV 450

void engineStart(void)
{
	overlayLoadingBegin(1);
	memset((void*)&engineCtrl,0, sizeof(ENGINECTRL));


	subGameRestart = FALSE;

	// ================================
	// Setup the draw and cycle routines
	// ================================
	draw_routine = engineDraw;
	cycle_routine = engineCycle;

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

//	psiInitialise(10);
//	psiAllocWorkspace();
//	actorInitialise();

	PSImodelctrl.farclip = 1024;
	//GsSetProjection(50);
	scenicInit();

//	loadsndLoadBank("A4_ENGINEHUT");
	sound_FreeLanguageBank();

	sound_LoadLanguageBankBody(gameTextLang, "A4_ENGINEHUT");	// Loads "A4_ENGINEHUT\\A4_ENGINEHUT_eng.sbb" (or other language versions)

	mapviewLoadMap("A4_ENGINEHUT");								
	setupCollision("A4_ENGINEHUT");	// not that its needed

	EXLIGHT_PostBFF();

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

//	loadsndSubGames(LEVNUMBER_A4_ENGINEHUT, engineCtrl.pSamples, NUM_ENGINE_SAMPLES);
	engineLoadsnd(LEVNUMBER_A4_ENGINEHUT, engineCtrl.pSamples, NUM_ENGINE_SAMPLES);

	overlayLoadingEnd();

//	DB("*\nengineCtrl.pSamples[SFX_ENGINE_RUNNING] = %d\n",engineCtrl.pSamples[SFX_ENGINE_RUNNING]);

	engineCtrl.loopSampleNum = -1;// no sound at the mo

	// Load and get pointers to the models and create the actors from them
	
	model = BFF_IsModelLoaded("COGBIKE");
	ASSERT(model);
	cogbike = actorCreate(model);
	ASSERT(cogbike);

	model = BFF_IsModelLoaded("PUMPER");
	ASSERT(model);
	pumper = actorCreate(model);
	ASSERT(pumper);

	model = BFF_IsModelLoaded("OILER");
	ASSERT(model);
	oiler = actorCreate(model);
	ASSERT(oiler);

	model = BFF_IsModelLoaded("ROCKYTUB");
	ASSERT(model);
	rockytub = actorCreate(model);
	ASSERT(rockytub);

	model = BFF_IsModelLoaded("GEAR");
	ASSERT(model);
	cogs = actorCreate(model);
	ASSERT(cogs);

	model = BFF_IsModelLoaded("SHAFT");
	ASSERT(model);
	shaft = actorCreate(model);
	ASSERT(shaft);

	model = BFF_IsModelLoaded("ENGINE");
	ASSERT(model);
	engine = actorCreate(model);
	ASSERT(engine);

	// Moved here to prevent null pointer access. Love, Fred -x-
	engine->position.vx=ENGINE_X;
	engine->position.vy=ENGINE_Y;
	engine->position.vz=ENGINE_Z;

//	nmeDogEnsureHourglass();

	engine_fma_world = (void *)BFF_FindObject(BFF_FMA_WORLD2_ID,utilStr2CRC("LNDMAP"));
	if(!engine_fma_world)
		engine_fma_world = (void *)BFF_FindObject(BFF_FMA_WORLD2_ID,0);
	ASSERT(engine_fma_world);

	wheel=psiObjectScan(cogbike->psiData.object,"COG");
	ASSERT(wheel);

	cog1=psiObjectScan(cogs->psiData.object,"GEAR01");
	ASSERT(cog1);
	cog2=psiObjectScan(cogs->psiData.object,"GEAR02");
	ASSERT(cog2);
	cog3=psiObjectScan(cogs->psiData.object,"GEAR03");
	ASSERT(cog3);


	engineCtrl.icons[0] = textureFindInAllBanks("TUB_ICON");
	ASSERT(engineCtrl.icons[0]);
	engineCtrl.icons[1] = textureFindInAllBanks("GEAR_ICON");
	ASSERT(engineCtrl.icons[1]);
	engineCtrl.icons[2] = textureFindInAllBanks("ENG_ICON");
	ASSERT(engineCtrl.icons[2]);


	woodBackDrop=textureFindInAllBanks("BARBACK");
	ASSERT(woodBackDrop);

	woodBackDropSelected=textureFindInAllBanks("BARBACK2");
	ASSERT(woodBackDropSelected);

	
	mainGuage=textureFindInAllBanks("MAINGUAGE");
	//mainGuage=textureFindInAllBanks("TEMPFONTMESSAGE");
	ASSERT(mainGuage);

	mainGuageAmount=textureFindInAllBanks("MAINGUAGEBAR");
	ASSERT(mainGuageAmount);

	needle=textureFindInAllBanks("NEEDLE");
	ASSERT(needle);

	actPtr[0]=oiler;
	actPtr[1]=pumper;
	actPtr[2]=cogbike;
	actPtr[3]=rockytub;


	pumper->position.vx=416;
	pumper->position.vy=0;
	pumper->position.vz=-2504;
	pumper->psiData.object->rotate.vy=2048;

	oiler->position.vx=-100;
	oiler->position.vy=0;
	oiler->position.vz=550;
	oiler->psiData.object->rotate.vy=1024;

	cogbike->position.vx=-765;
	cogbike->position.vy=0;
	cogbike->position.vz=-1352;
	cogbike->psiData.object->rotate.vy=2048;

	rockytub->position.vx=-80;
	rockytub->position.vy=-100;
	rockytub->position.vz=-2150;
	rockytub->psiData.object->rotate.vy=2600;

	cogs->position.vx=-640;
	cogs->position.vy=-130;
	cogs->position.vz=-775;
	cogs->psiData.object->rotate.vy=0;

	shaft->position.vx=-615;
	shaft->position.vy=-265;
	shaft->position.vz=-140;
	//shaft->psiData.object->rotate.vy=2048;

	engine->position.vx=ENGINE_X;
	engine->position.vy=ENGINE_Y;
	engine->position.vz=ENGINE_Z;
	engine->psiData.object->rotate.vy = 1024;
	//engine->psiData.object->rotate.vy=1024;


	actorAnimate(pumper, PUMP_SLOW_PUMP, 1, 0, 256, 1, 0);
	actorAnimate(oiler, OILER_IDLE_CHECK_WATCH, 0, 0, 256, 1, 0);
	actorAnimate(cogbike, COG_LOOK_ROUND, 0, 0, 256, 1, 0);
	actorAnimate(rockytub, RELAX_IDLE, 1, 0, 256, 1, 0);


	actorAnimate(cogs, 0, 1, 0, 256, 1, 0);
	actorAnimate(engine, 0, 1, 0, 256, 1, 0);

	camlook.vx=targetLook[2].vx;
	camlook.vy=targetLook[2].vy;
	camlook.vz=targetLook[2].vz;

	campos.vx=targetPos[2].vx;
	campos.vy=targetPos[2].vy;
	campos.vz=targetPos[2].vz;

	engineCtrl.gameState = ENGINE_FADEIN;

	engineCtrl.active=COGBIKE_ACTIVE;
	//camlook.vx=cogbike->position.vx;
	//camlook.vy=cogbike->position.vy-512;
	//camlook.vz=cogbike->position.vz;

	engineCtrl.target.vx=engineCtrl.oldTarget.vx=camlook.vx;
	engineCtrl.target.vy=engineCtrl.oldTarget.vy=camlook.vy;
	engineCtrl.target.vz=engineCtrl.oldTarget.vz=camlook.vz;

	engineCtrl.camPos.vx=engineCtrl.oldCamPos.vx=campos.vx;
	engineCtrl.camPos.vy=engineCtrl.oldCamPos.vy=campos.vy;
	engineCtrl.camPos.vz=engineCtrl.oldCamPos.vz=campos.vz;

	engineCtrl.justChangedFlag=FALSE;

	engineCtrl.bikerSpeed=0;
	engineCtrl.pumperSpeed=200;	// rocky starts with bubbles
	engineCtrl.oilerSpeed=0;

	engineCtrl.bikerCurrentAction=ACTION_BIKER_IDLE;
	engineCtrl.bikerLastAction=ACTION_BIKER_IDLE;

	engineCtrl.oilerCurrentAction=ACTION_OILER_IDLE;
	engineCtrl.oilerLastAction=ACTION_OILER_IDLE;

	engineCtrl.oilerAng=3000;
	engineCtrl.gauge=-512;
	engineCtrl.gameTimer=ENG_COUNTDOWN_TIME * FRAMESEC; // 2 mins at 25 ticks per second
	engineCtrl.gameState=ENGINE_FADEIN;

	GsSetProjection(ENGINE_FOV);

#ifdef DREAMCAST
	engineCtrl.texture[ENG_SQUARE] = textureFindInAllBanks("X_BUTTON");//x
	ASSERT(engineCtrl.texture[ENG_SQUARE]);

	engineCtrl.texture[ENG_CROSS] = textureFindInAllBanks("A_BUTTON");		//a
	ASSERT(engineCtrl.texture[ENG_CROSS]);

	engineCtrl.texture[ENG_CIRCLE] = textureFindInAllBanks("B_BUTTON");	   //b
	ASSERT(engineCtrl.texture[ENG_CIRCLE]);

	engineCtrl.texture[ENG_TRIANGLE] = textureFindInAllBanks("Y_BUTTON");	  //y
	ASSERT(engineCtrl.texture[ENG_TRIANGLE]);

	engineCtrl.inTexture[ENG_SQUARE] = textureFindInAllBanks("X_BUTTONIN"); //x
	ASSERT(engineCtrl.inTexture[ENG_SQUARE]);

	engineCtrl.inTexture[ENG_CROSS] = textureFindInAllBanks("A_BUTTONIN");	  //a
	ASSERT(engineCtrl.inTexture[ENG_CROSS]);

	engineCtrl.inTexture[ENG_CIRCLE] = textureFindInAllBanks("B_BUTTONIN"); //b
	ASSERT(engineCtrl.inTexture[ENG_CIRCLE]);

	engineCtrl.inTexture[ENG_TRIANGLE] = textureFindInAllBanks("Y_BUTTONIN");//y
	ASSERT(engineCtrl.inTexture[ENG_TRIANGLE]);
#else
	#ifdef _WINDOWS
		engineCtrl.texture[ENG_SQUARE] = textureFindInAllBanks("PCBUT_4");
		ASSERT(engineCtrl.texture[ENG_SQUARE]);

		engineCtrl.texture[ENG_CROSS] = textureFindInAllBanks("PCBUT_3");
		ASSERT(engineCtrl.texture[ENG_CROSS]);

		engineCtrl.texture[ENG_CIRCLE] = textureFindInAllBanks("PCBUT_2");
		ASSERT(engineCtrl.texture[ENG_CIRCLE]);

		engineCtrl.texture[ENG_TRIANGLE] = textureFindInAllBanks("PCBUT_1");
		ASSERT(engineCtrl.texture[ENG_TRIANGLE]);

		engineCtrl.inTexture[ENG_SQUARE] = textureFindInAllBanks("PCBUT_4D");
		ASSERT(engineCtrl.inTexture[ENG_SQUARE]);

		engineCtrl.inTexture[ENG_CROSS] = textureFindInAllBanks("PCBUT_3D");
		ASSERT(engineCtrl.inTexture[ENG_CROSS]);

		engineCtrl.inTexture[ENG_CIRCLE] = textureFindInAllBanks("PCBUT_2D");
		ASSERT(engineCtrl.inTexture[ENG_CIRCLE]);

		engineCtrl.inTexture[ENG_TRIANGLE] = textureFindInAllBanks("PCBUT_1D");
		ASSERT(engineCtrl.inTexture[ENG_TRIANGLE]);
	#else
		engineCtrl.texture[ENG_SQUARE] = textureFindInAllBanks("SQUARE");
		ASSERT(engineCtrl.texture[ENG_SQUARE]);

		engineCtrl.texture[ENG_CROSS] = textureFindInAllBanks("CROSS");
		ASSERT(engineCtrl.texture[ENG_CROSS]);

		engineCtrl.texture[ENG_CIRCLE] = textureFindInAllBanks("CIRCLE");
		ASSERT(engineCtrl.texture[ENG_CIRCLE]);

		engineCtrl.texture[ENG_TRIANGLE] = textureFindInAllBanks("TRIANGLE");
		ASSERT(engineCtrl.texture[ENG_TRIANGLE]);

		engineCtrl.inTexture[ENG_SQUARE] = textureFindInAllBanks("INSQUARE");
		ASSERT(engineCtrl.inTexture[ENG_SQUARE]);

		engineCtrl.inTexture[ENG_CROSS] = textureFindInAllBanks("INCROSS");
		ASSERT(engineCtrl.inTexture[ENG_CROSS]);

		engineCtrl.inTexture[ENG_CIRCLE] = textureFindInAllBanks("INCIRCLE");
		ASSERT(engineCtrl.inTexture[ENG_CIRCLE]);

		engineCtrl.inTexture[ENG_TRIANGLE] = textureFindInAllBanks("INTRIANGLE");
		ASSERT(engineCtrl.inTexture[ENG_TRIANGLE]);
	#endif
#endif
	engineCtrl.arrow = textureFindInAllBanks("RARROW");
	ASSERT(engineCtrl.arrow);

//	nmeDogEnsureHourglass();

	//SB - replaced PALMODE since DC has a 50/60 Hz switch! Please leave!!
	if(palMode)
		initStopWatch(160, 90, ENGINE_FOV);
	else
		initStopWatch(160, 80, ENGINE_FOV);

	initFowler(ENGINE_FOV, SG_ENGINE);


}

//-------------------------------------------------------------------------------------------------
void engineExit()
{
	subGameRestart = FALSE;
	engineCtrl.frameCount = 1;
	engineCtrl.gameState = ENGINE_FADEOUT;
}



//-------------------------------------------------------------------------------------------------
void engineReset()
{


	dsEvent_Init();

	engineCtrl.loopSampleNum = -1;// no sound at the mo

	engine->position.vx=ENGINE_X;
	engine->position.vy=ENGINE_Y;
	engine->position.vz=ENGINE_Z;



	pumper->position.vx=416;
	pumper->position.vy=0;
	pumper->position.vz=-2504;
	pumper->psiData.object->rotate.vy=2048;

	oiler->position.vx=-100;
	oiler->position.vy=0;
	oiler->position.vz=550;
	oiler->psiData.object->rotate.vy=1024;

	cogbike->position.vx=-765;
	cogbike->position.vy=0;
	cogbike->position.vz=-1352;
	cogbike->psiData.object->rotate.vy=2048;

	rockytub->position.vx=-80;
	rockytub->position.vy=-100;
	rockytub->position.vz=-2150;
	rockytub->psiData.object->rotate.vy=2600;


	cogs->position.vx=-640;
	cogs->position.vy=-130;
	cogs->position.vz=-775;
	cogs->psiData.object->rotate.vy=0;

	shaft->position.vx=-615;
	shaft->position.vy=-265;
	shaft->position.vz=-140;
	//shaft->psiData.object->rotate.vy=2048;

	engine->position.vx=ENGINE_X;
	engine->position.vy=ENGINE_Y;
	engine->position.vz=ENGINE_Z;
	engine->psiData.object->rotate.vy = 1024;
	//engine->psiData.object->rotate.vy=1024;


	actorAnimate(pumper, PUMP_SLOW_PUMP, 1, 0, 256, 1, 0);
	actorAnimate(oiler, OILER_IDLE_CHECK_WATCH, 0, 0, 256, 1, 0);
	actorAnimate(cogbike, COG_LOOK_ROUND, 0, 0, 256, 1, 0);
	actorAnimate(rockytub, RELAX_IDLE, 1, 0, 256, 1, 0);


	actorAnimate(cogs, 0, 1, 0, 256, 1, 0);
	actorAnimate(engine, 0, 1, 0, 256, 1, 0);

	camlook.vx=targetLook[2].vx;
	camlook.vy=targetLook[2].vy;
	camlook.vz=targetLook[2].vz;

	campos.vx=targetPos[2].vx;
	campos.vy=targetPos[2].vy;
	campos.vz=targetPos[2].vz;

	engineCtrl.gameState = ENGINE_FADEIN;
	engineCtrl.frameCount = 1;

	engineCtrl.active=COGBIKE_ACTIVE;
	//camlook.vx=cogbike->position.vx;
	//camlook.vy=cogbike->position.vy-512;
	//camlook.vz=cogbike->position.vz;

	engineCtrl.target.vx=engineCtrl.oldTarget.vx=camlook.vx;
	engineCtrl.target.vy=engineCtrl.oldTarget.vy=camlook.vy;
	engineCtrl.target.vz=engineCtrl.oldTarget.vz=camlook.vz;

	engineCtrl.camPos.vx=engineCtrl.oldCamPos.vx=campos.vx;
	engineCtrl.camPos.vy=engineCtrl.oldCamPos.vy=campos.vy;
	engineCtrl.camPos.vz=engineCtrl.oldCamPos.vz=campos.vz;

	engineCtrl.justChangedFlag=FALSE;

	engineCtrl.bikerSpeed=0;
	engineCtrl.pumperSpeed=200;	// rocky starts with bubbles
	engineCtrl.oilerSpeed=0;

	engineCtrl.bikerCurrentAction=ACTION_BIKER_IDLE;
	engineCtrl.bikerLastAction=ACTION_BIKER_IDLE;

	engineCtrl.oilerCurrentAction=ACTION_OILER_IDLE;
	engineCtrl.oilerLastAction=ACTION_OILER_IDLE;

	engineCtrl.oilerAng=3000;
	engineCtrl.gauge=-512;
	engineCtrl.gameTimer=ENG_COUNTDOWN_TIME * FRAMESEC; // 2 mins at 25 ticks per second
	engineCtrl.gameState=ENGINE_FADEIN;

	GsSetProjection(ENGINE_FOV);

	resetStopWatch();

	sound_XA_Start(levinfo->tune_number);



}

void engineFree(void)
{
	dsEvent_Init();

	actorFree(cogbike);
	actorFree(oiler);
	actorFree(pumper);
	actorFree(rockytub);
	actorFree(cogs);
	actorFree(shaft);
	actorFree(engine);
	freeStopWatch();
	freeFowler();


	//actorFree(wheel);
	//enemyDeleteAll();
	psiDestroy();
	//menuStart();
	mapviewReleaseMap();

	sound_XA_Stop();
	sound_LoadLanguageBank(gameTextLang);


}


/*	--------------------------------------------------------------------------------
	Function 	: 
	Purpose 	: 
	Parameters 	: 
	Returns 	: 
	Info 		:
*/
void engineRestart()
{
	subGameRestart = TRUE;
	engineCtrl.frameCount = 1;
	engineCtrl.gameState = ENGINE_FADEOUT;
}


/////////////////////////////////////////////////////////////////
void	engineEnd(void)
{

	sound_XA_Stop();
	sfxStopChannel(-1);


	dsEvent_Init();
//	sfxStopChannel(engineCtrl.loopSampleNum);

	if(subGameRestart == TRUE)
	{
		engineReset();
	}
	else
	{
//	mapviewReleaseMap();
	//textureUnloadBank(overlay_textures);

		engineFree();

		memoryShowStats();
		memoryShow();
		act4SubgameComplete("A4_WORKHUT2");	// In Wings.c
	}


//	if(subGameRestart == TRUE)
//	{
//		engineStart();
//	}
//	else
//	{
//		act4SubgameComplete("A4_WORKHUT2");	// In Wings.c
//	}
}



#define ENG_COGBIKE_RUMBLE   900
#define ENG_ROCKY_RUMBLE     700
#define ENG_RUMBLE_START     50
#define ENG_MAX_RUMBLE       100

#define ENG_REQUIRED_GUAGE  512

//int	movewho=FALSE;

void engineCycle(void)
{
	char	testMess[255];
	int rumble, i;

	
	EXLIGHT_Update();


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

	
	
	engineCtrl.frameCount++;


	if(engineCtrl.gameState == ENGINE_RUNNING)
	{
	
		// Do the rumble
		if(engineCtrl.active == OILER_ACTIVE)
			rumble = 1024;
		else if(engineCtrl.active == COGBIKE_ACTIVE)
			rumble = ENG_COGBIKE_RUMBLE;
		else 
			rumble = ENG_ROCKY_RUMBLE;
		
		rumble = ENG_RUMBLE_START + ((ENG_MAX_RUMBLE - ENG_RUMBLE_START)*(rumble * engineCtrl.bikerSpeed)) / (1024 * 200);
		dsEvent_Add(0, 0, 1, rumble, 0, 12, 0);
	}


	dsEvent_Update();

	engineCamera();		 

#ifdef ENG_DEBUGGING

	// don't need to keep pumping
	engineCtrl.pumperSpeed=200;

#endif

	//wheel->rotate.vx+=16;

#ifdef DEBUG
//	if(padData.debounce[0] & PAD_START)
//	{
//		engineEnd();
//		return;
//	}
#endif



	//cycle
	switch(engineCtrl.gameState)
	{

		case ENGINE_FADEIN:
			break;
		case ENGINE_INTRO:
			if(pReadPad->debounce[0] & PAD_CROSS)
			{
				engineCtrl.gameState = ENGINE_RUNNING;
					subGameRestart = FALSE;
			}
#ifdef DREAMCAST
			else if(pReadPad->debounce[0] & PAD_CIRCLE)
#else
			else if(pReadPad->debounce[0] & PAD_TRIANGLE)
#endif
			{
				subGameRestart = FALSE;
				engineCtrl.frameCount = 1;
				engineCtrl.gameState = ENGINE_FADEOUT;
				return;
			}


			break;
		case ENGINE_RUNNING:

#ifdef DEBUG
			if(SwimCheatCycle())
			{
				engineCtrl.gauge=ENG_REQUIRED_GUAGE;
				engineCtrl.frameCount = 0;
				engineCtrl.gameState=ENGINE_FINISHING_SUCCEED;
			}
#endif


#ifdef ENG_DEBUGGING
			if((padData.debounce[0] & PAD_RIGHT) && !engineCtrl.justChangedFlag)
#else
			if ( ((pReadPad->analogXS[0] > 500)||(padData.debounce[0] & PAD_RIGHT)) && !engineCtrl.justChangedFlag)
#endif
			{
//				soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_CAMERA], 0xffff, 0);
				
				engineCtrl.active++;
				if (engineCtrl.active==MAX_ENGINE_ACTORS) engineCtrl.active=OILER_ACTIVE;
				engineCtrl.justChangedFlag=TRUE;
				engineCtrl.oldTarget.vx=engineCtrl.target.vx;
				engineCtrl.oldTarget.vy=engineCtrl.target.vy;
				engineCtrl.oldTarget.vz=engineCtrl.target.vz;

				engineCtrl.target.vx=targetLook[engineCtrl.active].vx;
				engineCtrl.target.vy=targetLook[engineCtrl.active].vy;
				engineCtrl.target.vz=targetLook[engineCtrl.active].vz;

				engineCtrl.oldCamPos.vx=engineCtrl.camPos.vx;
				engineCtrl.oldCamPos.vy=engineCtrl.camPos.vy;
				engineCtrl.oldCamPos.vz=engineCtrl.camPos.vz;

				engineCtrl.camPos.vx=targetPos[engineCtrl.active].vx;
				engineCtrl.camPos.vy=targetPos[engineCtrl.active].vy;
				engineCtrl.camPos.vz=targetPos[engineCtrl.active].vz;

			}

#ifdef ENG_DEBUGGING
			else if ( (padData.debounce[0] & PAD_LEFT) && !engineCtrl.justChangedFlag)
#else
			else if ( ((pReadPad->analogXS[0] < -500)||(padData.debounce[0] & PAD_LEFT)) && !engineCtrl.justChangedFlag)
#endif

			{
//				soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_CAMERA], 0xffff, 0);
				
				engineCtrl.active--;
				if (engineCtrl.active<0) engineCtrl.active=COGBIKE_ACTIVE;
				engineCtrl.justChangedFlag=TRUE;
				engineCtrl.oldTarget.vx=engineCtrl.target.vx;
				engineCtrl.oldTarget.vy=engineCtrl.target.vy;
				engineCtrl.oldTarget.vz=engineCtrl.target.vz;

				engineCtrl.target.vx=targetLook[engineCtrl.active].vx;
				engineCtrl.target.vy=targetLook[engineCtrl.active].vy;
				engineCtrl.target.vz=targetLook[engineCtrl.active].vz;

				engineCtrl.oldCamPos.vx=engineCtrl.camPos.vx;
				engineCtrl.oldCamPos.vy=engineCtrl.camPos.vy;
				engineCtrl.oldCamPos.vz=engineCtrl.camPos.vz;

				engineCtrl.camPos.vx=targetPos[engineCtrl.active].vx;
				engineCtrl.camPos.vy=targetPos[engineCtrl.active].vy;
				engineCtrl.camPos.vz=targetPos[engineCtrl.active].vz;
				
			}

			if(engineCtrl.gameTimer) engineCtrl.gameTimer--;
			else
			{
				engineCtrl.gameState=ENGINE_FINISHING_TIMEUP;
				engineCtrl.frameCount = 0;
			}

			engineTicker++;
			if(engineTicker>1) engineTicker=0;

			if(engineCtrl.bikerSpeed>100 && engineCtrl.oilerSpeed>100)
			{
				engineCtrl.gauge+=(engineCtrl.bikerSpeed+engineCtrl.oilerSpeed)/200;
			}

			if (engineCtrl.pumperSpeed<45 && engineCtrl.pumperSpeed>25)
				fontCentredMultiLine(font,0,0,312,(char*)TEXTSTR(TEXTSTR_SUB_ENG_WHERE_BUBBLES), 128,128,128);
			if (engineCtrl.pumperSpeed<26 && engineCtrl.pumperSpeed>0)
				fontCentredMultiLine(font,0,0,312,(char*)TEXTSTR(TEXTSTR_SUB_ENG_STOP_THIS), 128,128,128);
			if (engineCtrl.pumperSpeed<=0 )
			{
///				fontCentredMultiLine(font,0,78,512,"At this point the game is failed\n", 128,128,128);
				engineCtrl.gameState=ENGINE_FINISHING_ROCKY;//ENGINE_FAILED;
				engineCtrl.frameCount = 0;
			}


			switch (engineCtrl.active)
			{
				case OILER_ACTIVE:
#ifdef _WINDOWS
					if(DI_KEYDEB(DIK_4) || DI_KEYDEB(DIK_1))
#else
					if(padData.debounce[0] & (PAD_SQUARE|PAD_TRIANGLE) )
#endif
						engineCtrl.oilerSpeed+=9;
					break;

				case PUMPER_ACTIVE:
#ifdef _WINDOWS
					if(DI_KEYDEB(DIK_3) || DI_KEYDEB(DIK_2))
#else
					if(padData.debounce[0] & (PAD_CROSS|PAD_CIRCLE) )
#endif
						engineCtrl.pumperSpeed+=9;
					break;

				case COGBIKE_ACTIVE:
#ifdef _WINDOWS
					if(DI_KEYDEB(DIK_4) || DI_KEYDEB(DIK_2))
#else
					if(padData.debounce[0] & (PAD_SQUARE|PAD_CIRCLE) )
#endif
						engineCtrl.bikerSpeed+=9;
					break;

				default:
					DB("nothing active\n");
					ASSERT(0);
					break;
			}
			oilerUpdate();
			pumperUpdate();
			bikerUpdate();
			break;

		case ENGINE_FINISHING_SUCCEED:

		case ENGINE_FINISHING_TIMEUP:
		case ENGINE_FINISHING_ROCKY:



			if((engineCtrl.gameState == ENGINE_FINISHING_SUCCEED)&&(engineCtrl.frameCount == 1))
			{
				if(engineCtrl.active != OILER_ACTIVE)
				{
					engineCtrl.active=OILER_ACTIVE;
					engineCtrl.justChangedFlag=TRUE;
					engineCtrl.oldTarget.vx=engineCtrl.target.vx;
					engineCtrl.oldTarget.vy=engineCtrl.target.vy;
					engineCtrl.oldTarget.vz=engineCtrl.target.vz;

					engineCtrl.target.vx=targetLook[engineCtrl.active].vx;
					engineCtrl.target.vy=targetLook[engineCtrl.active].vy;
					engineCtrl.target.vz=targetLook[engineCtrl.active].vz;

					engineCtrl.oldCamPos.vx=engineCtrl.camPos.vx;
					engineCtrl.oldCamPos.vy=engineCtrl.camPos.vy;
					engineCtrl.oldCamPos.vz=engineCtrl.camPos.vz;

					engineCtrl.camPos.vx=targetPos[engineCtrl.active].vx;
					engineCtrl.camPos.vy=targetPos[engineCtrl.active].vy;
					engineCtrl.camPos.vz=targetPos[engineCtrl.active].vz;
				}
			}
			else if(engineCtrl.frameCount == 1)
			{
				if(engineCtrl.active != PUMPER_ACTIVE)
				{

					actorAnimate(rockytub, ROCKY_FAILED, FALSE, FALSE, 256, 0, 512);
					actorAnimate(rockytub, ROCKY_FAILED_CYCLE, FALSE, TRUE, 256, 0, 0);
					//todone need fail cycle anim here

					engineCtrl.active=PUMPER_ACTIVE;
					engineCtrl.justChangedFlag=TRUE;
					engineCtrl.oldTarget.vx=engineCtrl.target.vx;
					engineCtrl.oldTarget.vy=engineCtrl.target.vy;
					engineCtrl.oldTarget.vz=engineCtrl.target.vz;

					engineCtrl.target.vx=targetLook[engineCtrl.active].vx;
					engineCtrl.target.vy=targetLook[engineCtrl.active].vy;
					engineCtrl.target.vz=targetLook[engineCtrl.active].vz;

					engineCtrl.oldCamPos.vx=engineCtrl.camPos.vx;
					engineCtrl.oldCamPos.vy=engineCtrl.camPos.vy;
					engineCtrl.oldCamPos.vz=engineCtrl.camPos.vz;

					engineCtrl.camPos.vx=targetPos[engineCtrl.active].vx;
					engineCtrl.camPos.vy=targetPos[engineCtrl.active].vy;
					engineCtrl.camPos.vz=targetPos[engineCtrl.active].vz;
				}
			}



			// ease the stuff down
			engineCtrl.oilerCurrentAction = ACTION_OILER_IDLE;
			
			if(engineCtrl.gameState == ENGINE_FINISHING_SUCCEED)
			{
				int temp;//, temp2;
				temp = SAMPLE_VOL_MAX - (engineCtrl.frameCount < 30 ? 4*engineCtrl.frameCount:120);
//? i have no idea what this is for so I've commented it out	temp2 = SAMPLE_PIT_MIN + (engineCtrl.bikerSpeed*(SAMPLE_PIT_MAX - SAMPLE_PIT_MIN))/200;

//				temp = temp<temp2 ? temp:temp2;

				//DB("temp = %d\n", temp);

				if(sfxGetSampleStatus(engineCtrl.pSamples[SFX_ENGINE_RUNNING])==0)
				{
					engineCtrl.loopSampleNum = soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_RUNNING], 0x4040, 0);
				}
				sfxSetChannelVolume(engineCtrl.loopSampleNum, temp, temp);

				engineCtrl.bikerSpeed += 10;
				engineCtrl.pumperSpeed += 10;

				engineCtrl.oilerSpeed += 10;
				if (engineCtrl.oilerSpeed>200) engineCtrl.oilerSpeed=200;

			}
			else
			{
				engineCtrl.bikerSpeed -= 10;
				engineCtrl.pumperSpeed -= 10;
			}
			oilerUpdate();
			pumperUpdate();
			bikerUpdate();


			if((engineCtrl.frameCount > 70) ||((engineCtrl.frameCount > 30) &&(pReadPad->debounce[0] & PAD_CROSS)) )
			{
				if(engineCtrl.gameState == ENGINE_FINISHING_SUCCEED)
				{
					if(gameCalledFrom != GAMECALLEDFROM_DEBUG)
					{
						gamePlayData->SubGameStates[SUBGAME_ENGINE] = REPLAY_BEATEN;
						gameSaveData.levels_available[REPLAY_AVAILABLE_ENGINE] = REPLAY_BEATEN;
					}


					//check time here for medals
					if(engineCtrl.gameTimer > ENGINE_TIME_FOR_GOLD)
					{
						gameSaveData.medals_won[MEDAL_WON_ENGINE] = 3; 
						engineCtrl.gameState = ENGINE_GOLD_SUCCESS;
						startFowler(GOLD);
					}
					else if(engineCtrl.gameTimer > ENGINE_TIME_FOR_SILVER)
					{
						if(gameSaveData.medals_won[MEDAL_WON_ENGINE] < 2)
							gameSaveData.medals_won[MEDAL_WON_ENGINE]= 2; 

						engineCtrl.gameState = ENGINE_SILVER_SUCCESS;
						startFowler(SILVER);
					}
					else 
					{
						if(gameSaveData.medals_won[MEDAL_WON_ENGINE] < 1)
							gameSaveData.medals_won[MEDAL_WON_ENGINE] = 1;
						engineCtrl.gameState = ENGINE_BRONZE_SUCCESS;
						startFowler(BRONZE);
					}

					engineCtrl.frameCount = 0;
					sound_XA_Start(TUNE_3_COMPLETE + SOUND_XA_NOLOOP);
				}
				else
				{
					engineCtrl.gameState = ENGINE_FAILED;
					startFowler(FAIL);
					engineCtrl.frameCount = 0;
					sound_XA_Start(TUNE_4_FAILED + SOUND_XA_NOLOOP);
				}
			}
			break;

		case ENGINE_BRONZE_SUCCESS:
		case ENGINE_SILVER_SUCCESS:
		case ENGINE_GOLD_SUCCESS:
			engineCtrl.bikerSpeed += 10;
			engineCtrl.pumperSpeed += 10;
			bikerUpdate();
			pumperUpdate();


		case ENGINE_FAILED:

			makeFowlerSpeak();

			if(engineCtrl.frameCount > 30)
			{
			
				if(pReadPad->debounce[0] & PAD_CROSS)
				{
					engineCtrl.gameState = ENGINE_FADEOUT;
					engineCtrl.frameCount = 0;
					subGameRestart = TRUE;
				}
#ifdef DREAMCAST
				else if(pReadPad->debounce[0] & PAD_CIRCLE)
#else
				else if(pReadPad->debounce[0] & PAD_TRIANGLE)
#endif
				{
					engineCtrl.gameState = ENGINE_FADEOUT;
					engineCtrl.frameCount = 0;
					subGameRestart = FALSE;
				}
			}
			break;

		case ENGINE_FADEOUT:
			if(subGameRestart == TRUE)
			{
				i= (engineCtrl.frameCount)*20;
				if(i >=255)
				{
					engineEnd();
					return;
				}
			}
			else
			{
				engineEnd();
				return;
			}
			break;

	}


	if((engineCtrl.gameState != ENGINE_FADEOUT) && (engineCtrl.gameState != ENGINE_FADEIN))
	{
		updateStopWatch();
	}

	engineUpdateAnims();

#ifdef _WINDOWS
	DI_KEYUPDATEALL;
#endif
}


void engineUpdateAnims()
{
	actorMaintainAnimation(oiler);
	actorMaintainAnimation(pumper);
	actorMaintainAnimation(cogbike);
	actorMaintainAnimation(rockytub);
	actorMaintainAnimation(engine);
}

//todo
#define SOUND1PLAYTIME  3
//int SOUND2PLAYTIME = 8; 
 

#define	CAMCHANGETIME	15
void	engineCamera(void)
{
#ifdef ENG_DEBUGGING
	VECTOR	debug[4];
#endif

	mycamera.vpx=campos.vx;
	mycamera.vpy=campos.vy;
	mycamera.vpz=campos.vz;

	mycamera.vrx=camlook.vx;
	mycamera.vry=camlook.vy;
	mycamera.vrz=camlook.vz;


#ifdef ENG_DEBUGGING


	//pReadPad->analogX2S[0]
	campos.vx-=padData.analogXS[0] >> 6;
	campos.vz+=padData.analogYS[0] >> 6;

	camlook.vx-=padData.analogX2S[0] >> 6;
	camlook.vz+=padData.analogY2S[0] >> 6;

	debug[0].vx=camlook.vx-10;
	debug[0].vy=camlook.vy;
	debug[0].vz=camlook.vz+10;

	debug[1].vx=camlook.vx+10;
	debug[1].vy=camlook.vy;
	debug[1].vz=camlook.vz+10;

	debug[2].vx=camlook.vx-10;
	debug[2].vy=camlook.vy;
	debug[2].vz=camlook.vz-10;

	debug[3].vx=camlook.vx+10;
	debug[3].vy=camlook.vy;
	debug[3].vz=camlook.vz-10;

	overlayShowDebugPolygon(&debug[0], 4, 0xff0000, 4);

#endif


	//GsSetProjection(engineFOV);

	mapCamSetRefView2L(&mycamera);

	if (engineCtrl.justChangedFlag)
	{
		camlook.vx=( (engineCtrl.target.vx*engineCtrl.changeTime) + (engineCtrl.oldTarget.vx * (CAMCHANGETIME-engineCtrl.changeTime)) )/CAMCHANGETIME;
		camlook.vy=( (engineCtrl.target.vy*engineCtrl.changeTime) + (engineCtrl.oldTarget.vy * (CAMCHANGETIME-engineCtrl.changeTime)) )/CAMCHANGETIME;
		camlook.vz=( (engineCtrl.target.vz*engineCtrl.changeTime) + (engineCtrl.oldTarget.vz * (CAMCHANGETIME-engineCtrl.changeTime)) )/CAMCHANGETIME;

		campos.vx=( (engineCtrl.camPos.vx*engineCtrl.changeTime) + (engineCtrl.oldCamPos.vx * (CAMCHANGETIME-engineCtrl.changeTime)) )/CAMCHANGETIME;
		campos.vy=( (engineCtrl.camPos.vy*engineCtrl.changeTime) + (engineCtrl.oldCamPos.vy * (CAMCHANGETIME-engineCtrl.changeTime)) )/CAMCHANGETIME;
		campos.vz=( (engineCtrl.camPos.vz*engineCtrl.changeTime) + (engineCtrl.oldCamPos.vz * (CAMCHANGETIME-engineCtrl.changeTime)) )/CAMCHANGETIME;


		// Give it 2 frames in which to sound
		if ((engineCtrl.changeTime>=SOUND1PLAYTIME)&&(engineCtrl.changeTime<(SOUND1PLAYTIME+2)))
		{
			if(sfxGetSampleStatus(engineCtrl.pSamples[SFX_ENGINE_CAMERA]) == 0)
				soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_CAMERA], 0x9090, 0);
		}
//		if ((engineCtrl.changeTime==SOUND2PLAYTIME)&&(engineCtrl.changeTime<(SOUND2PLAYTIME+2)))
//		{
//			if(sfxGetSampleStatus(engineCtrl.pSamples[SFX_ENGINE_CAM_REV]) == 0)
//				soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_CAM_REV], 0xffff, 0);
//		}



		if (engineCtrl.changeTime==CAMCHANGETIME)
		{
			engineCtrl.changeTime=1;
			engineCtrl.justChangedFlag=FALSE;
		}
		engineCtrl.changeTime++;
		//DB("cam pos x %d z %d\n",campos.vx,campos.vz);
	}
#ifdef ENG_DEBUGGING
	else
	{
		targetPos[engineCtrl.active].vx = campos.vx;
		targetPos[engineCtrl.active].vy = campos.vy;
		targetPos[engineCtrl.active].vz = campos.vz;

		targetLook[engineCtrl.active].vx = camlook.vx;
		targetLook[engineCtrl.active].vy = camlook.vy;
		targetLook[engineCtrl.active].vz = camlook.vz;
	}
#endif

}

//int	depth=200;
#define E_INRO_TEXT_XPOS	    -144
#define ENG_POWER_BAR_TEXTXPOS  12

#ifdef DREAMCAST

#if PALMODE==1
int ENG_POWER_BAR_TEXTYPOS = -100;
int ENG_PANEL_Y	= -120;
#else
int ENG_POWER_BAR_TEXTYPOS = -80;
int ENG_PANEL_Y	= -100;
#endif

#else

#if PALMODE==1
	#define ENG_POWER_BAR_TEXTYPOS  -100
	#define ENG_PANEL_Y	(-120)
#else
	#define ENG_POWER_BAR_TEXTYPOS  -80
	#define ENG_PANEL_Y	(-100)
#endif

#endif

#define ENG_ROCKY_TEX     64

#define E_INRO_TEXT_YPOS  18//26;


//int ENG_HGLASS_X = 140;
//#if PALMODE==1
//	int ENG_HGLASS_Y = 44;
//#else
//	int ENG_HGLASS_Y = 34;
//#endif

#define ENGINE_ARROW_Y  -10

#define OILER_DEPTH  160

void engineDraw(void)
{											   
	int i;

#ifdef DREAMCAST
	depthBump = engineWorldDepth;
#endif

#ifdef _WINDOWS
	SetDrawOffsetPC(256, 128);
#endif
	
	MapDraw_DrawFMA_World((FMA_WORLD2 *)engine_fma_world);

	EXLIGHT_SetupActorLights(oiler);
	if(1)
	{
#ifndef DREAMCAST
		i = PSImodelctrl.depthoverride;
		PSImodelctrl.depthoverride = OILER_DEPTH;
#else
		depthBump = engineWorldDepth-80;
#endif

#ifdef _WINDOWS
		d2mActorDraw(oiler);
#else
		actorDraw(oiler);
#endif

#ifndef DREAMCAST
		PSImodelctrl.depthoverride = i;
#else
		depthBump = 0;
#endif
	}

#ifdef DREAMCAST
	depthBump = engineWorldDepth;
#endif

	EXLIGHT_SetupActorLights(pumper);
#ifdef _WINDOWS
	d2mActorDraw(pumper);
#else
	actorDraw(pumper);
#endif

	EXLIGHT_SetupActorLights(cogbike);
#ifdef _WINDOWS
	d2mActorDraw(cogbike);
#else
	actorDraw(cogbike);
#endif

	EXLIGHT_SetupActorLights(rockytub);
#ifdef _WINDOWS
	d2mActorDraw(rockytub);
#else
	actorDraw(rockytub);
#endif

	actorSetAnimSpeed(engine, engineCtrl.bikerSpeed);//(engineCtrl.bikerSpeed-40)+60 );
	EXLIGHT_SetupActorLights(engine);
#ifdef _WINDOWS
	d2mActorDraw(engine);
#else
	actorDraw(engine);
#endif

	// to fix sorting problems on the shaft
	if((engineCtrl.active == OILER_ACTIVE)&&((engineCtrl.justChangedFlag == FALSE) || (engineCtrl.changeTime > 10)))
	{
#ifndef DREAMCAST
		PSImodelctrl.depthoverride=580;
#endif
		psiSetKeyFrames(cogs->psiData.object, 0);
		EXLIGHT_SetupActorLights(cogs);

#ifdef _WINDOWS
		d2mActorDraw(cogs);
#else
		actorDraw(cogs);
#endif

		psiSetKeyFrames(shaft->psiData.object, 0);

		EXLIGHT_SetupActorLights(shaft);
		
		
#ifndef DREAMCAST
		PSImodelctrl.depthoverride=575;
#endif

#ifdef _WINDOWS
		d2mActorDraw(shaft);
#else
		actorDraw(shaft);
#endif

		PSImodelctrl.depthoverride=0;
	}
	else if((engineCtrl.active == COGBIKE_ACTIVE)&&((engineCtrl.justChangedFlag == FALSE) || (engineCtrl.changeTime > 9)))
	{
#ifndef DREAMCAST
		PSImodelctrl.depthoverride=500;
#endif
		psiSetKeyFrames(cogs->psiData.object, 0);
		EXLIGHT_SetupActorLights(cogs);

#ifdef _WINDOWS
		d2mActorDraw(cogs);
#else
		actorDraw(cogs);
#endif

		psiSetKeyFrames(shaft->psiData.object, 0);

		EXLIGHT_SetupActorLights(shaft);
		
		
#ifndef DREAMCAST
		PSImodelctrl.depthoverride=550;
#endif

#ifdef _WINDOWS
		d2mActorDraw(shaft);
#else
		actorDraw(shaft);
#endif

		PSImodelctrl.depthoverride=0;
	}
	else
	{

		psiSetKeyFrames(cogs->psiData.object, 0);
		EXLIGHT_SetupActorLights(cogs);

#ifdef _WINDOWS
		d2mActorDraw(cogs);
#else
		actorDraw(cogs);
#endif

		psiSetKeyFrames(shaft->psiData.object, 0);

		EXLIGHT_SetupActorLights(shaft);

#ifdef _WINDOWS
		d2mActorDraw(shaft);
#else
		actorDraw(shaft);
#endif
	}



	engPrintDebug();


	//draw
	switch(engineCtrl.gameState)
	{

		case ENGINE_FADEIN:

			if(subGameRestart == TRUE)
			{

				i= 255 - (engineCtrl.frameCount)*20;

//				DB("fade in i=%d\n",i);
				if(i <= 0)
					engineCtrl.gameState = ENGINE_INTRO;
				else
					deathScreenAdd(i, i, i, SEMITRANS_SUB, 2);
			}
			else
				engineCtrl.gameState = ENGINE_INTRO;
			break;

		case ENGINE_INTRO:

			engDrawIntro();
			break;

		case ENGINE_RUNNING:

			DrawDirectionArrows(engineCtrl.arrow, ENGINE_ARROW_Y);

			break;

		case ENGINE_FINISHING_TIMEUP:
			fontPrintCentred(font, 0,0, (char*)TEXTSTR(TEXTSTR_SUB_TIMES_UP), 128,128,128);
			break;

		case ENGINE_FINISHING_ROCKY:
			fontPrintCentred(font, 0,0, (char*)TEXTSTR(TEXTSTR_SUB_ENG_BUBBLES), 128,128,128);
			break;

		case ENGINE_FINISHING_SUCCEED:
			fontPrintCentred(font, 0,0, (char*)TEXTSTR(TEXTSTR_SUB_ENG_RUNNING), 128,128,128);
			break;

		case ENGINE_BRONZE_SUCCESS:
#ifdef DREAMCAST  
			depthBump = engineFowlerBump;
			fowlerDraw();
			depthBump=0;
#else
			fowlerDraw();
#endif
			engDrawBronzeSuccess();
			break;
		case ENGINE_SILVER_SUCCESS:
#ifdef DREAMCAST  
			depthBump = engineFowlerBump;
			fowlerDraw();
			depthBump=0;
#else
			fowlerDraw();
#endif
			engDrawSilverSuccess();
			break;
		case ENGINE_GOLD_SUCCESS:
#ifdef DREAMCAST  
			depthBump = engineFowlerBump;
			fowlerDraw();
			depthBump=0;
#else
			fowlerDraw();
#endif
			engDrawGoldSuccess();
			break;
		case ENGINE_FAILED:
#ifdef DREAMCAST  
			depthBump = engineFowlerBump;
			fowlerDraw();
			depthBump=0;
#else
			fowlerDraw();
#endif
			engDrawFail();
			break;
		case ENGINE_FADEOUT:

			if(subGameRestart == TRUE)
			{
				i= (engineCtrl.frameCount)*20;
				if(i > 230)
				{
					deathScreenAdd(255, 255, 255, SEMITRANS_SUB, 0);
//					DB("fade out i=255*\n");
				}
				else
				{
					deathScreenAdd(i, i, i, SEMITRANS_SUB, 0);
//					DB("fade out i=%d\n",i);
				}



			}
//			else
//				engineEnd();
			break;

	}

	if((engineCtrl.gameState != ENGINE_FADEOUT) && (engineCtrl.gameState != ENGINE_FADEIN))
	{
#ifdef _WINDOWS
		SetDrawOffsetPC(0, 0);
#endif

		if((engineCtrl.gameState != ENGINE_BRONZE_SUCCESS) && (engineCtrl.gameState != ENGINE_SILVER_SUCCESS) && (engineCtrl.gameState != ENGINE_GOLD_SUCCESS) && (engineCtrl.gameState != ENGINE_FAILED))
			drawStopWatch(4096 - ((4096*engineCtrl.gameTimer)/(ENG_COUNTDOWN_TIME * FRAMESEC)));

		powerBars();

//		fontPrint(font, 16+ENG_ROCKY_TEX+ENG_POWER_BAR_TEXTXPOS-256,ENG_POWER_BAR_TEXTYPOS, TEXTSTR(TEXTSTR_SUB_ENG_ROCKY), 128,98,0);
//		fontPrint(font, 185+ENG_ROCKY_TEX+ENG_POWER_BAR_TEXTXPOS-256,ENG_POWER_BAR_TEXTYPOS, TEXTSTR(TEXTSTR_SUB_ENG_BIKER), 128,98,0);
//		fontPrint(font, 351+ENG_ROCKY_TEX+ENG_POWER_BAR_TEXTXPOS-256,ENG_POWER_BAR_TEXTYPOS, TEXTSTR(TEXTSTR_SUB_ENG_OILER), 128,98,0);
	}
#ifdef DREAMCAST
	depthBump = 0;
#endif

}


void engPrintDebug()
{
#ifdef ENG_VIEW_STATES
	char strBuff[128];

	sprintf(strBuff, "gameState %d time%d", engineCtrl.gameState, engineCtrl.gameTimer);
	fontPrint(font, -250, -50, strBuff, 128, 128, 0);

#endif

#ifdef ENG_VIEW_OILER
	char strBuff[128];

	sprintf(strBuff, "engineCtrl.oilerCount %d", engineCtrl.oilerCount);
	fontPrint(font, -250, -90, strBuff, 128, 128, 0);


	sprintf(strBuff, "engineCtrl.oilerSpeed =  %d",engineCtrl.oilerSpeed );
	fontPrint(font, -250, -80, strBuff, 128, 128, 0);


	sprintf(strBuff, "engineCtrl.oilerCurrentAction %d", engineCtrl.oilerCurrentAction);
	fontPrint(font, -250, -70, strBuff, 128, 128, 0);


	sprintf(strBuff, "oiler->animation.animData[0].reachedEnd %d", oiler->animation.animData[0].reachedEnd);
	fontPrint(font, -250, -60, strBuff, 128, 128, 0);

	sprintf(strBuff, "oiler->animation.animData[0].segment %d", oiler->animation.animData[0].segment);
	fontPrint(font, -250, -50, strBuff, 128, 128, 0);

	sprintf(strBuff, "oiler->animation.animData[1].reachedEnd %d", oiler->animation.animData[1].reachedEnd);
	fontPrint(font, -250, -40, strBuff, 128, 128, 0);

	sprintf(strBuff, "oiler->animation.animData[1].segment %d", oiler->animation.animData[1].segment);
	fontPrint(font, -250, -30, strBuff, 128, 128, 0);


#endif

}





void engDrawIntro()
{
	// RFW - fontPrintMultiLineBox can only cope with 256-char strings. The German for this one is longer
	// Oh bugger, in a very big way, why does this multi-line-plus-box thing not even try to cope?
	char string[400];

/*
	sprintf(string, "%s\n\n%s\n\n%s\n\n%s",
		fontUpper((char*)TEXTSTR(TEXTSTR_NAME_OF_ENGINE)),
		(char*)TEXTSTR(TEXTSTR_SUB_ENG_INTRO1), 
		(char*)TEXTSTR(TEXTSTR_SUB_ENG_BUTTONS),
		(char*)TEXTSTR(TEXTSTR_SUB_XSTART)
	);

	fontPrintMultiLineBox(font, 0, 30, 340, string, 80, 90, 100);
*/

	sprintf(string, "\n%s\n\n%s\n",
		(char*)TEXTSTR(TEXTSTR_SUB_ENG_INTRO1), 
		(char*)TEXTSTR(TEXTSTR_SUB_ENG_BUTTONS)
	);

	fontPrintMultiLineBoxHeaderFooter(font, 0, 30, 340,
		string,
		fontUpper((char*)TEXTSTR(TEXTSTR_NAME_OF_ENGINE)),
		(char*)TEXTSTR(TEXTSTR_SUB_XSTART),
		80, 90, 100);


}



#define ENG_OUTRO_TEXT_YPOS   30
//------------------------------------------------
void engDrawBronzeSuccess()
{
	char string[400];
	
	sprintf(string, "%s\n%s", (char*)TEXTSTR(TEXTSTR_SUB_ENGINE_BRONZE), (char*)TEXTSTR(TEXTSTR_SUB_GAME_EXIT_RESTART));

	//SB - replaced PALMODE since DC has a 50/60 Hz switch! Please leave!!
	if(palMode)
		fontPrintMultiLineBoxSetDepth(font, 0, 0, 340, string, 40, 40, 20,engineBoxDepth);
	else
		fontPrintMultiLineBoxSetDepth(font, 0, 10, 340, string, 40, 40, 20,engineBoxDepth);
}

//------------------------------------------------
void engDrawSilverSuccess()
{
	char string[400];
	sprintf(string, "%s\n%s", (char*)TEXTSTR(TEXTSTR_SUB_ENGINE_SILVER), (char*)TEXTSTR(TEXTSTR_SUB_GAME_EXIT_RESTART));

	//SB - replaced PALMODE since DC has a 50/60 Hz switch! Please leave!!
	if(palMode)
		fontPrintMultiLineBoxSetDepth(font, 0, 0, 340, string, 40, 40, 20,engineBoxDepth);
	else
		fontPrintMultiLineBoxSetDepth(font, 0, 10, 340, string, 40, 40, 20,engineBoxDepth);
}

//------------------------------------------------
void engDrawGoldSuccess()
{
	char string[400];
	
	sprintf(string, "%s\n%s", (char*)TEXTSTR(TEXTSTR_SUB_ENGINE_GOLD), (char*)TEXTSTR(TEXTSTR_SUB_GAME_EXIT_RESTART));

	//SB - replaced PALMODE since DC has a 50/60 Hz switch! Please leave!!
	if(palMode)
		fontPrintMultiLineBoxSetDepth(font, 0, 0, 340, string, 40, 40, 20,engineBoxDepth);
	else
		fontPrintMultiLineBoxSetDepth(font, 0, 10, 340, string, 40, 40, 20,engineBoxDepth);
}



//------------------------------------------------
void engDrawFail()
{
	char string[400];
	
	sprintf(string, "%s\n%s", (char*)TEXTSTR(TEXTSTR_SUB_ENGINE_FAIL), (char*)TEXTSTR(TEXTSTR_SUB_GAME_EXIT_RESTART));

	//SB - replaced PALMODE since DC has a 50/60 Hz switch! Please leave!!
	if(palMode)
		fontPrintMultiLineBoxSetDepth(font, 0, 0, 340, string, 40, 40, 20,engineBoxDepth);
	else
		fontPrintMultiLineBoxSetDepth(font, 0, 10, 340, string, 40, 40, 20,engineBoxDepth);
}









#define E_BUTT_X  15
#define E_BUTT_Y  16
#define E_BUTT_S  30

//todo
#define ENG_ICON_X  95
#define ENG_ICON_Y  13
//int myhighbyte = 0;
//int myalphaval = 100;

#define myrval  70
#define mygval  80
#define mybval  120




/////////////////////////////////////////////////////////////////
void	powerBars(void)
{
	POLY_G4 *powerBar;
	VECTOR	gauge;
//	char	textMess[255];
//	int		mins,secs;

//	mins=engineCtrl.gameTimer/(60*25);
//	secs=(engineCtrl.gameTimer-(mins*(60*25)))/25;
//	sprintf(textMess,"Time Left");
//	fontPrint(font, 30,50, textMess, 128,128,0);
//	if (mins!=1) sprintf(textMess,"%d mins %d secs ",mins,secs);
//	else sprintf(textMess,"%d min %d secs ",mins,secs);
//	fontPrint(font, 30,62, textMess, 128,128,0);

//	nmeDogStartHourglass(int state);
//	nmeDogCycleHourglass();
// 	nmeDogDrawHourglass();
	//hourglass_time=60;
	//nmeDogDrawHourglass();

//	baseBar(16-256,-120);
//	baseBar(181-256,-120);
//	baseBar(346-256,-120);

	if(engineCtrl.active == PUMPER_ACTIVE)
		overlaySprite(woodBackDropSelected,15-256,ENG_PANEL_Y-1,engineBoxDepth+2,0xff808080);
	else
		overlaySprite(woodBackDrop,16-256,ENG_PANEL_Y,engineBoxDepth+2,0xff808080);

	if(engineCtrl.active == COGBIKE_ACTIVE)
		overlaySprite(woodBackDropSelected,180-256,ENG_PANEL_Y-1  ,engineBoxDepth+2,0xff808080);
	else
		overlaySprite(woodBackDrop,181-256,ENG_PANEL_Y  ,engineBoxDepth+2,0xff808080);

	if(engineCtrl.active == OILER_ACTIVE)
		overlaySprite(woodBackDropSelected, 345-256,ENG_PANEL_Y-1 ,engineBoxDepth+2,0xff808080);
	else
		overlaySprite(woodBackDrop, 346-256,ENG_PANEL_Y ,engineBoxDepth+2,0xff808080);

	

	//todo
	{
		unsigned long colour = (myrval)+ ((mygval)<<8)+ ((mybval)<<16);

#ifndef _WINDOWS
// Re-introduced to the playstation. RFW. 4 Oct 00.
 		overlayAlphaSprite(engineCtrl.icons[0], (16 - 256 + ENG_ICON_X),  (ENG_PANEL_Y + ENG_ICON_Y), engineBoxDepth+1, colour);
 		overlayAlphaSprite(engineCtrl.icons[1], (180 - 256 + ENG_ICON_X), (ENG_PANEL_Y + ENG_ICON_Y), engineBoxDepth+1, colour);
 		overlayAlphaSprite(engineCtrl.icons[2], (345 - 256 + ENG_ICON_X), (ENG_PANEL_Y + ENG_ICON_Y), engineBoxDepth+1, colour);
#else
 		overlayAlphaSprite(engineCtrl.icons[0], (16 - 256 + ENG_ICON_X),  (ENG_PANEL_Y + ENG_ICON_Y), engineBoxDepth+1, colour);
 		overlayAlphaSprite(engineCtrl.icons[1], (180 - 256 + ENG_ICON_X), (ENG_PANEL_Y + ENG_ICON_Y), engineBoxDepth+1, colour);
 		overlayAlphaSprite(engineCtrl.icons[2], (345 - 256 + ENG_ICON_X), (ENG_PANEL_Y + ENG_ICON_Y), engineBoxDepth+1, colour);

#endif

	}



	// rocky cross
#ifdef _WINDOWS
	if((engineCtrl.active == PUMPER_ACTIVE) && DI_KEY(DIK_3) && (engineCtrl.gameState == ENGINE_RUNNING))
#else
	if((engineCtrl.active == PUMPER_ACTIVE) && (pReadPad->debounce[0] & PAD_CROSS) && (engineCtrl.gameState == ENGINE_RUNNING))
#endif
	{
#ifdef DREAMCAST
		overlaySprite(engineCtrl.inTexture[ENG_CROSS], 16-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.inTexture[ENG_CROSS], 16-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif
		engineCtrl.buttonStates[0] = 1;
	}
	else if(engineCtrl.buttonStates[0] == 1)
	{
#ifdef DREAMCAST
		overlaySprite(engineCtrl.inTexture[ENG_CROSS], 16-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.inTexture[ENG_CROSS], 16-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif
		engineCtrl.buttonStates[0] = 0;
	}
	else
#ifdef DREAMCAST
		overlaySprite(engineCtrl.texture[ENG_CROSS], 16-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.texture[ENG_CROSS], 16-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif



	// rocky circle
#ifdef _WINDOWS
	if((engineCtrl.active == PUMPER_ACTIVE) && DI_KEY(DIK_2) && (engineCtrl.gameState == ENGINE_RUNNING))
#else
	if((engineCtrl.active == PUMPER_ACTIVE) && (pReadPad->debounce[0] & PAD_CIRCLE) && (engineCtrl.gameState == ENGINE_RUNNING))
#endif

	{
#ifdef DREAMCAST
		overlaySprite(engineCtrl.inTexture[ENG_CIRCLE], 16-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.inTexture[ENG_CIRCLE], 16-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif
		engineCtrl.buttonStates[1] = 1;
	}
	else if(engineCtrl.buttonStates[1] == 1)
	{
#ifdef DREAMCAST
		overlaySprite(engineCtrl.inTexture[ENG_CIRCLE], 16-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.inTexture[ENG_CIRCLE], 16-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif
		engineCtrl.buttonStates[1] = 0;
	}
	else
#ifdef DREAMCAST
		overlaySprite(engineCtrl.texture[ENG_CIRCLE], 16-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.texture[ENG_CIRCLE], 16-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif


	// bike square
#ifdef _WINDOWS
	if((engineCtrl.active == COGBIKE_ACTIVE) && DI_KEY(DIK_4) && (engineCtrl.gameState == ENGINE_RUNNING))
#else
	if((engineCtrl.active == COGBIKE_ACTIVE) && (pReadPad->debounce[0] & PAD_SQUARE) && (engineCtrl.gameState == ENGINE_RUNNING))
#endif
	{
#ifdef DREAMCAST
		overlaySprite(engineCtrl.inTexture[ENG_SQUARE], 181-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.inTexture[ENG_SQUARE], 181-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif
		engineCtrl.buttonStates[2] = 1;
	}
	else if(engineCtrl.buttonStates[2] == 1)
	{
#ifdef DREAMCAST
		overlaySprite(engineCtrl.inTexture[ENG_SQUARE], 181-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.inTexture[ENG_SQUARE], 181-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif
		engineCtrl.buttonStates[2] = 0;
	}
	else
#ifdef DREAMCAST
		overlaySprite(engineCtrl.texture[ENG_SQUARE], 181-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.texture[ENG_SQUARE], 181-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif



	// bike circle
#ifdef _WINDOWS
	if((engineCtrl.active == COGBIKE_ACTIVE) && DI_KEY(DIK_2) && (engineCtrl.gameState == ENGINE_RUNNING))
#else
	if((engineCtrl.active == COGBIKE_ACTIVE) && (pReadPad->debounce[0] & PAD_CIRCLE) && (engineCtrl.gameState == ENGINE_RUNNING))
#endif
	{
#ifdef DREAMCAST
		overlaySprite(engineCtrl.inTexture[ENG_CIRCLE], 181-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y,-engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.inTexture[ENG_CIRCLE], 181-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif
		engineCtrl.buttonStates[3] = 1;
	}
	else if(engineCtrl.buttonStates[3] == 1)
	{
#ifdef DREAMCAST
		overlaySprite(engineCtrl.inTexture[ENG_CIRCLE], 181-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.inTexture[ENG_CIRCLE], 181-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif
		engineCtrl.buttonStates[3] = 0;
	}
	else
#ifdef DREAMCAST
		overlaySprite(engineCtrl.texture[ENG_CIRCLE], 181-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.texture[ENG_CIRCLE], 181-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif

	// oiler square
#ifdef _WINDOWS
	if((engineCtrl.active == OILER_ACTIVE) && DI_KEY(DIK_4) && (engineCtrl.gameState == ENGINE_RUNNING))
#else
	if((engineCtrl.active == OILER_ACTIVE) && (pReadPad->debounce[0] & PAD_SQUARE) && (engineCtrl.gameState == ENGINE_RUNNING))
#endif
	{
#ifdef DREAMCAST
		overlaySprite(engineCtrl.inTexture[ENG_SQUARE], 346-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.inTexture[ENG_SQUARE], 346-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif
		engineCtrl.buttonStates[4] = 1;
	}
	else if(engineCtrl.buttonStates[4] == 1)
	{
#ifdef DREAMCAST
		overlaySprite(engineCtrl.inTexture[ENG_SQUARE], 346-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.inTexture[ENG_SQUARE], 346-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif
		engineCtrl.buttonStates[4] = 0;
	}
	else
#ifdef DREAMCAST
		overlaySprite(engineCtrl.texture[ENG_SQUARE], 346-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.texture[ENG_SQUARE], 346-256+E_BUTT_X,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif

	// oiler triangle
#ifdef _WINDOWS
	if((engineCtrl.active == OILER_ACTIVE) && DI_KEY(DIK_1) && (engineCtrl.gameState == ENGINE_RUNNING))
#else
	if((engineCtrl.active == OILER_ACTIVE) && (pReadPad->debounce[0] & PAD_TRIANGLE) && (engineCtrl.gameState == ENGINE_RUNNING))
#endif
	{
#ifdef DREAMCAST
		overlaySprite(engineCtrl.inTexture[ENG_TRIANGLE], 346-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.inTexture[ENG_TRIANGLE], 346-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif
		engineCtrl.buttonStates[5] = 1;
	}
	else if(engineCtrl.buttonStates[5] == 1)
	{
#ifdef DREAMCAST
		overlaySprite(engineCtrl.inTexture[ENG_TRIANGLE], 346-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.inTexture[ENG_TRIANGLE], 346-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif
		engineCtrl.buttonStates[5] = 0;
	}
	else
#ifdef DREAMCAST
		overlaySprite(engineCtrl.texture[ENG_TRIANGLE], 346-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, -engineBoxDepth+1, 0x808080);
#else
		overlaySprite(engineCtrl.texture[ENG_TRIANGLE], 346-256+E_BUTT_X+E_BUTT_S,ENG_PANEL_Y+E_BUTT_Y, 1, 0x808080);
#endif


	//SB - replaced PALMODE since DC has a 50/60 Hz switch! Please leave!!
	if(palMode)
		powerGuage(-236,40);
	else
		powerGuage(-228,28);


	BEGINPRIM(powerBar, POLY_G4);
	setPolyG4(powerBar);				
#ifdef DREAMCAST
	powerBar->x2=powerBar->x0= 43;//pbx0;//256 + (36-256)*1.25;
	powerBar->y1=powerBar->y0= (ENG_PANEL_Y+6)*1.875 + 240;//pby0;//240 + (ENG_PANEL_Y + 12)*1.875;	//-108;//-113;
	powerBar->x3=powerBar->x1= 42+(engineCtrl.pumperSpeed*0.7);//182;//pbx1;//256 + ((36+( (engineCtrl.pumperSpeed*110)/200 ))-256)*1.25; // why is it that every time an overlay is drarn its some silly dimention?
	powerBar->y3=powerBar->y2= (ENG_PANEL_Y+12)*1.875 + 240;//pby1;//240 + (ENG_PANEL_Y + 5)*1.875;		//-115;//-117;
#else
	powerBar->x2=powerBar->x0= 36-256;
	powerBar->y1=powerBar->y0= ENG_PANEL_Y + 12;	//-108;//-113;
	powerBar->x3=powerBar->x1= (36+( (engineCtrl.pumperSpeed*110)/200 ))-256; // why is it that every time an overlay is drarn its some silly dimention?
	powerBar->y3=powerBar->y2= ENG_PANEL_Y + 6;//5;		//-115;//-117;
#endif
	powerBar->r0 = 100;
	powerBar->g0 = 0;
	powerBar->b0 = 0;
	powerBar->r1 = 150;//(128*(200-engineCtrl.pumperSpeed))/200;
	powerBar->g1 = (140*(engineCtrl.pumperSpeed))/200;//0;
	powerBar->b1 = (130*(engineCtrl.pumperSpeed))/200;//(128*(engineCtrl.pumperSpeed))/200;

	powerBar->r2 = powerBar->r0;
	powerBar->g2 = powerBar->g0;
	powerBar->b2 = powerBar->b0;
	powerBar->r3 = powerBar->r1;
	powerBar->g3 = powerBar->g1;
	powerBar->b3 = powerBar->b1;

	ENDPRIM(powerBar, 0, POLY_G4);

	BEGINPRIM(powerBar, POLY_G4);
	setPolyG4(powerBar);
#ifdef DREAMCAST
	powerBar->x2=powerBar->x0= 250;//pbx0;//201-256;
	powerBar->y1=powerBar->y0= (ENG_PANEL_Y+6)*1.875 + 240;//pby0;//ENG_PANEL_Y + 12;	//-108;
	powerBar->x3=powerBar->x1= 250+(engineCtrl.bikerSpeed*0.7);//390pbx1;//(201+( (engineCtrl.bikerSpeed*110)/200))-256;
	powerBar->y3=powerBar->y2= (ENG_PANEL_Y+12)*1.875 + 240;//pby1;//ENG_PANEL_Y + 5;		//-115;
#else
	powerBar->x2=powerBar->x0= 201-256;
	powerBar->y1=powerBar->y0= ENG_PANEL_Y + 12;	//-108;
	powerBar->x3=powerBar->x1= (201+( (engineCtrl.bikerSpeed*110)/200))-256;
	powerBar->y3=powerBar->y2= ENG_PANEL_Y + 6;		//-115;
#endif
	powerBar->r0 = 100;
	powerBar->g0 = 0;
	powerBar->b0 = 0;
	powerBar->r1 = 150;//(128*(200-engineCtrl.pumperSpeed))/200;                          
	powerBar->g1 = (140*(engineCtrl.bikerSpeed))/200;//0;                                 
	powerBar->b1 = (130*(engineCtrl.bikerSpeed))/200;//(128*(engineCtrl.pumperSpeed))/200;
			   

	powerBar->r2 = powerBar->r0;
	powerBar->g2 = powerBar->g0;
	powerBar->b2 = powerBar->b0;
	powerBar->r3 = powerBar->r1;
	powerBar->g3 = powerBar->g1;
	powerBar->b3 = powerBar->b1;

	ENDPRIM(powerBar, 0, POLY_G4);

	BEGINPRIM(powerBar, POLY_G4);
	setPolyG4(powerBar);				
#ifdef DREAMCAST
	powerBar->x2=powerBar->x0= 457;//366-256;
	powerBar->y1=powerBar->y0= (ENG_PANEL_Y+6)*1.875 + 240;//ENG_PANEL_Y + 12;	//-108;
	powerBar->x3=powerBar->x1= 456+(engineCtrl.oilerSpeed*0.7);//(366+((engineCtrl.oilerSpeed*110)/200))-256;
	powerBar->y3=powerBar->y2= (ENG_PANEL_Y+12)*1.875 + 240;//ENG_PANEL_Y + 5;		//-115;
#else
	powerBar->x2=powerBar->x0= 366-256;
	powerBar->y1=powerBar->y0= ENG_PANEL_Y + 12;	//-108;
	powerBar->x3=powerBar->x1= (366+((engineCtrl.oilerSpeed*110)/200))-256;
	powerBar->y3=powerBar->y2= ENG_PANEL_Y + 6;		//-115;
#endif
	powerBar->r0 = 100;
	powerBar->g0 = 0;
	powerBar->b0 = 0;
	powerBar->r1 = 150;//(128*(200-engineCtrl.pumperSpeed))/200;                          
	powerBar->g1 = (140*(engineCtrl.oilerSpeed))/200;//0;                                 
	powerBar->b1 = (130*(engineCtrl.oilerSpeed))/200;//(128*(engineCtrl.pumperSpeed))/200;


	
	
	



	powerBar->r2 = powerBar->r0;
	powerBar->g2 = powerBar->g0;
	powerBar->b2 = powerBar->b0;
	powerBar->r3 = powerBar->r1;
	powerBar->g3 = powerBar->g1;
	powerBar->b3 = powerBar->b1;
		
	ENDPRIM(powerBar, 0, POLY_G4);

	gauge.vx=0;
	gauge.vy=0;
	gauge.vz=60;

	//RotateVector2D(&gauge, &gauge,engineCtrl.gauge);
	//overlayLine(-158,100,-200,68, 0x00ffff);
	//overlayLine(-158,100,-116,68, 0x00ffff);
	//overlayLine(-158,100,gauge.vx-158,100-(gauge.vz*3)/4, 0x00ffff);
	//engineCtrl.gauge+=4;

	if (engineCtrl.gauge>ENG_REQUIRED_GUAGE)
	{
		engineCtrl.gauge=ENG_REQUIRED_GUAGE;
		engineCtrl.frameCount = 0;
		// check here the time it took to decide medal....
		engineCtrl.gameState=ENGINE_FINISHING_SUCCEED;//ENGINE_BRONZE_SUCCESS;

	}


}

#ifdef DREAMCAST
 #define PG_XOFF  65
 #define PG_YOFF  86
 #define PG_XPOSDELTA  324
 #define PG_YPOSDELTA  368
#else
 #define PG_XOFF  50
 #define PG_YOFF  68
 #define PG_XPOSDELTA  49
 #define PG_YPOSDELTA  52
#endif

#define PG_ANGLE_START    820
#define PG_ANGLE_FACTOR   6640
#define PG_ANGLE_STRANGE  512


/////////////////////////////////////////////////////////////////
void powerGuage(int x1,int y1)
{
	int	dispAngle;

	dispAngle =  PG_ANGLE_START -(((engineCtrl.gauge+PG_ANGLE_STRANGE)*PG_ANGLE_FACTOR)/4096);

	overlaySprite(mainGuage,x1,y1,engineBoxDepth,0xff808080);
	overlaySprite(mainGuageAmount,x1,y1,engineBoxDepth-1,0xff808080);
	overlaySpriteRotate(needle,x1+PG_XPOSDELTA,y1+PG_YPOSDELTA,PG_XOFF,PG_YOFF,engineBoxDepth-2,dispAngle ,0xff808080);
}

/////////////////////////////////////////////////////////////////
//void baseBar(int x1,int y1)
//{

//	overlaySprite(woodBackDrop,x1,y1,4,0xff808080);




/*
	POLY_FT4 *baseBar;
	BEGINPRIM(baseBar, POLY_FT4);
	setPolyFT4(baseBar);				

	baseBar->x0=baseBar->x2=x2;
	baseBar->x1=baseBar->x3=x1;
	baseBar->y0=baseBar->y1=y2;
	baseBar->y2=baseBar->y3=y1;

	//baseBar->r0=baseBar->r1=baseBar->r2=baseBar->r3=0;
	//baseBar->g0=baseBar->g1=baseBar->g2=baseBar->g3=0;
	//baseBar->b0=baseBar->b1=baseBar->b2=baseBar->b3=0;

	baseBar->r0=128;
	baseBar->g0=128;
	baseBar->b0=128;

	*(ULONG *)(&baseBar->u0) = ((unsigned long)*(USHORT *)&woodBackDrop->u0)
		                  | (((unsigned long)(woodBackDrop->clut)) <<16);
	*(ULONG *)(&baseBar->u2) = ((unsigned long)*(USHORT *)&woodBackDrop->u2);
	*(ULONG *)(&baseBar->u3) = ((unsigned long)*(USHORT *)&woodBackDrop->u3);

	*(ULONG *)(&baseBar->u1) = ((unsigned long)*(USHORT *)&woodBackDrop->u1)
						  | (((unsigned long)(woodBackDrop->tpage)) <<16);
						  //| ((trans-1) << (16+5));
	// *(ULONG*)&si->r0 = (colour & 0xffffff) | ((GPU_COM_TF4+2)<<24);
	// *(ULONG*)&siFT4->r0 = (bgr & 0xffffff) | ((GPU_COM_TF4+2)<<24);

	ENDPRIM(baseBar, 1, POLY_FT4);
*/
//}

#define OIL_SQUELCH_DELAY  5000
/////////////////////////////////////////////////////////////////
void	oilerUpdate(void)
{

	static int oilSoundPlayed = 0;
	int temp,temp1,temp2;

	int	oilerAnimSpeed=256;

//	if (padData.digital[0] & PAD_CROSS)
//		engineCtrl.oilerSpeed+=6;

	if (!engineTicker) engineCtrl.oilerSpeed--;

	if (engineCtrl.oilerSpeed<0) engineCtrl.oilerSpeed=0;
	if (engineCtrl.oilerSpeed>200) engineCtrl.oilerSpeed=200;


		if((!oilSoundPlayed)&&(oiler->animation.animData[0].reachedEnd == 0)
			&&((oiler->animation.animData[0].segment==OILER_OIL1) || (oiler->animation.animData[0].segment==OILER_OIL2))
			&&(oiler->animation.animData[0].scaledFrameOffset > OIL_SQUELCH_DELAY))
		{

			soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_OIL], 0x5050, 0);
			oilSoundPlayed = 1;
		}
			


	switch (engineCtrl.oilerCurrentAction)
	{
		case ACTION_OILER_IDLE:

			temp=(utilCalcAngle( (mycamera.vpx-mycamera.vrx),(mycamera.vpz-mycamera.vrz) ))&4095;
			engineCtrl.oilerAng=temp;
			temp1=oiler->psiData.object->rotate.vy&4095;

			temp2=(findShortestAngle(temp,temp1+2048));

			//temp2-=temp1;
			//if (temp2>0) temp2-=2048;
			//else temp2+=2048;

			if (temp2>32) temp2=64;
			if (temp2<-32) temp2=-64;

			oiler->psiData.object->rotate.vy+=temp2;

			if (oiler->animation.queueSize<=2)
			{
				temp=utilRandomInt(6);
				if (temp>4) temp=4;
				switch(temp)
				{
					case 0:
						actorAnimate(oiler, OILER_BREATH, 0, 1, 256, 1, 512);
						break;
					case 1:
						actorAnimate(oiler, OILER_IDLE_CHECK_WATCH, 0, 1, 256, 1, 512);
						break;
					case 2:
						actorAnimate(oiler, OILER_IDLE_LOOK_LEFT, 0, 1, 256, 1, 512);
						break;
					case 3:
						actorAnimate(oiler, OILER_IDLE_LOOK_RIGHT, 0, 1, 256, 1, 512);
						break;
					case 4:
						actorAnimate(oiler, OILER_IDLE_TAP_FOOT, 0, 1, 256, 1, 512);
						break;
				}
			}
			if (engineCtrl.oilerSpeed)
			{
				engineCtrl.oilerLastAction=engineCtrl.oilerCurrentAction;
				engineCtrl.oilerCurrentAction=ACTION_OILER_SLOW;
				actorAnimate(oiler, OILER_OIL1, 0, 0, 256, 1, 512);
				actorAnimate(oiler, OILER_BREATH, 0, 1, 256, 1, 512);
				engineCtrl.oilerCount=1000;
				engineCtrl.oilerAng=3000;
			}
			break;

		case 	ACTION_OILER_SLOW:
		{
			int	seg,endFrame,currentFrame;
			temp=engineCtrl.oilerAng;
			temp1=oiler->psiData.object->rotate.vy&4095;
			temp2=(findShortestAngle(temp,temp1+2048));
			
			if (temp2>32) temp2=64;
			if (temp2<-32) temp2=-64;
			oiler->psiData.object->rotate.vy+=temp2;

			if (!engineCtrl.oilerSpeed)
			{
				engineCtrl.oilerCurrentAction=ACTION_OILER_IDLE;
				actorAnimate(oiler, OILER_BREATH, 0, 1, 256, 1, 512);
			}

			seg=cogbike->animation.animData[0].segment;
			endFrame=cogbike->animation.pSegments[seg].actualStartFrame+cogbike->animation.pSegments[seg].actualAnimLength;
			endFrame--;
			currentFrame=cogbike->animation.animData[0].actualFrame;
			if (currentFrame==endFrame) // we only want to change at the end of one segment
			{
				actorAnimate(oiler, OILER_BREATH, 0, 0, 256, 1, 512);
			}
			engineCtrl.oilerCount-=engineCtrl.oilerSpeed;

			if (engineCtrl.oilerCount<=0)
			{
				engineCtrl.oilerCount=1000;

				if (oiler->animation.animData[0].reachedEnd)
				{
					if (oiler->animation.animData[1].reachedEnd)
					{
//						DB("here1\n");
						actorAnimate(oiler, OILER_OIL1, 0, 0, 256, 1, 512);
						oilSoundPlayed = 0;
//						soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_OIL], 0x5050, 0);
					}
					else if (oiler->animation.animData[1].segment!=OILER_OIL1)
					{
//						DB("here2\n");
						actorAnimate(oiler, OILER_OIL1, 0, 0, 256, 1, 512);
						oilSoundPlayed = 0;
//						soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_OIL], 0x5050, 0);

					}
				}
//				else if (oiler->animation.animData[1].reachedEnd)
//				{
//					if (oiler->animation.animData[0].reachedEnd)
//					{
//						DB("here3\n");
//						actorAnimate(oiler, OILER_OIL1, 0, 0, 256, 1, 512);
//						soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_OIL], 0x5050, 0);
//
//					}
//					else if (oiler->animation.animData[0].segment!=OILER_OIL1)
//					{
//						DB("here4\n");
//						actorAnimate(oiler, OILER_OIL1, 0, 0, 256, 1, 512);
//						soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_OIL], 0x5050, 0);
//					}
//				}
				else if (oiler->animation.animData[0].segment!=OILER_OIL1 && oiler->animation.animData[1].segment!=OILER_OIL1)
				{
//					DB("here5\n");
					actorAnimate(oiler, OILER_OIL1, 0, 0, 256, 1, 512);
					oilSoundPlayed = 0;
//					soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_OIL], 0x5050, 0);
				}
			}
			if (engineCtrl.oilerSpeed>105)
			{
				engineCtrl.oilerLastAction=engineCtrl.oilerCurrentAction;
				engineCtrl.oilerCurrentAction=ACTION_OILER_FAST;
			}

			break;

		case 	ACTION_OILER_FAST:
			if (engineCtrl.oilerSpeed>100) oilerAnimSpeed+=(engineCtrl.oilerSpeed-100)*2;

			temp=engineCtrl.oilerAng;
			temp1=oiler->psiData.object->rotate.vy&4095;
			temp2=(findShortestAngle(temp,temp1+2048));
			
			if (temp2>32) temp2=64;
			if (temp2<-32) temp2=-64;
			oiler->psiData.object->rotate.vy+=temp2;

			if (engineCtrl.oilerSpeed<95)
			{
				engineCtrl.oilerLastAction=engineCtrl.oilerCurrentAction;
				engineCtrl.oilerCurrentAction=ACTION_OILER_SLOW;
				engineCtrl.oilerAng=3000;
			}
			engineCtrl.oilerCount-=engineCtrl.oilerSpeed;
			if (engineCtrl.oilerCount<=0)
			{
				engineCtrl.oilerCount=1000;
				if (oiler->animation.animData[0].reachedEnd)// && oiler->animation.animData[1].reachedEnd)
				{
					temp=utilRandomInt(2);
					if (temp>1) temp=1;
					if (temp==0)
					{
						actorAnimate(oiler, OILER_OIL1, 0, 0, oilerAnimSpeed, 1, 512);
						engineCtrl.oilerAng=3500;
						oilSoundPlayed = 0;
//						soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_OIL], 0x6060, 0);
//						DB("here6\n");

					}
					else
					{
						actorAnimate(oiler, OILER_OIL2, 0, 0, oilerAnimSpeed, 1, 512);
						engineCtrl.oilerAng=3000;
						oilSoundPlayed = 0;
//						soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_OIL], 0x6060, 0);
//						DB("here7\n");
					}
				}
			}
			break;
		}
	}
}

/////////////////////////////////////////////////////////////////
int		cogRot,oldRot;
int		rotAddFlag=FALSE;




#define	COGOFFSET 	200

void	bikerUpdate(void)
{
//	if (padData.debounce[0] & PAD_CROSS)
//		engineCtrl.bikerSpeed+=6;
	int	temp;

//	if (padData.digital[0] & PAD_CROSS)
//		engineCtrl.bikerSpeed+=6;

	//if (!engineTicker) engineCtrl.bikerSpeed--;

	temp=engineCtrl.oilerSpeed/45;

	switch (temp)
	{
		case	0:	// v low oil level engine friction v high
			engineCtrl.bikerSpeed-=4;
			break;
		case	1:	// low oil level
			engineCtrl.bikerSpeed-=3;
			break;
		case	2:	// mid oil level
			engineCtrl.bikerSpeed-=2;
			break;
		case	3:	// highish oil level
			engineCtrl.bikerSpeed-=1;
			break;
		case	4:	// engine full of oil
			break;
	}

			

	if (engineCtrl.bikerSpeed<0) engineCtrl.bikerSpeed=0;
	if (engineCtrl.bikerSpeed>200) engineCtrl.bikerSpeed=200;

	if(engineCtrl.bikerSpeed > 40)
	{
		if(engineCtrl.loopSampleNum == -1)
		{
			// start sample again
			engineCtrl.loopSampleNum = soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_RUNNING], 0x4040, 0);
//			DB("bs = %d, playing sample %d, pSample=%d\n", engineCtrl.bikerSpeed, engineCtrl.loopSampleNum, engineCtrl.pSamples[SFX_ENGINE_RUNNING]);
		}
		else
		{
			// DOING STUFF HERE
			if((engineCtrl.gameState == ENGINE_RUNNING))
			{
				// need this for pause
				if(sfxGetSampleStatus(engineCtrl.pSamples[SFX_ENGINE_RUNNING])==0)
				{
					engineCtrl.loopSampleNum = soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_RUNNING], 0x4040, 0);
				}
				
				temp = SAMPLE_VOL_MIN + (engineCtrl.bikerSpeed*(SAMPLE_VOL_MAX - SAMPLE_VOL_MIN))/200;
	//			sfxSetChannelVolume(engineCtrl.loopSampleNum, temp);
				
				sfxSetSampleVolume(engineCtrl.pSamples[SFX_ENGINE_RUNNING], engineCtrl.loopSampleNum, temp, temp);

				temp = SAMPLE_PIT_MIN + (engineCtrl.bikerSpeed*(SAMPLE_PIT_MAX - SAMPLE_PIT_MIN))/200;
	//			sfxSetChannelVolume(engineCtrl.loopSampleNum, temp, temp);
				sfxSetSamplePitch(engineCtrl.pSamples[SFX_ENGINE_RUNNING],engineCtrl.loopSampleNum, temp);

				if(utilRandomInt(100) > 94)
					soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_SQUEAKS], 0x7070, 0);
			}

		}

		//set sample speed + volume
	}
	else 
	{
		if(engineCtrl.loopSampleNum != -1)
		{
			//stop sample
			sfxStopChannel(engineCtrl.loopSampleNum);
	//		DB("num %d pSample %d stop sample\n", engineCtrl.loopSampleNum, engineCtrl.pSamples[SFX_ENGINE_FAILED]);

			engineCtrl.loopSampleNum = -1;
			//try playing splutter
			soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_FAILED], 0x6060, 0);
		}

		if((engineCtrl.active == COGBIKE_ACTIVE) && (engineCtrl.oilerSpeed < 140))
		{
		 
			if((padData.debounce[0] & (PAD_SQUARE|PAD_TRIANGLE))&&(sfxGetSampleStatus(engineCtrl.pSamples[SFX_ENGINE_BADSQUEAK]) == 0))
			{
				temp = (280 - engineCtrl.oilerSpeed)/4;
				temp += ((temp&0xff)<<8);
				soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_BADSQUEAK], 0x8080, 0);
			}

		}
	}

	switch ( cogbike->animation.animData[0].segment )
	{
		case COG_START_PEDALING:
		case COG_PEDAL_SLOW:
		//case COG_SIT_BACK_SLOW:
		case COG_FAST_PEDAL:
		case COG_SIT_BACK_FAST:	// all the anims where the wheel rotates
		{
			int	totalLen;
			int	currentLen;
			int	segment,rot;
			segment=cogbike->animation.animData[0].segment;
			currentLen=cogbike->animation.animData[0].scaledFrameOffset;
			totalLen=cogbike->animation.pSegments[segment].scaledAnimLength;
			//DB("len %d total len %d\n",currentLen,totalLen);
			rot=(currentLen*4096)/totalLen;
			if (oldRot>rot && !rotAddFlag) rotAddFlag=TRUE;
			else if (oldRot>rot && rotAddFlag) rotAddFlag=FALSE;
			oldRot=rot;

			if (rotAddFlag) cogRot=rot+4096;
			else cogRot=rot;

			wheel->rotate.vx=rot;
			engineCtrl.cogGearsFrame=(rot*50)/4096;

			shaft->psiData.object->rotate.vz=-(rot);

			cog1->rotate.vx=(rot+COGOFFSET);
			cog2->rotate.vx=(-COGOFFSET/2)-(cogRot/2);
			cog3->rotate.vz=((-cogRot/2)-COGOFFSET/2);

			

			//if (segment==5)
			//{
			//	DB("len %d total len %d\n",currentLen,totalLen);
			//}
		}
	}


	switch ( engineCtrl.bikerCurrentAction )
	{
		case ACTION_BIKER_IDLE:
			if (!engineCtrl.bikerSpeed)
			{
				if (cogbike->animation.queueSize<=2)	// time to add an other action to the queue
				{
					temp=utilRandomInt(10);
					if (temp>2) temp=2;
					switch (temp)
					{
						case 0:
							actorAnimate(cogbike, COG_LOOK_ROUND, 0, 1, 256, 1, 512);
							break;
						case 1:
							actorAnimate(cogbike, COG_LOOK_ROUND_NOD, 0, 1, 256, 1, 512);
							break;
						case 2:
							actorAnimate(cogbike, COG_BREATH_CYCLE, 0, 1, 256, 1, 512);
							break;
					}
				}
			}
			else
			{
				engineCtrl.bikerLastAction=engineCtrl.bikerCurrentAction;
				engineCtrl.bikerCurrentAction=ACTION_BIKER_SLOW;
				actorAnimate(cogbike, COG_START_PEDALING, 0, 0, 56, 1, 512);	// comes complete with "what the hell?" wheel action
				actorAnimate(cogbike, COG_PEDAL_SLOW, 1, 1, 56, 1, 512);	// slow has 48 frames
			}
			break;

		case ACTION_BIKER_SLOW:
			if (engineCtrl.bikerSpeed==0)
			{
				int	seg,endFrame,currentFrame;
				seg=cogbike->animation.animData[0].segment;
				endFrame=cogbike->animation.pSegments[seg].actualStartFrame+cogbike->animation.pSegments[seg].actualAnimLength;
				endFrame--;
				currentFrame=cogbike->animation.animData[0].actualFrame;
				if (currentFrame==endFrame) // we only want to change at the end of one segment
				{
					//actorAnimate(cogbike, COG_SIT_BACK_SLOW, 1, 0, 256, 1, 512);
					actorAnimate(cogbike, COG_SIT_BACK_SLOW, 1, 0, 256, 1, 512);
					engineCtrl.bikerLastAction=engineCtrl.bikerCurrentAction;
					engineCtrl.bikerCurrentAction=ACTION_BIKER_IDLE;
				}		
			}
			else if ( engineCtrl.bikerSpeed < 105 ) // larger than this is fast
			{
				//if( (cogbike->animation.animData[0].segment!=COG_START_PEDALING) && 
				//	(cogbike->animation.animData[0].segment!=COG_PEDAL_SLOW))
				//{
					//actorAnimate(cogbike, COG_START_PEDALING, 0, 0, 256, 1, 0);
					//actorAnimate(cogbike, COG_PEDAL_SLOW, 1, 1, 256, 1, 0);	// slow has 48 frames
				//}
				//else
				//if (cogbike->animation.animData[0].segment==COG_PEDAL_SLOW)
				//	actorSetAnimSpeed(cogbike, (engineCtrl.bikerSpeed*2)+55 );
				if (cogbike->animation.animData[0].segment==COG_FAST_PEDAL)
					actorSetAnimSpeed(cogbike, (engineCtrl.bikerSpeed-40)+60 );
				else
					actorSetAnimSpeed(cogbike, (engineCtrl.bikerSpeed*2)+55 );
			}
			else // speed > 105 change to fast 
			{
				engineCtrl.bikerLastAction=engineCtrl.bikerCurrentAction;
				engineCtrl.bikerCurrentAction=ACTION_BIKER_FAST;
				actorAnimate(cogbike, COG_FAST_PEDAL, 1, 1, 256, 1, 512);	// slow has 15 frames
			}
			break;


		case ACTION_BIKER_FAST:
			if (engineCtrl.bikerSpeed<95)	// bit of a window to stop jumps in anims
			{
				int	seg,endFrame,currentFrame;
				seg=cogbike->animation.animData[0].segment;
				endFrame=cogbike->animation.pSegments[seg].actualStartFrame+cogbike->animation.pSegments[seg].actualAnimLength;
				endFrame--;
				currentFrame=cogbike->animation.animData[0].actualFrame;
				if (currentFrame==endFrame) // we only want to change at the end of one segment
				{
					actorAnimate(cogbike, COG_PEDAL_SLOW, 1, 1, 256, 1, 512);	// slow has 48 frames
					engineCtrl.bikerLastAction=engineCtrl.bikerCurrentAction;
					engineCtrl.bikerCurrentAction=ACTION_BIKER_SLOW;
				}
			}
			else
			{
				//actorSetAnimSpeed(cogbike, (engineCtrl.bikerSpeed-40)+60 );
				if (cogbike->animation.animData[0].segment==COG_PEDAL_SLOW)
					actorSetAnimSpeed(cogbike, (engineCtrl.bikerSpeed*2)+55 );
				else if (cogbike->animation.animData[0].segment==COG_FAST_PEDAL)
					actorSetAnimSpeed(cogbike, (engineCtrl.bikerSpeed-40)+60 );
			}
			break;
				  
		default:
			DB("Error in biker \n");
			ASSERT(0);
			break;
	}


/*	engineCtrl.bikerSpeed-=1;
	if (engineCtrl.bikerSpeed<0) engineCtrl.bikerSpeed=0;

	if (engineCtrl.bikerSpeed>200) engineCtrl.bikerSpeed=200;

	if (engineCtrl.bikerSpeed)
	{
		if (engineCtrl.bikerSpeed<100)
		{
			if( (cogbike->animation.animData[0].segment!=COG_START_PEDALING) && 
				(cogbike->animation.animData[0].segment!=COG_PEDAL_SLOW))
			{
				actorAnimate(cogbike, COG_START_PEDALING, 0, 0, 256, 1, 0);
				actorAnimate(cogbike, COG_PEDAL_SLOW, 1, 1, 256, 1, 0);	// slow has 48 frames
			}
			//if( cogbike->animation.animData[0].segment==COG_PEDAL_SLOW )
			actorSetAnimSpeed(cogbike, (engineCtrl.bikerSpeed*2)+engineCtrl.bikerSpeed/2 );
		}
		else
		{
			if (cogbike->animation.animData[0].segment!=COG_FAST_PADAL || cogbike->animation.animData[1].segment!=COG_FAST_PADAL)
			{
				int	seg,endFrame,currentFrame;
				seg=cogbike->animation.animData[0].segment;
				endFrame=cogbike->animation.pSegments[seg].actualStartFrame+cogbike->animation.pSegments[seg].actualAnimLength;
				endFrame--;
				currentFrame=cogbike->animation.animData[0].actualFrame;
				if (currentFrame==endFrame) // we only want to change at the end of one segment
					actorAnimate(cogbike, COG_FAST_PADAL, 1, 0, 256, 1, 512);	// fast has 15 frames

				//cogbike->animation.animData[0].loop=0;
				//cogbike->animation.blendSpeed=512;
				//cogbike->animation.blendCounter=0;
				//actorAnimate(cogbike, COG_FAST_PADAL, 1, 1, 256, 1, 512);	// fast has 15 frames
			}

			actorSetAnimSpeed(cogbike, engineCtrl.bikerSpeed-(engineCtrl.bikerSpeed/5) );
		}
	}
	else if( (cogbike->animation.animData[0].segment==COG_START_PEDALING) ||
	(cogbike->animation.animData[0].segment==COG_PEDAL_SLOW))
	{
		actorAnimate(cogbike, COG_SIT_BACK_SLOW, 0, 0, 256, 1, 512);
		actorAnimate(cogbike, COG_BREATH_CYCLE, 0, 1, 256, 1, 512);
		actorAnimate(cogbike, COG_LOOK_ROUND_NOD, 0, 1, 256, 1, 512);
		actorAnimate(cogbike, COG_BREATH_CYCLE, 1, 1, 256, 1, 512);
	}
*/
}
/////////////////////////////////////////////////////////////////
// also handles updates for rocky in the tub
void	pumperUpdate(void)
{
	static int ahSample = 0;
	int	temp;
	int	pumpAnimSpeed=256;

//	if (padData.digital[0] & PAD_CROSS)
//		engineCtrl.pumperSpeed+=6;

	if (!engineTicker) engineCtrl.pumperSpeed--;

	if (engineCtrl.pumperSpeed<0) engineCtrl.pumperSpeed=0;
	if (engineCtrl.pumperSpeed>200) engineCtrl.pumperSpeed=200;


//	if(engineCtrl.gameState == ENGINE_FINISHING_TIMEUP)
//	{
//		return;

//		if(engineCtrl.pumperSpeed > 0)
//			engineCtrl.pumperSpeed = (engineCtrl.pumperSpeed-1)/2;
//	}
//	else 
	if((engineCtrl.gameState != ENGINE_RUNNING)&&(engineCtrl.gameState != ENGINE_FINISHING_TIMEUP))
		return;


	if (engineCtrl.pumperSpeed>65) // rocky is happy
	{
		

		if((engineCtrl.active == PUMPER_ACTIVE)&&(engineCtrl.pumperSpeed>100)&&(utilRandomInt(100) > 95))
		{
			if(ahSample)
			{
				ahSample = 0;
				soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_PUMPER], 0x7070, 0);
			}
			else
			{
				ahSample = 1;
				soundPlaySample(engineCtrl.pSamples[SFX_ENGINE_AH], 0x6060, 0);
			}
		}



		if (rockytub->animation.queueSize<=0)	// time to add an other action to the queue
		{
			temp=utilRandomInt(3);
			if (temp>2) temp=0;
			switch (temp)
			{
				case 0:
					actorAnimate(rockytub, RELAX_IDLE, 0, 1, 256, 1, 512);
					break;
				case 1:
					actorAnimate(rockytub, RELAX_STRETCH, 0, 1, 256, 1, 512);
					break;
				case 2:
					actorAnimate(rockytub, RELAX_SCRATCH, 0, 1, 256, 1, 512);
					break;
				//case 3:
				//	actorAnimate(rockytub, GET_UP, 0, 1, 256, 1, 512);
				//	break;
			}
		}
	}
	else if (engineCtrl.pumperSpeed<=65 && engineCtrl.pumperSpeed>1) // rocky is annoyed
	{
		if (rockytub->animation.queueSize<=0)	// time to add an other action to the queue
		{
			temp=utilRandomInt(3);
			if (temp>2) temp=0;
			switch (temp)
			{
				case 0:
					actorAnimate(rockytub, ANNOYED_LOOKROUND, 0, 1, 256, 1, 512);
					break;
				case 1:
					actorAnimate(rockytub, ANNOYED_TAP, 0, 1, 256, 1, 512);
					break;
				case 2:
					actorAnimate(rockytub, ANNOYED_SHRUG, 0, 1, 256, 1, 512);
					break;
			}
		}
	}
	else // rocky like the rest of us is pissed off
	{
		// can get rid of this here

//		if (rockytub->animation.animData[0].segment!=ROCKY_FAILED_CYCLE && rockytub->animation.animData[0].segment!=ROCKY_FAILED)
//		//if (rockytub->animation.queueSize<=0)
//		{
//			actorAnimate(rockytub, ROCKY_FAILED, 0, 0, 256, 1, 512);
//			actorAnimate(rockytub, ROCKY_FAILED_CYCLE, 1, 1, 256, 1, 512);
//			//actorAnimate(rockytub, ROCKY_FAILED_CYCLE, 1, 1, 256, 1, 512);
//		}
	}


	//if (engineCtrl.pumperSpeed<45 && engineCtrl.pumperSpeed>25)
	//	fontCentredMultiLine(font,0,78,512,"Oi where's me bubbles\n", 128,128,128);
	//if (engineCtrl.pumperSpeed<26 && engineCtrl.pumperSpeed>0)
	//	fontCentredMultiLine(font,0,78,512,"I'm going to stop this if you don't get a move on\n", 128,128,128);
	//if (engineCtrl.pumperSpeed<=0 )
	//{
	//	fontCentredMultiLine(font,0,78,512,"At this point the game is failed\n", 128,128,128);
	//	engineCtrl.gameState=FAILED;
	//}






	switch ( engineCtrl.pumperCurrentAction )
	{
		case ACTION_PUMPER_IDLE:
			if (!engineCtrl.pumperSpeed)
			{
				if (pumper->animation.queueSize<=2)	// time to add an other action to the queue
				{
					temp=utilRandomInt(3);
					if (temp>2) temp=0;
					switch (temp)
					{
						case 0:
							actorAnimate(pumper, PUMP_BREATH, 0, 1, 256, 1, 512);
							break;
						case 1:
							actorAnimate(pumper, PUMP_IDLE_LOOK_RIGHT, 0, 1, 256, 1, 512);
							break;
						case 2:
							actorAnimate(pumper, PUMP_IDLE_LOOK_LEFT, 0, 1, 256, 1, 512);
							break;
					}
				}
			}
			else
			{
				engineCtrl.pumperLastAction=engineCtrl.pumperCurrentAction;
				engineCtrl.pumperCurrentAction=ACTION_PUMPER_SLOW;
				actorAnimate(pumper, PUMP_SLOW_PUMP, 1, 0, 256, 1, 512);
				//actorAnimate(pumper, PUMP_BREATH, 0, 1, 256, 1, 512);
			}
			break;

		case ACTION_PUMPER_SLOW:
			if (engineCtrl.pumperSpeed==0)
			{
				actorAnimate(pumper, PUMP_BREATH, 0, 1, 256, 1, 512);
				engineCtrl.pumperLastAction=engineCtrl.pumperCurrentAction;
				engineCtrl.pumperCurrentAction=ACTION_PUMPER_IDLE;
			}
			pumpAnimSpeed=50+engineCtrl.pumperSpeed*4;
			actorSetAnimSpeed(pumper, pumpAnimSpeed );
			if (engineCtrl.pumperSpeed>105)
			{
				engineCtrl.pumperLastAction=engineCtrl.pumperCurrentAction;
				engineCtrl.pumperCurrentAction=ACTION_PUMPER_FAST;
				actorAnimate(pumper, PUMP_FAST_PUMP, 1, 0, 166, 1, 512);
			}
			break;

		case ACTION_PUMPER_FAST:
			pumpAnimSpeed=166+(engineCtrl.pumperSpeed-100)*2;
			actorSetAnimSpeed(pumper, pumpAnimSpeed );
			if (engineCtrl.pumperSpeed<95)
			{
				engineCtrl.pumperLastAction=engineCtrl.pumperCurrentAction;
				engineCtrl.pumperCurrentAction=ACTION_PUMPER_SLOW;
				actorAnimate(pumper, PUMP_SLOW_PUMP, 1, 0, 166, 1, 512);
			}
			break;

	}
}


/*
void junk(void)
{
	camlook.vx=campos.vx-rsin(camangle);
	camlook.vz=campos.vz-rcos(camangle);
	mycamera.vpx=campos.vx;
	mycamera.vpy=campos.vy;
	mycamera.vpz=campos.vz;

	mycamera.vrx=camlook.vx;
	mycamera.vry=camlook.vy;
	mycamera.vrz=camlook.vz;

	mapCamSetRefView2L(&mycamera);

	if (movewho==FALSE)
	{
		if (padData.digital[0] & PAD_LEFT) camangle+=32;
		if (padData.digital[0] & PAD_RIGHT) camangle-=32;

		if (padData.digital[0] & PAD_UP) campos.vy-=512;
		if (padData.digital[0] & PAD_DOWN) campos.vy+=512;

		if (padData.digital[0] & PAD_TRIANGLE)
		{
			campos.vx-=rsin(camangle)/32;
			campos.vz-=rcos(camangle)/32;
		}
		if (padData.digital[0] & PAD_CROSS)
		{
			campos.vx+=rsin(camangle)/32;
			campos.vz+=rcos(camangle)/32;
		}
	}
	else
	{
		if (padData.digital[0] & PAD_LEFT) pumper->position.vx+=16;
		if (padData.digital[0] & PAD_RIGHT) pumper->position.vx-=16;

		if (padData.digital[0] & PAD_UP) pumper->position.vz+=16;
		if (padData.digital[0] & PAD_DOWN) pumper->position.vz-=16;

		if (padData.digital[0] & PAD_R1) pumper->position.vy-=16;
		if (padData.digital[0] & PAD_R2) pumper->position.vy+=16;

		if (padData.debounce[0] & PAD_L1) pumper->psiData.object->rotate.vy+=1024;
	}
	if (padData.debounce[0] & PAD_L2)
	{
		if (movewho==TRUE) movewho=FALSE;
		else movewho=TRUE;
	}


//	if (padData.digital[0] & PAD_UP) campos.vz-=512;
//	if (padData.digital[0] & PAD_DOWN) campos.vz+=512;
//	if (padData.digital[0] & PAD_LEFT) campos.vx-=512;
//	if (padData.digital[0] & PAD_RIGHT) campos.vx+=512;

//	if (padData.digital[0] & PAD_TRIANGLE) camlook.vz-=512;
//	if (padData.digital[0] & PAD_CROSS) camlook.vz+=512;
//	if (padData.digital[0] & PAD_CIRCLE) camlook.vx-=512;
//	if (padData.digital[0] & PAD_SQUARE) camlook.vx+=512;

}

*/