#include "glover.h"
//#include "bff_load.h"
//#include "water.h"
//#include "libapi.h"	// criticalsection

PSAWORLD *pWld;

//NEWMODEL *plionfishPSA;
//NEWMODEL *pmalletPSA;
//NEWMODEL *psharkyPSA;

//gameCtrl.dropOutFlag==FALSE
NEWMODEL *pSky;

VECTOR	BallStartPos;	// These are tempory for demo
VECTOR	GloveStartPos;

int		gameScore;

// overlays are now in generic. nmes are now in the level
//TextureBankType *pOvlBank,*pWldBank,*pNMEBank;
TextureBankType *pWldBank;
BFF_Header *Level_BFF = NULL;

extern objectSegDataType  	*GloveSeg;

void pauseBegin();


#ifdef TWOLEVEL_DEMO
	#define NUM_DEMOVERLAYS 3
	OVERLAY demOvl[NUM_DEMOVERLAYS];
	OVERLAY prog, hasfrnt;
#endif

ULONG frmCols[]={0x007f00, 0x00007f00, 0x00007f00, 0x00004f7f, 0x0000007f};


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

// Note - "nextlevel" is defined as "HUB8" or "WAYROOM" where it should be a lookup-hub
// and many levels need to be special-cased


LEVELINFO LevelInfo[] =
{
//	Note - Needs to match the level numbers in MENU.H
//   Music track,	Next Level,			world			    level id

	{TRACK_HUB7,	TITLE,				HUB				},	// TESTMESH,
	{TRACK_HUB7,	TITLE,				HUB				},	// HUB1,		//0	
	{TRACK_HUB7,	TITLE,				HUB				},	// HUB2,		//1 
	{TRACK_HUB7,	TITLE,				HUB				},	// HUB3,		//2 
	{TRACK_HUB7,	TITLE,				HUB				},	// HUB4,		//3 
	{TRACK_HUB7,	TITLE,				HUB				},	// HUB5,		//4 
	{TRACK_HUB7,	TITLE,				HUB				},	// HUB6,		//5 
	{TRACK_HUB7,	TITLE,				HUB				},	// HUB7,		//6 
	{TRACK_HUB8,	TITLE,				HUB				},	// HUB8,		//7  

	{TRACK_HUB7,	TITLE,				HUB				},	// CAVE,		//8
	{TRACK_HUB7,	TITLE,				HUB				},	// ACOURSE,	//9

	{TRACK_AT1,		ATLANTIS2,			ATLANTIS		},	// ATLANTIS1,//10 
	{TRACK_AT2,		ATLANTIS3,			ATLANTIS		},	// ATLANTIS2,//11
	{TRACK_AT3,		ATLANTISBOSS,		ATLANTIS		},	// ATLANTIS3,//12
	{TRACK_ATBOSS,	HUB8,				ATLANTIS		},	// ATLANTISBOSS,	//13
	{TRACK_XTRA1,	WAYROOM,			ATLANTIS		},	// ATLANTISBONUS,//14

	{TRACK_CA1,		CARNIVAL2,			CARNIVAL		},	// CARNIVAL1, 	//15
	{TRACK_CA2,		CARNIVAL3,			CARNIVAL		},	// CARNIVAL2,	//16
	{TRACK_CA3,		CARNIVALBOSS,		CARNIVAL		},	// CARNIVAL3,	//17
	{TRACK_CABOSS,	HUB8,				CARNIVAL		},	// CARNIVALBOSS,	//18
	{TRACK_CABONUS,	WAYROOM,			CARNIVAL		},	// CARNIVALBONUS,//19

	{TRACK_PI1,		PIRATES2,			PIRATES			},	// PIRATES1,	  	//20
	{TRACK_PI2,		PIRATES3,			PIRATES			},	// PIRATES2,  	//21
	{TRACK_PI3,		PIRATESBOSS,		PIRATES			},	// PIRATES3,  	//22
	{TRACK_PIBOSS,	HUB8,				PIRATES			},	// PIRATESBOSS,	//23
	{TRACK_XTRA2,	WAYROOM,			PIRATES			},	// PIRATESBONUS,	//24

	{TRACK_PR1,		PREHISTORIC2,		PREHISTORIC		},	// PREHISTORIC1, //25
	{TRACK_PR2,		PREHISTORIC3,		PREHISTORIC		},	// PREHISTORIC2, //26
	{TRACK_PR3,		PREHISTORICBOSS,	PREHISTORIC		},	// PREHISTORIC3, //27
	{TRACK_PRBOSS,	HUB8,				PREHISTORIC		},	// PREHISTORICBOSS,	//28
	{TRACK_XTRA3,	WAYROOM,			PREHISTORIC		},	// PREHISTORICBONUS,	//29

	{TRACK_FF1,		FEAR2,				FORTRESS		},	// FEAR1,  		//30
	{TRACK_FF2,		FEAR3,				FORTRESS		},	// FEAR2,  		//31
	{TRACK_FF3,		FEARBOSS,			FORTRESS		},	// FEAR3, 		//32
	{TRACK_XTRA4,	HUB8,				FORTRESS		},	// FEARBOSS, 	//33
	{TRACK_XTRA4,	WAYROOM,			FORTRESS		},	// FEARBONUS,	//34

	{TRACK_SP1,		SPACE2B,			SPACE			},	// SPACE2A,		//35
	{TRACK_SP2,		SPACE3,				SPACE			},	// SPACE2B,		//36
	{TRACK_SP3,		SPACEBOSS2,			SPACE			},	// SPACE3,		//37
	{TRACK_SPBOSS,	TITLE,				SPACE			},	// SPACEBOSS1, 	//38
	{TRACK_SPBOSS,	HUB8,				SPACE			},	// SPACEBOSS2, 	//39
	{TRACK_XTRA5,	WAYROOM,			SPACE			},	// SPACEBONUS, 	//40

	{TRACK_HUB7,	TITLE,				HUB				},	// WAYROOM,	  	//41
	{TRACK_HUB7,	TITLE,				ATLANTIS		},	// ATTEST,
	{TRACK_HUB7,	TITLE,				CARNIVAL		},	// CATEST,
	{TRACK_HUB7,	TITLE,				PIRATES			},	// PITEST,
	{TRACK_HUB7,	TITLE,				PREHISTORIC		},	// PREHISTORICTEST,
	{TRACK_HUB7,	TITLE,				FORTRESS		},	// FEARTEST,
	{TRACK_HUB7,	TITLE,				SPACE			},	// SPACETEST,
	{TRACK_HUB7,	TITLE,				HUB				},	// INTRO,	  	//42
};

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












void showFrameRate(int frm) // frame rate and other dev stuff
{
	int col=frm;
	static SPRITEX *pCamCase=NULL;

	if(col>4)
		col=4;

	*(ULONG *)&(sprctrl.r)=frmCols[col];
	sprctrl.scalex=4096;
	sprctrl.scaley=4096;
	if(frm<10)
		spritePrint(fontList[0]+(0x10+frm), -140,100,0);
	else
		spritePrint(fontList[0]+('!'-0x20), -140,100,0);

	if(CamVars.flags)
	{
		if(!pCamCase)
		{
//			DB("Finding tex ...\n");
			pCamCase=textureFindInAllBanks("CAMCASE");
		}
//		DB("Printing %p\n", pCamCase);

		sprctrl.r=sprctrl.g=sprctrl.b=128;
		sprctrl.scalex=5192;
		sprctrl.scaley=4096;
		spritePrint(pCamCase, -96,100,0);
	}
}


GAME_CTRL	gameCtrl;

void gameInitGameStuff(void)
{
	GsF_LIGHT light;

	Effects_LevelStart();
/*
	pRipplePSA=LoadPSA("WORLDS\\GENERIC\\NME\\RIPPLE.PSA");
	objectSetupSegmentSort(pRipplePSA);
	pRipplePSA->globalscale.vx=512;
	pRipplePSA->globalscale.vy=512;
	pRipplePSA->globalscale.vz=512;

	pWakePSA=LoadPSA("WORLDS\\GENERIC\\NME\\WAKE.PSA");
	objectSetupSegmentSort(pWakePSA);
	pWakePSA->globalscale.vx=512;
	pWakePSA->globalscale.vy=512;
	pWakePSA->globalscale.vz=512;
*/
	Load_And_Init_Ball();
	Load_And_Init_Glove();	

	// Init memory card file system
//	InitCards(); //test stuff for cards

	//plionfishPSA=LoadPSA("WORLDS\\ATLANTIS\\NME\\LIONFISH.PSA");
	//pmalletPSA=LoadPSA("WORLDS\\ATLANTIS\\NME\\MALLET.PSA");
	//psharkyPSA=LoadPSA("WORLDS\\ATLANTIS\\NME\\GENERALW.PSA");

	Load_And_Init_Tips();	// will have to be level and language dependant

	gameCtrl.fadeIn=0;
	gameCtrl.fadeOut=0;
	gameCtrl.gameActive=TRUE;
	gameCtrl.state=TRUE;
	gameCtrl.select=0;
	gameCtrl.dropOutFlag=GAME_INLEVEL;
	gameCtrl.nextLevel = TITLE;
	gameCtrl.MrTipActive=FALSE;
 	light.vx = -2896;
	light.vy = 2896;
	light.vz = 0;
	light.r  = 255>>1;
	light.g  = 255>>1;
	light.b  = 255>>1;

	GsSetFlatLight(0, &light);
 	GsSetAmbient(127*16, 127*16, 127*16); //ONE/2,ONE/2,ONE/2);

#ifdef TWOLEVEL_DEMO
	#if PALMODE==YES
		overlaySetupAndAdd(demOvl+0,	textureFindInAllBanks("ISLLOGO"),	256,32,0, 0);
		overlaySetupAndAdd(&hasfrnt,	textureFindInAllBanks("HASFRNT"),	256,20,0, 0);
		overlaySetupAndAdd(demOvl+1,	textureFindInAllBanks("HASBACK"),	256,32,0, 0);
		overlaySetupAndAdd(demOvl+2,	textureFindInAllBanks("E3"),		256,32,0, 0);
	#else
		overlaySetupAndAdd(demOvl+0,	textureFindInAllBanks("ISLLOGO"),	256,32+2,0, 0);
		overlaySetupAndAdd(&hasfrnt,	textureFindInAllBanks("HASFRNT"),	256,20+24,0, 0);
		overlaySetupAndAdd(demOvl+1,	textureFindInAllBanks("HASBACK"),	256,32+24,0, 0);
		overlaySetupAndAdd(demOvl+2,	textureFindInAllBanks("E3"),		256,32+18,0, 0);
	// ick. No. Redraw.
	//	demOvl[1].scaleY = 3000;
	//	hasfrnt.scaleY = 3000;
	#endif

		demOvl[0].a=0;
		demOvl[1].a=0;
		hasfrnt.a=0;
		demOvl[2].a=0;
		overlaySetupAndAdd(&prog,	textureFindInAllBanks("PROG"),		240,230,0, 0);
#endif
//	overlayssprpointer=textureLoadSPT("GFX\\OVERLAYS.SPT");
}


void gameReleaseGameStuff()
{
	overlayClearAll();
	ClearAllText();

	ReleaseLandscapeFile();


//	objectFree(pRipplePSA,NULL);
//	objectFree(pWakePSA,NULL);

// tbd
// These belong in hand.c/ball.c, along with the loads, really
	objectFree(pGlovePSA,NULL);
	objectFree(pRotorPSA,NULL);
	objectFree(pBallPSA,NULL);
	objectFree(pCballPSA,NULL);
	objectFree(pPlasterPSA,NULL);
	objectFree(pPhongPSA,NULL);
	FREE(GloveSeg);



// sky is now BFF'd
//	if(pSky)
//		objectFree(pSky, NULL);

//	FreeWorld(pWld);	// world is now BFF'd
//	FREE(pWld->pZones);	// I think this one's a bug in FreeWorld?
//	FREE(pWld);	// the menu doesn't do this either... oops?

// Yes, this should be done earlier/differently, but for now, it's necessary
	textureDestroyBank(pWldBank);
	textureUnloadBank(pWldBank);

// Still to do - two files loaded by collide.c
// (level.RAW, level.DAT)
//	releaseCollision();	// coldata is now part of the BFF and doesn't need freeing

// undo stuff for the ADD_TEXT macro

	Free_Tips();

	if(Level_BFF)
	{
		BFF_ReleaseFile(Level_BFF);
		Level_BFF = NULL;
	}

}



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

#define SP_FADE 15

#ifdef TWOLEVEL_DEMO
void gameDoDemoOverlayBollox(void)
{
	static int thisOverlay=0;
	static int target=255;
	static int timer=0;

	int value=(int)demOvl[thisOverlay].a;

	if(timer<=0)
	{
		if(target>value)
		{
			value+=SP_FADE;
			if(value>=target)
			{	// we're now at our brightest
				value=target;
				target=0;
				timer=100;
			}
		}
		else
		{
			value-=SP_FADE;
			if(value<=target)
			{
				value=target;
				target=255;
				demOvl[thisOverlay].a=(UBYTE)value;
				thisOverlay++;
				if(thisOverlay==NUM_DEMOVERLAYS)
					thisOverlay=0;
			}
		}
	}

	timer--;

	demOvl[thisOverlay].a=(UBYTE)value;
//	if(thisOverlay==1) // stinky pooey bodge that is all Flynn's fault
//		hasfrnt.a=(UBYTE)value;
	hasfrnt.a = demOvl[1].a;	// lesser-spotted version of the bodge that works better :)
}
#endif

void gameFrame(void)
{
	ULONG	file;

	if (gameInfo.mode!=GAMEMODE_RESTART) gameInfo.mode=GAMEMODE_DEMO;

	switch(gameInfo.mode)
	{
	case GAMEMODE_DEMO:
		//atDemoFrame();
		FASTSTACK();

		SFXUpdate3D();

		Update_All_Effects();
		waterUpdate();
 		//Draw_All_Effects();
#ifdef TWOLEVEL_DEMO
		gameDoDemoOverlayBollox();
#endif
		overlayPrintAll();
		ShowText();
	
		//Kill_All_Effects(); //should put at end of level

		// Temp moving platforms stuff
		//pCollBox->cb.oldpX=pCollBox->cb.pX;
		//pCollBox->cb.oldpY=pCollBox->cb.pY;
		//pCollBox->cb.oldpZ=pCollBox->cb.pZ;

		//collboxMoveDynamicBox(pCollBox, 0, (rsin(gameInfo.frame*16)-4096)*128, rcos(gameInfo.frame*16)*128);

		//pCollBox->pY=(rsin(gameInfo.frame*16)*256);
		// End of moving plat. stuff

		//platformDrawDynamicBoxes();

	
		TIMER_START(TIMER_BALLGLOVE);
		Control_Ball_And_Glove();
		TIMER_STOP(TIMER_BALLGLOVE);

	SLOWSTACK();
		break;
	case GAMEMODE_PREVIEW:
		viewerFrame();
		break;
	case GAMEMODE_RESTART:
		//printf ("restarting\n");

#if RECORDKEYS == YES
		if (gameInfo.keyRecordFlag==RECORD)
		{
			if((file=PCcreat("record.dem",1)) == -1)
			{
				printf ("Error creating file record.dem\n");
				return;
			}
			else
			{
				PCwrite(file,(UBYTE*)keyRecord,32768);// 64k for main ptr array
				PCclose(file);
				//FREE( (UBYTE*)keyRecord );// Very bad way of doing this
			}
		}
#endif
		levelRestart();
		gameInfo.mode=GAMEMODE_DEMO;
		if (gameInfo.keyRecordFlag==RECORD)
			gameInfo.keyRecordFlag=PLAYBACK;

		keyRecordCount=0;
		break;

	}


	gameInfo.frame++;
}


/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
// This is for when Glove dies and the level has to be restarted
void	levelRestart(void)
{
	resetBall();
	resetGlove();


	Init_Camera();
	Respawn_Enemies();

	Use_Hoop(lasthoopused);	// nb - after the respawn

	UpdateOverlays();
}

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

DYNCOLLBOX *pCollBox;
char *sBonusTimer;

OVERLAY		ovlHealth[3];
TEXT		*lifePtr;
ULONG		file;
void gameMainGame(int lev)
{
	//OVERLAY ovlHealth[3], ovlLives;
	OVERLAY	ovlLives;
	int i;
	char *LevNamePtr;
	int track;

	DB("Attempting to load level %d\n", lev);
	pWaterSprites=NULL;
	track = LevelInfo[lev].musictrack;	//track = TRACK_HUB8;
	world = LevelInfo[lev].world;
	gameScore=0;

//	printf(">>> Entering gameMainGame\n");
//	memoryShow();

	overlayClearAll();

	gameInitGameStuff();
	Init_Camera();


	for(i=0; i<GloveCtrl.health; i++)
	{
#if PALMODE==YES
		overlaySetupAndAdd(ovlHealth+i, textureFindInAllBanks("HEALTH01"), 32+(i*24), 232, 0, 0);
#else
		overlaySetupAndAdd(ovlHealth+i, textureFindInAllBanks("HEALTH01"), 32+(i*24), 232-8, 0, 0);
#endif
	}

#if PALMODE==YES
	overlaySetupAndAdd(&ovlLives, textureFindInAllBanks("NUMLIVES01"), 453, 228, 0, 0);
#else
	overlaySetupAndAdd(&ovlLives, textureFindInAllBanks("NUMLIVES01"), 453, 228-8, 0, 0);
#endif

	ClearAllText();

	messctrl.font=fontList[0];

#if PALMODE==YES
	NEW_TEXT(428,232, 128,128,0,255, 4096,4096, FALSE, "3*", FALSE);
#else
	NEW_TEXT(428,232-16, 128,128,0,255, 4096,4096, FALSE, "3*", FALSE);
#endif

	lifePtr=mtext;

	lifePtr->flags=TEXT_SHADED;

	lifePtr->r1=128;
	lifePtr->g1=40;
	lifePtr->b1=8;

//	textureFogPaletteOn();// enable fogging textures for each texture bank loaded
	pSky=NULL;
	object_atlantis_waterflag = 0;
	platformCreateDynamicBoxList();
	modelctrl.halfgouraud=0;
	modelctrl.subdivflag=TRUE;
	loadlnd_allow_platforms=TRUE;

	gameInfo.levelType=NORMAL_LEVEL;
	

// set the default fog to far off...
	SETRGBC(clscol.r, 0,0,0, GPU_COM_F4);
	lscapeFogStartZ = 5000;
	lscapeFogEndZ	= 5800;
	lscapeFogFlatZ	= 6000;
	SETRGBC(lscapeFogColour.r,255,255,255,255);

	switch(lev)
	{
	case TESTMESH:
		pWldBank=textureLoadBank("WORLDS\\TESTMESH\\TESTMESH\\TESTMESH.SPT");
		world=HUB;
		break;
  	case HUB1:
  	case HUB2:
  	case HUB3:
  	case HUB4:
  	case HUB5:
  	case HUB6:
  	case HUB7:
	case HUB8:
//		textureFogPaletteOff();// enable fogging textures for hub 8 to stop Tim moaning ...
		pWldBank=textureLoadBank("WORLDS\\HUB\\HUB8\\HUB8.SPT");
		SETRGBC(clscol.r, 128,255,255, GPU_COM_F4);
		SETRGBC(lscapeFogColour.r, 0,128,0, GPU_COM_F4);
		lscapeFogStartZ = 10000;
		lscapeFogEndZ	= 10200;
		lscapeFogFlatZ	= 10400;


		BallStartPos.vx=GloveStartPos.vx=0*4096;
		BallStartPos.vy=GloveStartPos.vy=-100*4096;
		BallStartPos.vz=GloveStartPos.vz=-800*4096;
		break;
	case CAVE:
		pWldBank=textureLoadBank("WORLDS\\HUB\\CAVE\\CAVE.SPT");
		break;


	case ATLANTIS1:
		pWldBank=textureLoadBank("WORLDS\\ATLANTIS\\L1\\AT1.SPT");
		SETRGBC(clscol.r, 255,255,162, GPU_COM_F4);
		world=ATLANTIS;

//		lscapeFogStartZ = 3200;
//		lscapeFogEndZ	= 3800;
//		lscapeFogFlatZ	= 4800;

//		lscapeFogStartZ = 3400;
//		lscapeFogEndZ	= 4000;
//		lscapeFogFlatZ	= 4800;

		break;
	case ATLANTIS2:
		pWldBank=textureLoadBank("WORLDS\\ATLANTIS\\L2\\AT2.SPT");
//		SETRGBC(clscol.r, 0,0,255, GPU_COM_F4);
		SETRGBC(clscol.r, 41,193,175, GPU_COM_F4);
		break;
	case ATLANTIS3:
		pWldBank=textureLoadBank("WORLDS\\ATLANTIS\\L3\\AT3.SPT");
		SETRGBC(clscol.r, 41,193,175, GPU_COM_F4);
		break;
	case ATTEST:
		pWldBank=textureLoadBank("WORLDS\\ATLANTIS\\TEST\\ATTEST.SPT");
		SETRGBC(clscol.r, 255,255,162, GPU_COM_F4);
		break;

	case ATLANTISBOSS:
		pWldBank=textureLoadBank("WORLDS\\ATLANTIS\\BOSS\\ATBOSS.SPT");
		break;
	case ATLANTISBONUS:
		pWldBank=textureLoadBank("WORLDS\\ATLANTIS\\BONUS\\ATBONUS.SPT");
		SETRGBC(clscol.r, 0,255,255, GPU_COM_F4);
		gameInfo.levelType=BONUS_LEVEL;
		break;
	
	case CARNIVAL1:
		pWldBank=textureLoadBank("WORLDS\\CARNIVAL\\L1\\CA1.SPT");
//		SETRGBC(clscol.r, 255,128,0, GPU_COM_F4);
		SETRGBC(clscol.r, 240,112,0, GPU_COM_F4);
		break;
	case CARNIVAL2:
		pWldBank=textureLoadBank("WORLDS\\CARNIVAL\\L2\\CA2.SPT");
		SETRGBC(clscol.r, 240,112,0, GPU_COM_F4);
		break;
	case CARNIVAL3:
		pWldBank=textureLoadBank("WORLDS\\CARNIVAL\\L3\\CA3.SPT");
		SETRGBC(clscol.r, 255,127,0, GPU_COM_F4);
		break;
	case CARNIVALBOSS:
		pWldBank=textureLoadBank("WORLDS\\CARNIVAL\\BOSS\\CABOSS.SPT");
		break;
	case CARNIVALBONUS:
		pWldBank=textureLoadBank("WORLDS\\CARNIVAL\\BONUS\\CABONUS.SPT");
		gameInfo.levelType=BONUS_LEVEL;
		break;
	case CATEST:
		pWldBank=textureLoadBank("WORLDS\\CARNIVAL\\TEST\\CATEST.SPT");
		break;

	case PIRATES1:
		pWldBank=textureLoadBank("WORLDS\\PIRATES\\L1\\PI1.SPT");
		SETRGBC(clscol.r, 255,122,66, GPU_COM_F4);
		break;
	case PIRATES2:
		pWldBank=textureLoadBank("WORLDS\\PIRATES\\L2\\PI2.SPT");
		SETRGBC(clscol.r, 0,0,64, GPU_COM_F4);
		break;
	case PIRATES3:
		pWldBank=textureLoadBank("WORLDS\\PIRATES\\L3\\PI3.SPT");
		break;

	case PIRATESBOSS:
		pWldBank=textureLoadBank("WORLDS\\PIRATES\\BOSS\\PIBOSS.SPT");
		SETRGBC(clscol.r, 0,0,240, GPU_COM_F4);
		break;
	case PIRATESBONUS:
		pWldBank=textureLoadBank("WORLDS\\PIRATES\\BONUS\\PIBONUS.SPT");
		gameInfo.levelType=BONUS_LEVEL;

		break;
	case PITEST:
		pWldBank=textureLoadBank("WORLDS\\PIRATES\\TEST\\PITEST.SPT");
		break;

	case PREHISTORICTEST:
		pWldBank=textureLoadBank("WORLDS\\PREHIST\\TEST\\PRTEST.SPT");
		break;
	case PREHISTORIC1:
		pWldBank=textureLoadBank("WORLDS\\PREHIST\\L1\\PR1.SPT");
		break;
	case PREHISTORIC2:
		pWldBank=textureLoadBank("WORLDS\\PREHIST\\L2\\PR2.SPT");
		break;
	case PREHISTORIC3:
		pWldBank=textureLoadBank("WORLDS\\PREHIST\\L3\\PR3.SPT");
		break;
	case PREHISTORICBOSS:
		pWldBank=textureLoadBank("WORLDS\\PREHIST\\BOSS\\PRBOSS.SPT");
		break;
	case PREHISTORICBONUS:
		pWldBank=textureLoadBank("WORLDS\\PREHIST\\BONUS\\PRBONUS.SPT");
		gameInfo.levelType=BONUS_LEVEL;

		break;

	case FEAR1:
		pWldBank=textureLoadBank("WORLDS\\FEAR\\L1\\FF1.SPT");
		break;
	case FEAR2:
		pWldBank=textureLoadBank("WORLDS\\FEAR\\L2\\FF2.SPT");
		break;
	case FEAR3:
		pWldBank=textureLoadBank("WORLDS\\FEAR\\L3\\FF3.SPT");
		break;
	case FEARBONUS:
		pWldBank=textureLoadBank("WORLDS\\FEAR\\BONUS\\FFBONUS.SPT");
		gameInfo.levelType=BONUS_LEVEL;
		break;
	case FEARBOSS:
		pWldBank=textureLoadBank("WORLDS\\FEAR\\BOSS\\FFBOSS.SPT");
		break;
	case FEARTEST:
		pWldBank=textureLoadBank("WORLDS\\FEAR\\TEST\\FFTEST.SPT");
		break;


	case SPACE2A:
		pWldBank=textureLoadBank("WORLDS\\OOTW\\L1\\SP1.SPT");
		break;
	case SPACE2B:
		pWldBank=textureLoadBank("WORLDS\\OOTW\\L2\\SP2.SPT");
		break;
	case SPACE3:
		pWldBank=textureLoadBank("WORLDS\\OOTW\\L3\\SP3.SPT");
		break;
	case SPACETEST:
		pWldBank=textureLoadBank("WORLDS\\OOTW\\TEST\\SPTEST.SPT");
		break;

	case SPACEBOSS1:
		pWldBank=textureLoadBank("WORLDS\\OOTW\\BOSS\\SPBOSS.SPT");
		break;
	case SPACEBONUS:
		pWldBank=textureLoadBank("WORLDS\\OOTW\\BONUS\\SPBONUS.SPT");
		gameInfo.levelType=BONUS_LEVEL;

		break;
	case WAYROOM:
		pWldBank=textureLoadBank("WORLDS\\HUB\\WAYROOM\\WAYROOM.SPT");
		break;

	default:
		DB("WARNING: No texture bank has been loaded (other than generic)\n");
	}
	//platformLoadFragmentBodge();

	if(*(u_long *)(&lscapeFogColour.r) == 0xffffffff)
		lscapeFogColour = clscol;

	textureDownloadBank(pWldBank);
	textureDestroyBank(pWldBank);

	LoadMusic();
	weatherInitialise(WEATHER_NULL);

	ballOldPos.vx=ballPos.vx=glovePos.vx=BallStartPos.vx=GloveStartPos.vx=0;
	ballOldPos.vy=ballPos.vy=glovePos.vy=BallStartPos.vy=GloveStartPos.vy=0;
	ballOldPos.vz=ballPos.vz=glovePos.vz=BallStartPos.vz=GloveStartPos.vz=0;

	switch(lev)
	{
	case TESTMESH:
		//setupCollision("WORLDS\\TESTMESH\\TESTMESH\\TESTMESH");
		Level_BFF = BFF_LoadFile("WORLDS\\TESTMESH\\TESTMESH.BFF");
		setupCollision("TESTMESH");

		//ballPos.vy=glovePos.vy=BallStartPos.vy=GloveStartPos.vy=-10000*4096;

		BallStartPos.vx=GloveStartPos.vx=300*4096;
		BallStartPos.vy=GloveStartPos.vy=-200*4096;
		BallStartPos.vz=GloveStartPos.vz=-600*4096;

		ParseLandscapeFile("WORLDS\\TESTMESH\\TESTMESH\\TESTMESH.LEV");
		break;

	case HUB1:
		Level_BFF = BFF_LoadFile("WORLDS\\HUB\\HUB1.BFF");
		setupCollision("HUB1");
		ParseLandscapeFile("WORLDS\\HUB\\HUB1\\HUB1.LEV");
		break;
//		goto GENERICHUB;
	case HUB2:
		Level_BFF = BFF_LoadFile("WORLDS\\HUB\\HUB2.BFF");
		setupCollision("HUB2");
		ParseLandscapeFile("WORLDS\\HUB\\HUB2\\HUB2.LEV");
		break;
//		goto GENERICHUB;
 	case HUB3:
		Level_BFF = BFF_LoadFile("WORLDS\\HUB\\HUB3.BFF");
		setupCollision("HUB3");
		ParseLandscapeFile("WORLDS\\HUB\\HUB3\\HUB3.LEV");
		break;
//		goto GENERICHUB;
	case HUB4:
		Level_BFF = BFF_LoadFile("WORLDS\\HUB\\HUB4.BFF");
		setupCollision("HUB4");
		ParseLandscapeFile("WORLDS\\HUB\\HUB4\\HUB4.LEV");
		break;
//		goto GENERICHUB;
	case HUB5:
		Level_BFF = BFF_LoadFile("WORLDS\\HUB\\HUB5.BFF");
		setupCollision("HUB5");
		ParseLandscapeFile("WORLDS\\HUB\\HUB5\\HUB5.LEV");
		break;
//		goto GENERICHUB;
	case HUB6:
		Level_BFF = BFF_LoadFile("WORLDS\\HUB\\HUB6.BFF");
		setupCollision("HUB6");
		ParseLandscapeFile("WORLDS\\HUB\\HUB6\\HUB6.LEV");
		break;
//		goto GENERICHUB;
 	case HUB7:
		Level_BFF = BFF_LoadFile("WORLDS\\HUB\\HUB7.BFF");
		setupCollision("HUB7");
		ParseLandscapeFile("WORLDS\\HUB\\HUB7\\HUB7.LEV");
		break;
//		goto GENERICHUB;
	case HUB8:
		Level_BFF = BFF_LoadFile("WORLDS\\HUB\\HUB8.BFF");
		setupCollision("HUB8");
		ParseLandscapeFile("WORLDS\\HUB\\HUB8\\HUB8.LEV");
		break;
//		goto GENERICHUB;

//	GENERICHUB:

//		BallStartPos.vx=GloveStartPos.vx=0*4096;
//		BallStartPos.vy=GloveStartPos.vy=-100*4096;
//		BallStartPos.vz=GloveStartPos.vz=-800*4096;
	
		//weatherInitialise(WEATHER_BIRDY);
		//weatherInitialise(WEATHER_RAIN);
//		weatherInitialise(WEATHER_THUNDER|WEATHER_RAIN);
//		ParseLandscapeFile("WORLDS\\HUB\\HUB8\\HUB8.LEV");
//		break;

	case CAVE:
		Level_BFF = BFF_LoadFile("WORLDS\\HUB\\CAVE.BFF");
		setupCollision("CAVE");
		ParseLandscapeFile("WORLDS\\HUB\\CAVE\\CAVE.LEV");
		break;

	case ATLANTIS1:
		Level_BFF = BFF_LoadFile("WORLDS\\ATLANTIS\\AT1.BFF");
		setupCollision("AT1");

		object_atlantis_waterflag = 1;

  //		textureFogPaletteOff();

// As soon as we've got a proper lnd, it'll be time to move the lscape parse to after the start position define
		ParseLandscapeFile("WORLDS\\ATLANTIS\\L1\\AT1.LEV");

		break;

	case ATLANTIS2:
		Level_BFF = BFF_LoadFile("WORLDS\\ATLANTIS\\AT2.BFF");
		setupCollision("AT2");
		BallStartPos.vx=GloveStartPos.vx=0.08*4096;
		BallStartPos.vy=GloveStartPos.vy=-133.12*4096; // ?
		BallStartPos.vz=GloveStartPos.vz=79*4096;
		ParseLandscapeFile("WORLDS\\ATLANTIS\\L2\\AT2.LEV");
		break;

	case ATLANTIS3:
		Level_BFF = BFF_LoadFile("WORLDS\\ATLANTIS\\AT3.BFF");
		setupCollision("AT3");

		BallStartPos.vx=GloveStartPos.vx=0.08*4096;
		BallStartPos.vy=GloveStartPos.vy=-133.12*4096; // ?
		BallStartPos.vz=GloveStartPos.vz=79*4096;
		ParseLandscapeFile("WORLDS\\ATLANTIS\\L3\\AT3.LEV");
		break;

	case ATLANTISBOSS:
		Level_BFF = BFF_LoadFile("WORLDS\\ATLANTIS\\ATBOSS.BFF");
		setupCollision("ATBOSS");
		ParseLandscapeFile("WORLDS\\ATLANTIS\\BOSS\\ATBOSS.LEV");
		break;
	case ATLANTISBONUS:

		Level_BFF = BFF_LoadFile("WORLDS\\ATLANTIS\\ATBONUS.BFF");
		setupCollision("ATBONUS");
		BallStartPos.vy=GloveStartPos.vy=-80*4096;
		ParseLandscapeFile("WORLDS\\ATLANTIS\\BONUS\\ATBONUS.LEV");
		break;

	case ATTEST:
// note that the BFF load has to come after the music & sprite files have been loaded in
		Level_BFF = BFF_LoadFile("WORLDS\\ATLANTIS\\ATTEST.BFF");

		setupCollision("ATTEST");
		BallStartPos.vx=GloveStartPos.vx=0.08*4096;
		BallStartPos.vy=GloveStartPos.vy=-133.12*4096; // ?
		BallStartPos.vz=GloveStartPos.vz=79*4096;
//		loadlnd_load_scape = 1;
		ParseLandscapeFile("WORLDS\\ATLANTIS\\TEST\\ATTEST.LEV");
//		loadlnd_load_scape = 0;
		break;

	case CARNIVAL1:
		Level_BFF = BFF_LoadFile("WORLDS\\CARNIVAL\\CA1.BFF");
		setupCollision("CA1");
		BallStartPos.vy=GloveStartPos.vy=-50*4096; // ?

		ParseLandscapeFile("WORLDS\\CARNIVAL\\L1\\CA1.LEV");
		break;

	case CARNIVAL2:
		Level_BFF = BFF_LoadFile("WORLDS\\CARNIVAL\\CA2.BFF");
		setupCollision("CA2");

		BallStartPos.vx=GloveStartPos.vx=-1992*4096;
		BallStartPos.vy=GloveStartPos.vy=-50*4096; // ?
		BallStartPos.vz=GloveStartPos.vz=-397*4096;

		ParseLandscapeFile("WORLDS\\CARNIVAL\\L2\\CA2.LEV");
		break;

	case CARNIVAL3:
		Level_BFF = BFF_LoadFile("WORLDS\\CARNIVAL\\CA3.BFF");
		setupCollision("CA3");

		BallStartPos.vx=GloveStartPos.vx=345*4096;
		BallStartPos.vy=GloveStartPos.vy=-70*4096; // ?
		BallStartPos.vz=GloveStartPos.vz=1444*4096;

		ParseLandscapeFile("WORLDS\\CARNIVAL\\L3\\CA3.LEV");
		break;

	case CARNIVALBOSS:
		Level_BFF = BFF_LoadFile("WORLDS\\CARNIVAL\\CABOSS.BFF");
		setupCollision("CABOSS");
		ParseLandscapeFile("WORLDS\\CARNIVAL\\BOSS\\CABOSS.LEV");
		break;

	case CARNIVALBONUS:
		Level_BFF = BFF_LoadFile("WORLDS\\CARNIVAL\\CABONUS.BFF");
		setupCollision("CABONUS");
		ParseLandscapeFile("WORLDS\\CARNIVAL\\BONUS\\CABONUS.LEV");
		break;

	case CATEST:
		Level_BFF = BFF_LoadFile("WORLDS\\CARNIVAL\\CATEST.BFF");
		setupCollision("CATEST");
		BallStartPos.vx=GloveStartPos.vx=-700*4096;
		BallStartPos.vy=GloveStartPos.vy= -20*4096;
		BallStartPos.vz=GloveStartPos.vz=   0*4096;
		ParseLandscapeFile("WORLDS\\CARNIVAL\\TEST\\CATEST.LEV");
		break;


	case PIRATES1:
		Level_BFF = BFF_LoadFile("WORLDS\\PIRATES\\PI1.BFF");
		setupCollision("PI1");

		BallStartPos.vx=GloveStartPos.vx=2589*4096;
		BallStartPos.vy=GloveStartPos.vy=500*4096;//-622*4096;
		BallStartPos.vz=GloveStartPos.vz=115*4096;

		ParseLandscapeFile("WORLDS\\PIRATES\\L1\\PI1.LEV");
		break;
	case PIRATES2:
		Level_BFF = BFF_LoadFile("WORLDS\\PIRATES\\PI2.BFF");
		setupCollision("PI2");

		BallStartPos.vx=GloveStartPos.vx=5*4096;
		BallStartPos.vy=GloveStartPos.vy=-20*4096;//-622*4096;
		BallStartPos.vz=GloveStartPos.vz=0*4096;

		ParseLandscapeFile("WORLDS\\PIRATES\\L2\\PI2.LEV");
		break;
	case PIRATES3:
		Level_BFF = BFF_LoadFile("WORLDS\\PIRATES\\PI3.BFF");
		setupCollision("PI3");

		BallStartPos.vx=GloveStartPos.vx=50*4096;
		BallStartPos.vy=GloveStartPos.vy=0;
		BallStartPos.vz=GloveStartPos.vz=100*4096;

		ParseLandscapeFile("WORLDS\\PIRATES\\L3\\PI3.LEV");
		break;

	case PIRATESBOSS:
		Level_BFF = BFF_LoadFile("WORLDS\\PIRATES\\PIBOSS.BFF");
		setupCollision("PIBOSS");
		ParseLandscapeFile("WORLDS\\PIRATES\\BOSS\\PIBOSS.LEV");
		break;
	case PIRATESBONUS:
		Level_BFF = BFF_LoadFile("WORLDS\\PIRATES\\PIBONUS.BFF");
		setupCollision("PIBONUS");
		ParseLandscapeFile("WORLDS\\PIRATES\\BONUS\\PIBONUS.LEV");
		break;
	case PITEST:
		Level_BFF = BFF_LoadFile("WORLDS\\PIRATES\\PITEST.BFF");
		setupCollision("PITEST");
//		BallStartPos.vy=GloveStartPos.vy=-200*4096;
		BallStartPos.vx=GloveStartPos.vx=-700*4096;
		BallStartPos.vy=GloveStartPos.vy= -20*4096;//-622*4096;
		BallStartPos.vz=GloveStartPos.vz=   0*4096;
		ParseLandscapeFile("WORLDS\\PIRATES\\TEST\\PITEST.LEV");
		break;



	case PREHISTORICTEST:
		Level_BFF = BFF_LoadFile("WORLDS\\PREHIST\\PRTEST.BFF");
		setupCollision("PRTEST");
		BallStartPos.vy=GloveStartPos.vy=-200*4096;

		ParseLandscapeFile("WORLDS\\PREHIST\\TEST\\PRTEST.LEV");
		break;

	case PREHISTORIC1:
		Level_BFF = BFF_LoadFile("WORLDS\\PREHIST\\PR1.BFF");
		setupCollision("PR1");

		BallStartPos.vy=GloveStartPos.vy=-200*4096;
		ParseLandscapeFile("WORLDS\\PREHIST\\L1\\PR1.LEV");
		weatherInitialise(WEATHER_SNOW);
		break;

	case PREHISTORIC2:
		Level_BFF = BFF_LoadFile("WORLDS\\PREHIST\\PR2.BFF");
		setupCollision("PR2");

		BallStartPos.vy=GloveStartPos.vy=-200*4096;
		ParseLandscapeFile("WORLDS\\PREHIST\\L2\\PR2.LEV");
		pBoulderPSA=BFF_IsModelLoaded("BOULDER",NULL);
		objectSetupSegmentSort(pBoulderPSA);
		pBoulderPSA->globalscale.vx=1360;
		pBoulderPSA->globalscale.vy=1360;
		pBoulderPSA->globalscale.vz=1360;


		break;

	case PREHISTORIC3:
		Level_BFF = BFF_LoadFile("WORLDS\\PREHIST\\PR3.BFF");
		setupCollision("PR3");

		BallStartPos.vy=GloveStartPos.vy=-200*4096;
		ParseLandscapeFile("WORLDS\\PREHIST\\L3\\PR3.LEV");
		break;

	case PREHISTORICBOSS:
		Level_BFF = BFF_LoadFile("WORLDS\\PREHIST\\PRBOSS.BFF");
		setupCollision("PRBOSS");

		ParseLandscapeFile("WORLDS\\PREHIST\\BOSS\\PRBOSS.LEV");
		weatherInitialise(WEATHER_SNOW);

		break;

	case PREHISTORICBONUS:
		Level_BFF = BFF_LoadFile("WORLDS\\PREHIST\\PRBONUS.BFF");
		setupCollision("PRBONUS");

		ParseLandscapeFile("WORLDS\\PREHIST\\BONUS\\PRBONUS.LEV");
		break;



	case FEAR1:
		Level_BFF = BFF_LoadFile("WORLDS\\FEAR\\FF1.BFF");
		setupCollision("FF1");

		ParseLandscapeFile("WORLDS\\FEAR\\L1\\FF1.LEV");
		weatherInitialise(WEATHER_THUNDER|WEATHER_RAIN);
		break;
	case FEAR2:
		Level_BFF = BFF_LoadFile("WORLDS\\FEAR\\FF2.BFF");
		setupCollision("FF2");

		ParseLandscapeFile("WORLDS\\FEAR\\L2\\FF2.LEV");
		weatherInitialise(WEATHER_THUNDER|WEATHER_RAIN);
		break;

	case FEAR3:
		Level_BFF = BFF_LoadFile("WORLDS\\FEAR\\FF3.BFF");
		setupCollision("FF3");

		BallStartPos.vx=GloveStartPos.vx=-1880*4096;
		BallStartPos.vy=GloveStartPos.vy=-225*4096;
		BallStartPos.vz=GloveStartPos.vz=4596*4096;

		ParseLandscapeFile("WORLDS\\FEAR\\L3\\FF3.LEV");
		weatherInitialise(WEATHER_THUNDER|WEATHER_RAIN);

		break;

	case FEARTEST:
		Level_BFF = BFF_LoadFile("WORLDS\\FEAR\\FFTEST.BFF");
		setupCollision("FFTEST");
		BallStartPos.vy=GloveStartPos.vy=-200*4096;

		ParseLandscapeFile("WORLDS\\FEAR\\TEST\\FFTEST.LEV");
		break;
	case FEARBOSS:
		Level_BFF = BFF_LoadFile("WORLDS\\FEAR\\FFBOSS.BFF");
		setupCollision("FFBOSS");
		ParseLandscapeFile("WORLDS\\FEAR\\BOSS\\FFBOSS.LEV");
		break;
	case FEARBONUS:
		Level_BFF = BFF_LoadFile("WORLDS\\FEAR\\FFBONUS.BFF");
		setupCollision("FFBONUS");
		BallStartPos.vy=GloveStartPos.vy=-200*4096;

		ParseLandscapeFile("WORLDS\\FEAR\\BONUS\\FFBONUS.LEV");
		break;



	case SPACE2A:
		Level_BFF = BFF_LoadFile("WORLDS\\OOTW\\SP1.BFF");
		setupCollision("SP1");
		BallStartPos.vy=GloveStartPos.vy=-200*4096;

		ParseLandscapeFile("WORLDS\\OOTW\\L1\\SP1.LEV");
		break;
	case SPACE2B:
		Level_BFF = BFF_LoadFile("WORLDS\\OOTW\\SP2.BFF");
		setupCollision("SP2");
		BallStartPos.vy=GloveStartPos.vy=-200*4096;

		ParseLandscapeFile("WORLDS\\OOTW\\L2\\SP2.LEV");
		break;

	case SPACE3:
		Level_BFF = BFF_LoadFile("WORLDS\\OOTW\\SP3.BFF");
		setupCollision("SP3");
		BallStartPos.vy=GloveStartPos.vy=-200*4096;

		ParseLandscapeFile("WORLDS\\OOTW\\L3\\SP3.LEV");
		break;

	case SPACETEST:
		Level_BFF = BFF_LoadFile("WORLDS\\OOTW\\SPTEST.BFF");
		setupCollision("SPTEST");
		BallStartPos.vy=GloveStartPos.vy=-200*4096;

		ParseLandscapeFile("WORLDS\\OOTW\\TEST\\SPTEST.LEV");
		break;

	case SPACEBOSS1:
		Level_BFF = BFF_LoadFile("WORLDS\\OOTW\\SPBOSS.BFF");
		setupCollision("SPBOSS");
		ParseLandscapeFile("WORLDS\\OOTW\\BOSS\\SPBOSS.LEV");
		break;

	case SPACEBONUS:
		Level_BFF = BFF_LoadFile("WORLDS\\OOTW\\SPBONUS.BFF");
		setupCollision("SPBONUS");
		ParseLandscapeFile("WORLDS\\OOTW\\BONUS\\SPBONUS.LEV");
		break;



	case WAYROOM:
		Level_BFF = BFF_LoadFile("WORLDS\\HUB\\WAYROOM.BFF");
		setupCollision("WAYROOM");
		ParseLandscapeFile("WORLDS\\HUB\\WAYROOM\\WAYROOM.LEV");
		break;

	default:
		// have a fit!
		DB("LEVEL UNPLAYABLE\n");
		CRASH;
	}

//	textureMakeScrolling(textureFindInAllBanks("CONV3"));


	{
		BFF_WorldHeader *head;
		head = (void *)BFF_FindNamedObject(BFF_WLD_ID, "WORLD");
		if(head)
		{
			pWld = &head->world;
		}
	}

	pSky = BFF_IsModelLoaded("SKY",NULL);	// bff-only version of LoadPSA

	gameInfo.level=lev;

//Startpos will/should have been defined in the parselandscape
	ballPos = BallStartPos;
	glovePos = GloveStartPos;

	{
		pGlovePSA->position.vx = glovePos.vx >>12;	// the camera init runs off the glovePSA
		pGlovePSA->position.vy = glovePos.vy >>12;
		pGlovePSA->position.vz = glovePos.vz >>12;
		pBallPSA->position.vx = ballPos.vx >>12;
		pBallPSA->position.vy = ballPos.vy >>12;
		pBallPSA->position.vz = ballPos.vz >>12;
		ballOldPos.vx=ballPos.vx;
		ballOldPos.vy=ballPos.vy;
		ballOldPos.vz=ballPos.vz;
		Init_Camera();
	}


 //	textureFogPaletteOff();

	// Main loop

// got rid of, coz we're using the XA tracks now...
/*
	if (cdmusic==YES)
	{
		CDInitialise();	// Dunno, but let's give this a whirl. I was having to open the door for a mo to wake the music up

		CDPlayTrack(1);
	}
*/
//	debugPrintf("main loop\n");

	padResetWhenLastUsed();
	gameInfo.timePadLastHit=padGetWhenLastUsed();

#if RECORDKEYS == NO
	if (gameInfo.keyRecordFlag==PLAYBACK)
	{
		(UBYTE*)keyRecord=fileLoad(gameInfo.sKeyDemo,0);
		keyRecordCount=0;
		gameInfo.keyRecordFlag=PLAYBACK;
		FREE( (UBYTE*)keyRecord );// Very bad way of doing this
	}
#else

#endif

	XA_SetMusicGoing(track, 1);	// **** ALL FILE LOADING NEEDS TO HAVE BEEN DONE BY NOW! ****


// repeated here coz setmusicgoing can be a time consuming one in worst case
	padResetWhenLastUsed();
	gameInfo.timePadLastHit=padGetWhenLastUsed();

	if(gameInfo.levelType==BONUS_LEVEL)
	{
		NEW_TEXT(256, 16, 128,128,0,255, 3072,3072, FALSE, "TIME", TRUE);
		mtext->flags=TEXT_SHADED;
		mtext->r1=128;
		mtext->g1=40;
		mtext->b1=8;

		NEW_TEXT(256, 32, 128,128,0,255, 2400,2400, FALSE, "", TRUE);
		mtext->flags=TEXT_SHADED;
		mtext->r1=128;
		mtext->g1=40;
		mtext->b1=8;

		sBonusTimer=mtext->message;
		gameInfo.timeAllowed=(180*100)*30; // = 3 mins in iframes
	}

	gameInfo.levelStartTime=iframe;
	while(gameCtrl.dropOutFlag==GAME_INLEVEL)
	{
		//DB("F=%d\n", framerate);

		FASTSTACK();
   		Start_Loop();
		
		timerDisplay();
   		SLOWSTACK();

		gameFrame();

		//textureDoScrolling();

		showFrameRate(framerate);
		
		if(gameInfo.levelType==BONUS_LEVEL)
		{
			int timeLeft=gameInfo.timeAllowed-(iframe-gameInfo.levelStartTime);
			if(timeLeft<=0)
			{
				gameCtrl.dropOutFlag=GAME_FAILEDBONUS; // TIMEDOUT is for demo
			}
			menuGetTimerString(timeLeft/30, sBonusTimer);
		}

		//FASTSTACK();

		End_Loop(framerate);
		TIMER_ENDFRAME;
		if(debounce[1] & PAD_R1)
			timerActive = !timerActive;

		if(debounce[1] & PAD_CIRCLE)
			GloveCtrl.lives++;

 		//SLOWSTACK();

#ifdef TWOLEVEL_DEMO
		if (gameInfo.keyRecordFlag!=PLAYBACK)
		{
			if((iframe-padGetWhenLastUsed())>LEVEL_TIMEOUT) // drop out if pad not touched for some time
			{
				DB("Level timeout!\n");
				gameCtrl.dropOutFlag=GAME_TIMEDOUT;
			}
		}

		else
#endif
		if (gameInfo.keyRecordFlag==PLAYBACK)
		{
			if(keyRecordCount > gameInfo.keyTime)
			{
				gameCtrl.dropOutFlag=GAME_TIMEDOUT;
				SHOCK_STOP(0);
				SHOCK_NOBUZZ(0);
			}
			if(gameInfo.timePadLastHit!=padGetWhenLastUsed())
			{
				gameCtrl.dropOutFlag=GAME_TIMEDOUT;
				SHOCK_STOP(0);
				SHOCK_NOBUZZ(0);
			}
		}

		if(pad[1]&PAD_TRIANGLE)
			gameCtrl.dropOutFlag=GAME_TIMEDOUT;
	}

	gameInfo.levelEndTime=iframe;


	SFXStopSounds();
	gameReleaseGameStuff();
	weatherCleanUp();

//	printf(">>> Leaving gameMainGame\n");
//	memoryShow();

	if(gameCtrl.dropOutFlag==GAME_COMPLETED && level != HUB8)
	{
		HiScoreType theseScores;
		int timeTook=(gameInfo.levelEndTime-gameInfo.levelStartTime)/30;

		theseScores.betterTime=FALSE;

		if(timeTook<hiScores[gameInfo.level].timeTook)
		{
			theseScores.betterTime=TRUE;
			hiScores[gameInfo.level].timeTook=timeTook;
		}

		theseScores.betterGaribs=FALSE;

		if(garibscollected>hiScores[gameInfo.level].nGaribs)
		{
			theseScores.betterGaribs=TRUE;
			hiScores[gameInfo.level].nGaribs=garibscollected;
		}


		hiScores[gameInfo.level].nTotalGaribs=numGaribs; // store it here for convenience

		if(gameScore>hiScores[gameInfo.level].score)
			hiScores[gameInfo.level].score=gameScore;

		theseScores.timeTook=timeTook;
		theseScores.nGaribs=garibscollected;
		theseScores.nTotalGaribs=numGaribs;
		theseScores.score=gameScore;

		menuShowStats(&gameInfo, hiScores, &theseScores);
	}

#if RECORDKEYS == YES
	if (gameInfo.keyRecordFlag==RECORD)
	{
		if((file=PCcreat("record.dem",1)) == -1)
		{
			printf ("Error creating file record.dem\n");
			return;
		}
		else
		{
			PCwrite(file,(UBYTE*)keyRecord,32768);// 64k for main ptr array
			PCclose(file);
		}
	}
#endif
}

/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
//int	pauseFlag=FALSE;
//int	initcard=FALSE;

VECTOR soundPos;

void renderWorld(void)
{
	weatherDo();

	ballRender();
	handRender();


	TIMER_STOP(TIMER_BALLGLOVE);
	TIMER_START(TIMER_LSCAPE);
	lscapeDrawAll(pWld);
	TIMER_STOP(TIMER_LSCAPE);

	if(pSky)
	{
		ZEROVECTOR(&pSky->position);
		lscapeDraw(pSky,0);
	}

	Draw_All_Effects();

	TIMER_START(TIMER_LSCAPE);
	platformDrawDynamicBoxes();
	waterDraw();
	TIMER_STOP(TIMER_LSCAPE);

	TIMER_START(TIMER_BALLGLOVE);

}

void Control_Ball_And_Glove(void)
{
	int	loop;
//	VECTOR	tempVect; //,tempVect1;
	IQUATERNION	tempQ;
	//	,mapx,mapy,mapz;
	NEWMODEL	*swap;
	
	textSetPos(32,8);
	SETRGBC(sprctrl.r,0,128,0,0);

	sprctrl.scalex=4096;
	sprctrl.scaley=4096;
	sprctrl.stretch=0;

	if( (debounce[1]&PAD_SQUARE) )
	{
		if(SubDivCtrl.distance==SUBDIVISIONDEPTH)
		{
			DB("Subdiv off\n");
			SubDivCtrl.distance=-16000;	// disable subdiv, in effect
		}
		else
		{
			DB("Subdiv on\n");
			SubDivCtrl.distance=SUBDIVISIONDEPTH;
		}

	}

/*
	if ( (GloveCtrl.active==FALSE) && (GloveCtrl.action!=HAND_SKIDDING) )
	{
		if( (debounce[1]&PAD_CIRCLE) ) 
		{
			BallCtrl.type++;
			if (BallCtrl.type==NUM_BALL_MODES) BallCtrl.type=BALL_MODE_NORMAL;
			ballRadius=BallBehaviour[BallCtrl.type].radius;
			//ballGravity=BallBehaviour[BallCtrl.type].gravity;
			ballColl.physicsModel=BallCtrl.type;
			ChangeBall(&pBallPSA->world,ballTex[BallCtrl.type]);
			if (BallCtrl.type==BALL_MODE_CRYSTAL)
			{
				swap=pBallPSA;
				pBallPSA=pCballPSA;
				pCballPSA=swap;
			}
		}
		if( (debounce[1]&PAD_SQUARE) )
		{
			BallCtrl.type--;
			if (BallCtrl.type<BALL_MODE_NORMAL) BallCtrl.type=BALL_MODE_CRYSTAL;
			ballRadius=BallBehaviour[BallCtrl.type].radius;
			//ballGravity=BallBehaviour[BallCtrl.type].gravity;
			ballColl.physicsModel=BallCtrl.type;
			ChangeBall(&pBallPSA->world,ballTex[BallCtrl.type]);
			if (BallCtrl.type==BALL_MODE_CRYSTAL)
			{
				swap=pBallPSA;
				pBallPSA=pCballPSA;
				pCballPSA=swap;
			}
		}
	}
	if (PRINTMESS) textPrintf("Ball Type= %s\n",ballNames[BallCtrl.type] );
*/

	if (GloveCtrl.action==HAND_CASTSPELL)
	{
		pBallPSA->globalscale.vx=ballRadius/152;
		pBallPSA->globalscale.vy=ballRadius/152;
		pBallPSA->globalscale.vz=ballRadius/152;
	}
	ballColl.radius=ballRadius;

	GetQuaternionFromRotation(&tempQ,&pBallPSA->world.qRotVel);
	QuaternionMultiply(&pBallPSA->world.qRot,&pBallPSA->world.qRot,&tempQ);


	GetQuaternionFromRotation(&tempQ,&pBallPSA->world.qRotLightVel);
	QuaternionMultiply(&pBallPSA->world.qRotLight,&pBallPSA->world.qRotLight,&tempQ);
	//QuaternionMultiply(&pBallPSA->world.qRotLight,&tempQ,&pBallPSA->world.qRotLight);

	// Fix quat problem
	if (!(frame%100))
	{
		UnifyQuat(&pBallPSA->world.qRot);
		UnifyQuat(&pBallPSA->world.qRotLight);
		//printf ("fixing quats\n");
	}

	pBallPSA->world.rotatekeys->vect.x=pBallPSA->world.qRot.x;
	pBallPSA->world.rotatekeys->vect.y=pBallPSA->world.qRot.y;
	pBallPSA->world.rotatekeys->vect.z=pBallPSA->world.qRot.z;
	pBallPSA->world.rotatekeys->vect.w=pBallPSA->world.qRot.w;
	

	if (PRINTMESS) textPrintf("BallPos=%d,%d,%d\n", ballPos.vx, ballPos.vy, ballPos.vz);
	//textPrintf("BallVel=%d,%d,%d\n", ballVel.vx, ballVel.vy, ballVel.vz);

	if (PRINTMESS) textPrintf("Ball  Height= %d\n",getHeightAt(ballPos.vx, ballPos.vy, ballPos.vz) );
	if (PRINTMESS) textPrintf("Glove Height= %d\n",getHeightAt(glovePos.vx, glovePos.vy, glovePos.vz) );
	if (PRINTMESS) textPrintf("Camera angle= %d\n",CamVars.angle);
	if (PRINTMESS) textPrintf("Glove angle = %d\n",GloveCtrl.direction);


	if (debounce[0]&PAD_START && gameCtrl.state!=FALSE)
	{
		pauseBegin();
	}

	if (gameCtrl.MrTipActive && gameCtrl.gameActive!=FALSE)
	{
		tipDisplay();
		renderWorld();
	}
	else if (gameCtrl.gameActive==FALSE)
	{
		pauseDisplay();
		renderWorld();	// having this inside the pausedisplay caused stack shortage
	}
	else if (gameCtrl.gameActive==TRUE && gameCtrl.MrTipActive==FALSE)
	{
		//UpdateCamera(TRUE);
		//UpdateCamera(FALSE);

		TIMER_STOP(TIMER_BALLGLOVE);
		TIMER_START(TIMER_CAMERA);

		Control_Glove();
		UpdateOverlays();
		
		if(lightningIsModelInRange(&ballPos, BallBehaviour[BallCtrl.type].radius) && !GloveCtrl.deathType)
		{
			//DB("Hurt Ball!\n");
			GloveCtrl.hurtFlagBall=TRUE;
			GloveCtrl.deathTypeBall=DEADFROMBALLBURST;
		}

		if(lightningIsModelInRange(&glovePos, GloveBehaviour.radius) && !GloveCtrl.deathType)
		{
			//DB("Hurt Glove!\n");
			GloveCtrl.hurtFlag=TRUE;
			GloveCtrl.deathType=HURTFALL;
		}

		UpdateBallAndGlove();
		//UpdateBallAndGlove();
		TIMER_STOP(TIMER_CAMERA);
		TIMER_START(TIMER_BALLGLOVE);

		UpdateCamera(TRUE);
		UpdateCamera(FALSE);

		if(BallCtrl.hurt)
			doBallHurt();
		renderWorld();
	}
}
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
ULONG	numTips;
ULONG	*tipRecStart;
UBYTE	*tipDataStart;

void	Load_And_Init_Tips(void)
{
ULONG	*filePtrsStart;
UBYTE	*fileDataStart;	
UBYTE	*file;
ULONG	*offset;
ULONG	headerSize;
ULONG	numTips,loop,loop1;

	file=fileLoad("TEST\\TIPTEXT.DAT",0);	// read tip file
	numTips=(ULONG)file[0];
	headerSize=(ULONG)file[4];

	printf ("num tips=%d\n",(int)numTips);

	tipDataStart=&file[headerSize];
	tipRecStart=(ULONG*)&file[8];

	offset=(ULONG*)&file[8];
	filePtrsStart=(ULONG*)&file[8];		// get 1st prt addr

	for (loop1=0;loop1<numTips;loop1++)
	{
		*(filePtrsStart) +=(ULONG)offset;
		filePtrsStart++;
	}
	for (loop1=0;loop1<=numTips;loop1++)
	{
		numTips=(ULONG)filePtrsStart[0];
		filePtrsStart++;
		for (loop=0;loop<numTips;loop++)
		{
			*(filePtrsStart) +=(ULONG)tipDataStart;
			filePtrsStart++;
		}
	}
}

void Free_Tips()
{
	FREE(ADD2POINTER(tipRecStart,-8));
}

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

	ULONG	*recordPtr;
	UBYTE	*textPtr;
	ULONG	textLines,loop;
// put back leter here for debug only
void	tipDisplay(void)
{

	POLY_G4 *si = (POLY_G4 *) GsOUT_PACKET_P; 
	register	GsOTA 	*ot = (GsOTA*)(PolyList->org+1);
	int		x,y,i;
	int		displayFlag=FALSE;



	recordPtr=(void *)tipRecStart[GloveCtrl.tipNumber-1];
	recordPtr--;
	textLines=(ULONG)recordPtr[0];
	recordPtr++;

	if(gameCtrl.state==FALSE)// pause on
	{
		if (gameCtrl.fadeIn==0) tipBegin();

		if (gameCtrl.fadeIn<60) gameCtrl.fadeIn+=4;
		else displayFlag=TRUE;
		gameCtrl.fadeOut=gameCtrl.fadeIn;
		i=gameCtrl.fadeIn;
		x=(64-i)*2;

		SETRGBC(si->r0, x, x, x, GPU_COM_G4);
		SETRGBC(si->r1, x, x, x, GPU_COM_G4);
		SETRGBC(si->r2, x, x, x, GPU_COM_G4);
		SETRGBC(si->r3, x, x, x, GPU_COM_G4);


		x = (gameCtrl.fadeIn*160)/60;
		y = (gameCtrl.fadeIn*60)/60;

		si->x0=si->x2=-x;//0-320;
		si->x1=si->x3=x;//640-320;
		si->y0=si->y1=-y;//0-120-PALMODE*8;
		si->y2=si->y3=y;//240+(PALMODE*8)-120;

		si->code = si->code | 2;

 		PUTPACKETINTABLE(si,ot,POLYG4_LEN);
		GsOUT_PACKET_P+=sizeof(POLY_G4);
		si++;

		if(displayFlag)
		{
			if( MENUSELECT(0) )
				gameCtrl.state=TRUE;

			textReset();				// Setup font scale ect
			messctrl.font=fontList[1];
			spriteReset();
			sprctrl.stretch=1;
			sprctrl.scalex=4096;
			sprctrl.scaley=4096;
			sprctrl.r=128;
			sprctrl.g=64;
			sprctrl.b=64;
			textSetPos(100,80 );
			textPrintf( "MR TIP");
			textSetPos(100,100 );
			textPrintf( "NUMBER %d",GloveCtrl.tipNumber);
			for (loop=0;loop<textLines;loop++)
			{
				textPtr=(void *)(ULONG)recordPtr[loop];
				textSetPos(100,120+(loop*20) );
				textPrintf( textPtr );
			}
		}
	}
	else if (gameCtrl.fadeOut>0)
	{
		gameCtrl.fadeOut-=4;

		i=gameCtrl.fadeIn;
		x=(64-i)*2;

		SETRGBC(si->r0, x, x, x, GPU_COM_G4);
		SETRGBC(si->r1, x, x, x, GPU_COM_G4);
		SETRGBC(si->r2, x, x, x, GPU_COM_G4);
		SETRGBC(si->r3, x, x, x, GPU_COM_G4);

		x = (gameCtrl.fadeOut*160)/60;
		y = (gameCtrl.fadeOut*60)/60;

		si->x0=si->x2=-x;//0-320;
		si->x1=si->x3=x;//640-320;
		si->y0=si->y1=-y;//0-120-PALMODE*8;
		si->y2=si->y3=y;//240+(PALMODE*8)-120;

		si->code = si->code | 2;

 		PUTPACKETINTABLE(si,ot,POLYG4_LEN);
		GsOUT_PACKET_P+=sizeof(POLY_G4);
		si++;
	}
	else
	{
		gameCtrl.MrTipActive=FALSE;
		GloveCtrl.tipFlag=FALSE;
		//gloveCtrl.tipFlag=FALSE;
		//gloveCtrl.disableTimer=10;
		gameCtrl.fadeIn=0;
		gameCtrl.fadeOut=0;
		tipEnd();
	}
	ClearText();
}


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


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

void	tipBegin(void)
{
	gameCtrl.fadeIn=0;
	gameCtrl.handFrameRate=Glover.animInfo->speed;//animate(&Glover);
	Glover.animInfo->speed=0;
	ActorStartRoll(pBallPSA,0,0);
}

/****************************************************************************************************/
void	tipEnd(void)
{
	Glover.animInfo->speed=gameCtrl.handFrameRate;

}



/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
void	UpdateOverlays(void)
{
	ULONG	loop;
	int l;

	if (GloveCtrl.health!=3)
	{
		ovlHealth[GloveCtrl.health].texture=textureFindInAllBanks("HEALTH02");
		if (GloveCtrl.health>1)
		{
			for (loop=0;loop<GloveCtrl.health-1;loop++)
				ovlHealth[loop].texture=textureFindInAllBanks("HEALTH01");
		}
	}
	else
	{
		for (loop=0;loop<GloveCtrl.health;loop++)
			ovlHealth[loop].texture=textureFindInAllBanks("HEALTH01");
	}

	l=sprintf(lifePtr->message, "%d", GloveCtrl.lives);
	lifePtr->x = 420 - l * 16;

	//lifePtr->message[0]=48+GloveCtrl.lives;

	
//void overlaySetupAndAdd(OVERLAY *overlay, SPRITEX *texture, int xPos, int yPos, int zPos, int attrib)
//{
//	overlaySetup(overlay,texture,xPos,yPos,zPos,attrib);
//	overlayAdd(overlay);
//}



}

/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
//long	tiptoe=4096/7;
//long	walk=4048/(RUNSPEED);
//long	run=4048/(RUNSPEED);

int		offsetangle=1536;


void	UpdateBallAndGlove()
{

	VECTOR	tempVect,tempVectS;//,tempVect1;
//	USHORT	temp;
	SHORT	leftRight,upDown;
   //	ULONG	flag=FALSE;
	LONG	targetAngle,temp;
	VECTOR	tempV;
	USHORT	padIn;
	//MATRIX	mat;
	IQUATERNION	quat;




	if(!GloveCtrl.enabled)
		return;

	//TIMER_START(TIMER_LSCAPE);
	//lscapeDrawAll(pWld);
	//TIMER_STOP(TIMER_LSCAPE);

	if (GloveCtrl.active && GloveCtrl.disableTimer==0 && CamVars.mode!=ZOOM)
	{
		leftRight=(nleftx[0]);
		upDown=-(nlefty[0]);
		padIn=pad[0];
		// need to mask off camera buttons
		padIn=padIn&(~PAD_L1);
		padIn=padIn&(~PAD_R1);

		if (gameInfo.keyRecordFlag==RECORD)
		{
			padIn=keyRecord[keyRecordCount];
			padIn=padIn&(~PAD_L1);
			padIn=padIn&(~PAD_R1);

			if (padIn&PAD_LEFT) leftRight=-4096;
			if (padIn&PAD_RIGHT) leftRight=4096;
			if (padIn&PAD_UP) upDown=4096;
			if (padIn&PAD_DOWN) upDown=-4096;
		}

		if (gameInfo.keyRecordFlag==PLAYBACK)
		{
			if (gameInfo.keyRecordFlag==PLAYBACK)
			{
				padIn=keyRecord[keyRecordCount];
				padIn=padIn&(~PAD_L1);
				padIn=padIn&(~PAD_R1);
				leftRight=0;
				upDown=0;
				if (padIn&PAD_LEFT) leftRight=-4096;
				if (padIn&PAD_RIGHT) leftRight=4096;
				if (padIn&PAD_UP) upDown=4096;
				if (padIn&PAD_DOWN) upDown=-4096;
			}
			//keyRecordCount++;
		}
	}
	else
	{	
		GloveCtrl.idleTimer=0;
		leftRight=0;
		upDown=0;
		padIn=0;
	}

	if (gameInfo.keyRecordFlag==PLAYBACK || gameInfo.keyRecordFlag==RECORD) keyRecordCount++;

	if (GloveCtrl.preDelay)
	{
		GloveCtrl.preDelay--;
		pGlovePSA->world.rotate.vy=GloveCtrl.direction;

		//ballVel.vy-=BallBehaviour[BallCtrl.type].gravity;
		//ADDVECTOR(&ballPos, &ballPos, &ballVel);
		//ballPos.vy-=(ballVel.vy*2);

		UpdateBallPos();
		TIMER_STOP(TIMER_COLLISION);


		UpdateGlovePos();
		pBallPSA->position.vx=ballPos.vx/4096;
		pBallPSA->position.vy=ballPos.vy/4096;
		pBallPSA->position.vz=ballPos.vz/4096;

		HandCollision();

		pGlovePSA->position.vx=glovePos.vx/4096;
		pGlovePSA->position.vy=glovePos.vy/4096;
		pGlovePSA->position.vz=glovePos.vz/4096;


		// need to add probe checks

		//TIMER_START(TIMER_BALLGLOVE);
		//objectSetAnimation(pBallPSA, 0);
		//objectDrawWithShadow(pBallPSA,ballColl.radius >> 12,ballColl.radius >> 12,0);

		//TIMER_STOP(TIMER_BALLGLOVE);
	
/*		objectSetAnimation(pGlovePSA, animate(&Glover));	

		if (CamVars.mode==ZOOM) modelctrl.semitrans=2;
		objectSegmentSort(pGlovePSA);
		if(GloveCtrl.ballWithHand)
			objectDraw(pGlovePSA);
		else
			objectDrawWithShadow(pGlovePSA,8,6,0);
		if (CamVars.mode==ZOOM) modelctrl.semitrans=0;
*/
		//HandCollision();

		return;
	}

	switch (GloveCtrl.action)
	{
		case HAND_HURT:
			moveBall(0,0);

			//gloveVel.vy-=GRAVITY;
			//ADDVECTOR(&glovePos, &glovePos, &gloveVel);
			//glovePos.vy-=(gloveVel.vy*2);
			UpdateGlovePos();
			HandCollision();

			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;
			break;

		case HAND_SLAM:
			moveBall(0,0);
			//printf ("hand slam \n");
			if (GloveCtrl.actionTime==0) gloveVel.vy=SLAMSPEED/10;

			if (GloveCtrl.actionTime>=5 && GloveCtrl.actionTime<=15) gloveVel.vy-=SLAMSPEED/5;
			//gloveVel.vy-=GRAVITY;
			ADDVECTOR(&glovePos, &glovePos, &gloveVel);
			glovePos.vy-=(gloveVel.vy*2);

			HandCollision();
			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;


			break;


		case HAND_SWISH:
			moveBall(0,0);
			
			tempV.vx=abs(leftRight);
			tempV.vy=abs(upDown);
			tempV.vz=0;

			temp=Magnitude(&tempV);
			if (temp>4096) temp=4096;

			if (temp>4000) tempVect.vz=SWISHRUNSPEED;
			else tempVect.vz=SWISHWALKSPEED;

			if (GloveCtrl.mount->animinfo.num == NMEANIM_ACTION1) tempVect.vz=0;

			if (temp)
			{
				temp=calc_angle( leftRight,upDown );
				targetAngle=(temp+CamVars.angle)&4095;
				temp = findShortestAngle(GloveCtrl.direction,targetAngle);

				if (temp>0)
				{
					if ( temp>(ROTATESPEED/2) ) GloveCtrl.direction-=(ROTATESPEED/2);
					else GloveCtrl.direction=targetAngle;
				}
				else if (temp<0)
				{
					if ( temp<-(ROTATESPEED/2) ) GloveCtrl.direction+=(ROTATESPEED/2);
					else GloveCtrl.direction=targetAngle;
				}
				GloveCtrl.direction&=4095;

				//gloveVel.vz=-(rcos(GloveCtrl.direction)*CRAWLSPEED);
				//gloveVel.vx=-(rsin(GloveCtrl.direction)*CRAWLSPEED);
			}

			GloveCtrl.mount->psa->world.rotate.vy=GloveCtrl.direction;
			GloveCtrl.mount->ya=GloveCtrl.direction;

			SwishVel.vx-=SwishVel.vx/2;
			SwishVel.vz-=SwishVel.vz/2;

			if ( GloveCtrl.dennisJumpHit )
			{
				printf ("starting attack \n");
				AddToQueue(&GloveCtrl.mount->anim,NMEANIM_ACTION1,NO,NO,4096);
				AddToQueue(&GloveCtrl.mount->anim,NMEANIM_WALK,YES,YES,4096);
			}
			//SwishVel.vy=0;

			SwishVel.vx=0;
			SwishVel.vy=0;
			SwishVel.vz=0;

			tempVect.vy=0;
			tempVect.vx=0;
			RotateVector2D(&tempVect,&tempVect,GloveCtrl.direction );
			SwishVel.vx+=tempVect.vx;
			SwishVel.vz+=tempVect.vz;

			//GloveCtrl.mount->psa->world.rotate.vy=(GloveCtrl.mount->psa->world.rotate.vy+2048)&4095;
			GloveCtrl.mount->psa->world.rotate.vx=0;
			GloveCtrl.mount->psa->world.rotate.vy=0;			
			GloveCtrl.mount->psa->world.rotate.vz=0;

			objectSetAnimation(GloveCtrl.mount->psa, animate(&GloveCtrl.mount->anim));
			objectCalcWorldMatrix(GloveCtrl.mount->psa, &GloveCtrl.mount->psa->world);
			MatrixNormal(&GloveCtrl.mount->psa->world.child->matrix,&GloveCtrl.matrix);

			//RotMatrixY( -(GloveCtrl.direction )&4095 ,&GloveCtrl.matrix);
			TransposeMatrix(&GloveCtrl.matrix,&GloveCtrl.matrix);
			RotMatrixY( (GloveCtrl.direction )&4095 ,&GloveCtrl.matrix);

			glovePos.vx=GloveCtrl.mount->pos.vx;//+GloveCtrl.mount->psa->world.child->matrix.t[0]*409;
			glovePos.vy=GloveCtrl.mount->pos.vy;//+GloveCtrl.mount->psa->world.child->matrix.t[1]*409;
			glovePos.vz=GloveCtrl.mount->pos.vz;//+GloveCtrl.mount->psa->world.child->matrix.t[2]*409;

			SwishPos.vx+=SwishVel.vx;
			SwishPos.vz+=SwishVel.vz;

			GloveCtrl.mount->pos.vx=SwishPos.vx;
			GloveCtrl.mount->pos.vy=SwishPos.vy;
			GloveCtrl.mount->pos.vz=SwishPos.vz;
			
			//pGlovePSA->world.rotate.vy=GloveCtrl.direction;
			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			break;


		case HAND_HOPPING:
			//printf ("doing dennis\n");
			moveBall(0,0);

			tempV.vx=abs(leftRight);
			tempV.vy=abs(upDown);
			tempV.vz=0;
			temp=Magnitude(&tempV);
			if (temp>4096) temp=4096;
			//GloveCtrl.targetSpeed=(TOPSPEED*temp)/4096;
			pGlovePSA->world.rotate.vz=0;

			if (GloveCtrl.onGround)
			{
				GloveCtrl.speed=FALSE;
				if (GloveCtrl.dennisJumpHit || GloveCtrl.dennisJump) // jump pressed
				{
					if (!GloveCtrl.dennisJump)
					{
						AddToQueue(&GloveCtrl.mount->anim,NMEANIM_SPECIAL1,NO,NO,2048);
						AddToQueue(&GloveCtrl.mount->anim,NMEANIM_JUMP,NO,YES,2048);
						GloveCtrl.dennisJump=TRUE;
					}
					else
					{
						temp=GloveCtrl.mount->anim.animInfo->frame;
						temp+=GloveCtrl.mount->anim.animInfo->segInfo[GloveCtrl.mount->anim.currentAnimation].segStart;
//						printf ("frame %d\n",temp);
						if (temp>=61)
						{
							if (temp)
							{
								GloveCtrl.speed=TRUE;
								tempVect.vz = -temp*DENNISMOVESPEED;
								tempVect.vy=0;
								tempVect.vx=0;
								RotateVector2D(&tempVect, &tempVect,GloveCtrl.direction );
								DennisVel.vx = tempVect.vx;
								DennisVel.vz = tempVect.vz;
							}
							else GloveCtrl.speed=FALSE;

// Fred note - dennis's yvel's +ve downwards
							DennisVel.vy = -(20*4096+(GloveCtrl.dennisBounceCount*4096*3));
							if ( GloveCtrl.dennisBounceCount<6 ) GloveCtrl.dennisBounceCount++;
							GloveCtrl.dennisJumpHit=FALSE;
							GloveCtrl.dennisJump=FALSE;
						}
					}
				}
				else
				{
					GloveCtrl.dennisBounceCount=0;
				}
				/*if (GloveCtrl.ballHit) // jump pressed
				{
					DennisVel.vy=(20*4096+(GloveCtrl.dennisBounceCount*4096*3));
					GloveCtrl.dennisBounceCount++;
					GloveCtrl.ballHit=0;
				}
				else GloveCtrl.dennisBounceCount=0;
				*/
			}
			else
			{
				if (temp)
				{
					GloveCtrl.speed=TRUE;
					tempVect.vz = -(temp*DENNISMOVESPEED)/10;
					tempVect.vy=0;
					tempVect.vx=0;
					RotateVector2D(&tempVect, &tempVect,GloveCtrl.direction );
					DennisVel.vx += tempVect.vx;
					DennisVel.vz += tempVect.vz;
				}

				tempVect.vy=DennisVel.vy;
				DennisVel.vy=0;
				if ( Magnitude(&DennisVel)>(4096*DENNISMOVESPEED) )
				{
					SCALEVECTOR( &DennisVel,(DENNISMOVESPEED) );
				}
				DennisVel.vy=tempVect.vy;
				//if (GloveCtrl.ballHit) // jump pressed
				//{
				//	DennisVel.vy=(20*4096+(GloveCtrl.dennisBounceCount*4096*3));
				//	GloveCtrl.dennisBounceCount++;
				//	GloveCtrl.ballHit=0;
				//}
				//else GloveCtrl.dennisBounceCount=0;
			}



			HandCollision();
			temp=Magnitude(&tempV);
			if (temp>4096) temp=4096;
			if (temp)
			{
				temp=calc_angle( leftRight,upDown );
				targetAngle=(temp+CamVars.angle)&4095;
				temp = findShortestAngle(GloveCtrl.direction,targetAngle);

				if (temp>0)
				{
					if ( temp>ROTATESPEED ) GloveCtrl.direction-=ROTATESPEED;
					else GloveCtrl.direction=targetAngle;
				}
				else if (temp<0)
				{
					if ( temp<-ROTATESPEED ) GloveCtrl.direction+=ROTATESPEED;
					else GloveCtrl.direction=targetAngle;
				}
				GloveCtrl.direction&=4095;
				//gloveVel.vz=-(rcos(GloveCtrl.direction)*CRAWLSPEED);
				//gloveVel.vx=-(rsin(GloveCtrl.direction)*CRAWLSPEED);
			}

			GloveCtrl.mount->psa->world.rotate.vy=GloveCtrl.direction;
			GloveCtrl.mount->ya=GloveCtrl.direction;
			
			pGlovePSA->world.rotate.vy=GloveCtrl.direction;
			pGlovePSA->world.rotate.vy=GloveCtrl.direction;
			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			break;



		case HAND_FALLING:
			moveBall(0,0);
			//gloveVel.vy-=GRAVITY;
			//ADDVECTOR(&glovePos, &glovePos, &gloveVel);
			//glovePos.vy-=(gloveVel.vy*2);
			UpdateGlovePos();
			HandCollision();

			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;
			break;

		case HAND_CLING:
			gloveVel.vx=gloveVel.vy=gloveVel.vz=0;
			if (GloveCtrl.disableTimer) break;


			break;
		case HAND_CATCH:

			tempV.vx=abs(leftRight);
			tempV.vy=abs(upDown);
			tempV.vz=0;
			temp=Magnitude(&tempV);
			if (temp>4096) temp=4096;
			GloveCtrl.targetSpeed=(TOPSPEED*temp)/4096;
			pGlovePSA->world.rotate.vz=0;

			if (temp)
			{
				temp=calc_angle( leftRight,upDown );
				targetAngle=(temp+CamVars.angle)&4095;
				temp = findShortestAngle(GloveCtrl.direction,targetAngle);

				if (temp>0)
				{
					if ( temp>ROTATESPEED )
					{
						GloveCtrl.direction-=ROTATESPEED;
						if (GloveCtrl.action==HAND_WALK) pGlovePSA->world.rotate.vz = (LEANANGLE*GloveCtrl.speed)/TOPSPEED;
					}
					else 
					{
						GloveCtrl.direction=targetAngle;
						if (GloveCtrl.action==HAND_WALK) pGlovePSA->world.rotate.vz =  (((temp*LEANANGLE)/ROTATESPEED)*GloveCtrl.speed)/TOPSPEED;
						//(( (temp*4096)/ROTATESPEED )*LEANANGLE)/4096;
					}
				}
				else if (temp<0)
				{
					if ( temp<-ROTATESPEED )
					{
						GloveCtrl.direction+=ROTATESPEED;
						if (GloveCtrl.action==HAND_WALK) pGlovePSA->world.rotate.vz = -(LEANANGLE*GloveCtrl.speed)/TOPSPEED;
					}
					else 
					{
						GloveCtrl.direction=targetAngle;
						if (GloveCtrl.action==HAND_WALK) pGlovePSA->world.rotate.vz = - (((temp*LEANANGLE)/ROTATESPEED)*GloveCtrl.speed)/TOPSPEED;
					}
				}
			
			}
//			else
//			{
//				temp=0;
//			}


			GloveCtrl.oldSpeed=GloveCtrl.speed;
			if (GloveCtrl.speed<GloveCtrl.targetSpeed)
			{
				if ( GloveCtrl.speed<(GloveCtrl.targetSpeed+(GloveBehaviour.accel/4096)) ) 
					GloveCtrl.speed+=GloveBehaviour.accel/4096;
				else 
					GloveCtrl.speed=GloveCtrl.targetSpeed;
			}
			else if (GloveCtrl.speed>GloveCtrl.targetSpeed)
			{
				if ( GloveCtrl.speed>(GloveCtrl.targetSpeed+(GloveBehaviour.accel/4096)) )
					GloveCtrl.speed-=GloveBehaviour.accel/4096;
				else 
					GloveCtrl.speed=GloveCtrl.targetSpeed;
			}
			GloveCtrl.direction&=4095;
			pGlovePSA->world.rotate.vy=GloveCtrl.direction;

			gloveVel.vz=-(rcos(GloveCtrl.direction)*GloveCtrl.speed)/16;
			gloveVel.vx=-(rsin(GloveCtrl.direction)*GloveCtrl.speed)/16;
			// now need to set anim speed
			if (GloveCtrl.flags&GLOVEMOVE)
			{
				gloveVel.vy-=gravity;
				ADDVECTOR(&glovePos, &glovePos, &gloveVel);
				glovePos.vy-=(gloveVel.vy*2);
			}
			moveBall(0,0);

			HandCollision();

			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			break;

		case HAND_BALLWALK:
//			moveBall(upDown,leftRight);

			gloveVel.vx=ballVel.vx;
			gloveVel.vz=ballVel.vz;

			glovePos.vx=ballPos.vx;
			glovePos.vz=ballPos.vz;			

			gloveVel.vy-=GloveBehaviour.gravity;
			ADDVECTOR(&glovePos, &glovePos, &gloveVel);
			glovePos.vy-=(gloveVel.vy*2);

			//glovePos.vy=ballPos.vy-(GloveBehaviour.radius+BallBehaviour[BallCtrl.type].radius);
			glovePos.vy=ballPos.vy-(( (GloveBehaviour.radius+BallBehaviour[BallCtrl.type].radius)*4000)/4296);
			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			HandCollision();

			//pGlovePSA->position.vx=glovePos.vx/4096;
			//pGlovePSA->position.vy=glovePos.vy/4096;
			//pGlovePSA->position.vz=glovePos.vz/4096;

			moveBall(upDown,leftRight);

			tempV.vx=ballVel.vx;
			tempV.vy=0;
			tempV.vz=ballVel.vz;
			temp=Magnitude(&tempV);
			if (temp<512) temp=0;
			if (temp==0 && GloveCtrl.currentAnim!=HANDANIM_IDLE)
			{
				AddToQueue(&Glover,HANDANIM_BALLWALK2IDLE,NO,NO,2048);
				AddToQueue(&Glover,HANDANIM_IDLE,YES,YES,2048);
				GloveCtrl.currentAnim=HANDANIM_IDLE;
			}
			else if ( temp<(42959/2) && temp!=0 ) // ball physics need looking at
			{
				if (GloveCtrl.currentAnim!=HANDANIM_BALLWALK)
					AddToQueue(&Glover,HANDANIM_BALLWALK,YES,NO,2048);
				GloveCtrl.currentAnim=HANDANIM_BALLWALK;

			}
			else if ( temp>=(42959/2) )
			{
				if (GloveCtrl.currentAnim!=HANDANIM_BALLWALK2)
					AddToQueue(&Glover,HANDANIM_BALLWALK2,YES,NO,2048);
				GloveCtrl.currentAnim=HANDANIM_BALLWALK2;
			}
			break;


		case HAND_CLIMBDOWN:
			
			moveBall(0,0);
			//ballVel.vy-=BallBehaviour[BallCtrl.type].gravity;
			//ADDVECTOR(&ballPos, &ballPos, &ballVel);
			//ballPos.vy-=(ballVel.vy*2);

			//pBallPSA->position.vx=ballPos.vx/4096;
			//pBallPSA->position.vy=ballPos.vy/4096;
			//pBallPSA->position.vz=ballPos.vz/4096;

			gloveVel.vx=0;
			gloveVel.vy=0;
			gloveVel.vz=0;

			if (padIn&PAD_L2) 
			{	// Make hand move forewards
				AddToQueue(&Glover,HANDANIM_SITUP,NO,NO,4096);
				AddToQueue(&Glover,HANDANIM_IDLE,YES,YES,2048);
				GloveCtrl.action=HAND_CLIMBUP;
				GloveCtrl.disableTimer=22;
				GloveCtrl.speed=16;

			}

			//if ( collboxCheckSphere(&ballColl) )
			//{
			//	BallCtrl.ballOnGround=TRUE;
			//	ActorStartRoll(pBallPSA,ballVel.vx,ballVel.vz);
			//}
			//else BallCtrl.ballOnGround=FALSE;

			if (leftRight || upDown || padIn)
			{
				AddToQueue(&Glover,HANDANIM_SITUP,NO,NO,4096);
				AddToQueue(&Glover,HANDANIM_IDLE,YES,YES,2048);
				GloveCtrl.action=HAND_CLIMBUP;
				GloveCtrl.disableTimer=22;
			}
			break;

		case HAND_CLIMBUP:
			// make glove turn
			if (GloveCtrl.disableTimer<10 && GloveCtrl.speed==0)
			{
				GloveCtrl.direction+=204;
				pGlovePSA->world.rotate.vy=GloveCtrl.direction;
				HandCollision();
				GloveCtrl.speed=0;
			}
			else
			{
				gloveVel.vz=-(rcos(GloveCtrl.direction)*GloveCtrl.speed)/16;
				gloveVel.vx=-(rsin(GloveCtrl.direction)*GloveCtrl.speed)/16;
				pGlovePSA->world.rotate.vy=GloveCtrl.direction;

				gloveVel.vy-=gravity;
				ADDVECTOR(&glovePos, &glovePos, &gloveVel);
				glovePos.vy-=(gloveVel.vy*2);

				pGlovePSA->position.vx=glovePos.vx/4096;
				pGlovePSA->position.vy=glovePos.vy/4096;
				pGlovePSA->position.vz=glovePos.vz/4096;

				HandCollision();
			}
			moveBall(0,0);
			//ballVel.vy-=BallBehaviour[BallCtrl.type].gravity;
			//ADDVECTOR(&ballPos, &ballPos, &ballVel);
			//ballPos.vy-=(ballVel.vy*2);

			//TIMER_START(TIMER_COLLISION);

			//if ( collboxCheckSphere(&ballColl) ) 
			//{
			//	BallCtrl.ballOnGround=TRUE;
			//	ActorStartRoll(pBallPSA,ballVel.vx,ballVel.vz);
			//}
			//else BallCtrl.ballOnGround=FALSE;
			//TIMER_STOP(TIMER_COLLISION);

			//pBallPSA->position.vx=ballPos.vx/4096;
			//pBallPSA->position.vy=ballPos.vy/4096;
			//pBallPSA->position.vz=ballPos.vz/4096;

			
			if (!GloveCtrl.disableTimer) GloveCtrl.action=HAND_IDLE;
			break;

		case HAND_CASTSPELL:
			pGlovePSA->world.rotate.vy=GloveCtrl.direction;
			if (GloveCtrl.lastAction!=HAND_JOINED)
				moveBall(0,0);

			//COPYVECTOR(&GloveCtrl.move,&glovePos);
			HandCollision();
			//ballVel.vy-=BallBehaviour[BallCtrl.type].gravity;
			//ADDVECTOR(&ballPos, &ballPos, &ballVel);
			//ballPos.vy-=(ballVel.vy*2);

			//pBallPSA->position.vx=ballPos.vx/4096;
			//pBallPSA->position.vy=ballPos.vy/4096;
			//pBallPSA->position.vz=ballPos.vz/4096;

			//if ( collboxCheckSphere(&ballColl) )
			//{
			//	BallCtrl.ballOnGround=TRUE;
			//	ActorStartRoll(pBallPSA,ballVel.vx,ballVel.vz);
			//}
			//else BallCtrl.ballOnGround=FALSE;
			break;

		case HAND_DUCK:

			gloveVel.vx=0;
			gloveVel.vz=0;

			//gloveVel.vy-=GRAVITY;
			//ADDVECTOR(&glovePos, &glovePos, &gloveVel);
			//glovePos.vy-=(gloveVel.vy*2);
			UpdateGlovePos();
			//pGlovePSA->position.vx=glovePos.vx/4096;
			//pGlovePSA->position.vy=glovePos.vy/4096;
			//pGlovePSA->position.vz=glovePos.vz/4096;

			moveBall(0,0);

			HandCollision();
			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			break;

		case HAND_CRAWL:
			moveBall(0,0);
			gloveVel.vx=0;
			gloveVel.vz=0;

			if (GloveCtrl.onConveyer==XPOS) glovePos.vx+=(GloveCtrl.conveyerTimer*4096);
			if (GloveCtrl.onConveyer==XNEG) glovePos.vx-=(GloveCtrl.conveyerTimer*4096);
			if (GloveCtrl.onConveyer==ZPOS) glovePos.vz+=(GloveCtrl.conveyerTimer*4096);
			if (GloveCtrl.onConveyer==ZNEG) glovePos.vz-=(GloveCtrl.conveyerTimer*4096);

			if (leftRight || upDown)
			{
				ANIM_SPEED( Glover,2048 );
				if (Glover.animInfo->frame>=7) 
				{
					gloveVel.vy-=gravity;
					ADDVECTOR(&glovePos, &glovePos, &gloveVel);
					glovePos.vy-=(gloveVel.vy*2);

					HandCollision();
					pGlovePSA->position.vx=glovePos.vx/4096;
					pGlovePSA->position.vy=glovePos.vy/4096;
					pGlovePSA->position.vz=glovePos.vz/4096;
					break;
				}
				
				tempV.vx=abs(leftRight);
				tempV.vy=abs(upDown);
				tempV.vz=0;
				temp=Magnitude(&tempV);
				if (temp>4096) temp=4096;
				GloveCtrl.targetSpeed=(TOPSPEED*temp)/4096;
				pGlovePSA->world.rotate.vz=0;

				temp=calc_angle( leftRight,upDown );
				targetAngle=(temp+CamVars.angle)&4095;
				temp = findShortestAngle(GloveCtrl.direction,targetAngle);

				if (temp>0)
				{
					if ( temp>ROTATESPEED ) GloveCtrl.direction-=ROTATESPEED;
					else GloveCtrl.direction=targetAngle;
				}
				else if (temp<0)
				{
					if ( temp<-ROTATESPEED ) GloveCtrl.direction+=ROTATESPEED;
					else GloveCtrl.direction=targetAngle;
				}

				GloveCtrl.direction&=4095;
				gloveVel.vz=-(rcos(GloveCtrl.direction)*CRAWLSPEED);
				gloveVel.vx=-(rsin(GloveCtrl.direction)*CRAWLSPEED);

				pGlovePSA->world.rotate.vy=GloveCtrl.direction;

				//ballVel.vy-=BallBehaviour[BallCtrl.type].gravity;
				//ADDVECTOR(&ballPos, &ballPos, &ballVel);
				//ballPos.vy-=(ballVel.vy*2);

				//gloveVel.vy-=GRAVITY;
				//ADDVECTOR(&glovePos, &glovePos, &gloveVel);
				//glovePos.vy-=(gloveVel.vy*2);

				//pGlovePSA->position.vx=glovePos.vx/4096;
				//pGlovePSA->position.vy=glovePos.vy/4096;
				//pGlovePSA->position.vz=glovePos.vz/4096;

				//if ( collboxCheckSphere(&ballColl) )
				//{
				//	BallCtrl.ballOnGround=TRUE;
				//	ActorStartRoll(pBallPSA,ballVel.vx,ballVel.vz);
				//}
				//else BallCtrl.ballOnGround=FALSE;

				//TIMER_START(TIMER_COLLISION);
				//collboxCheckSphere(&gloveColl);
				//collboxCheckSphere(&gloveColl);
				//TIMER_STOP(TIMER_COLLISION);
				//HandCollision();
			}
			else if (Glover.animInfo->frame>=11) AddToQueue(&Glover,HANDANIM_CRAWL,YES,NO,0);



			gloveVel.vy-=gravity;
			ADDVECTOR(&glovePos, &glovePos, &gloveVel);
			glovePos.vy-=(gloveVel.vy*2);

			//pGlovePSA->position.vx=glovePos.vx/4096;
			//pGlovePSA->position.vy=glovePos.vy/4096;
			//pGlovePSA->position.vz=glovePos.vz/4096;
			HandCollision();
			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			break;

		case HAND_CARTWHEEL:
			moveBall(0,0);
			if (GloveCtrl.actionTime>=5 && GloveCtrl.actionTime<=20) // move glove
			{
				//moveBall(0,0);
				tempVect.vz = -CARTWHEELSPEED*4096;
				tempVect.vy = 0;
				tempVect.vx = 0;
				RotateVector2D(&tempVect, &tempVect, GloveCtrl.direction );
				gloveVel.vx = tempVect.vx;
				gloveVel.vz = tempVect.vz;

				gloveVel.vy-=gravity;
				ADDVECTOR(&glovePos, &glovePos, &gloveVel);
				glovePos.vy-=(gloveVel.vy*2);

				//ballVel.vy-=BallBehaviour[BallCtrl.type].gravity;
				//ADDVECTOR(&ballPos, &ballPos, &ballVel);
				//ballPos.vy-=(ballVel.vy*2);

				//TIMER_START(TIMER_COLLISION);
				//if ( collboxCheckSphere(&ballColl) ) 
				//{
				//	BallCtrl.ballOnGround=TRUE;
				//	ActorStartRoll(pBallPSA,ballVel.vx,ballVel.vz);
				//}
				//else BallCtrl.ballOnGround=FALSE;
				//TIMER_STOP(TIMER_COLLISION);

				//pBallPSA->position.vx=ballPos.vx/4096;
				//pBallPSA->position.vy=ballPos.vy/4096;
				//pBallPSA->position.vz=ballPos.vz/4096;

				GloveCtrl.iceData.vx=gloveVel.vx;
				GloveCtrl.iceData.vz=gloveVel.vz;

				HandCollision();
				pGlovePSA->position.vx=glovePos.vx/4096;
				pGlovePSA->position.vy=glovePos.vy/4096;
				pGlovePSA->position.vz=glovePos.vz/4096;

			}
			break;

		case HAND_WHACK:
			if (GloveCtrl.actionTime==0)
			{
				tempVect.vz = -BALLTHROWSPEED*2;
				tempVect.vx = 0;
				RotateVector2D(&tempVect, &tempVect,GloveCtrl.direction );	
				ballVel.vx = tempVect.vx;
				ballVel.vy = 9*4096;
				ballVel.vz = tempVect.vz;
				BallCtrl.anywhack = 2;
				if(BallCtrl.type == BALL_MODE_BOWLING || cheat_any_ball_powerwhacks)
					BallCtrl.powerwhack = 2;
			}

			moveBall(0,0);

			if (GloveCtrl.flags&GLOVEMOVE)
			{
				gloveVel.vy-=gravity;
				ADDVECTOR(&glovePos, &glovePos, &gloveVel);
				glovePos.vy-=(gloveVel.vy*2);
			}

			//ballVel.vy-=BallBehaviour[BallCtrl.type].gravity;
			//ADDVECTOR(&ballPos, &ballPos, &ballVel);
			//ballPos.vy-=(ballVel.vy*2);
/*
			TIMER_START(TIMER_COLLISION);

			if ( collboxCheckSphere(&ballColl) ) 
			{
				BallCtrl.ballOnGround=TRUE;
				ActorStartRoll(pBallPSA,ballVel.vx,ballVel.vz);
				BallApplySquash();
			}
			else BallCtrl.ballOnGround=FALSE;
			TIMER_STOP(TIMER_COLLISION);
			BallUpdateSquash();
*/
//			UpdateBallPos();
			//pBallPSA->position.vx=ballPos.vx/4096;
			//pBallPSA->position.vy=ballPos.vy/4096;
			//pBallPSA->position.vz=ballPos.vz/4096;

			//TIMER_START(TIMER_COLLISION);
			//collboxCheckSphere(&gloveColl);
			//collboxCheckSphere(&gloveColl);
			//TIMER_STOP(TIMER_COLLISION);
			HandCollision();
			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			break;

		case HAND_PREWHACK:

			//if (BallCtrl.ballStopMove!=TRUE) moveBall(0,0);
			moveBall(0,0);

			tempV.vx=abs(leftRight);
			tempV.vy=abs(upDown);
			tempV.vz=0;
			temp=Magnitude(&tempV);
			if (temp)
			{
				temp=calc_angle( leftRight,upDown );
				targetAngle=(temp+CamVars.angle)&4095;
				temp = findShortestAngle(GloveCtrl.direction,targetAngle);
				if (temp>0)
				{
					if ( temp>ROTATESPEED ) GloveCtrl.direction-=ROTATESPEED;
					else GloveCtrl.direction=targetAngle;
				}
				else if (temp<0)
				{
					if ( temp<-ROTATESPEED ) GloveCtrl.direction+=ROTATESPEED;
					else GloveCtrl.direction=targetAngle;
				}
			}
//			else
//			{
//				temp=0;
//			}


			GloveCtrl.direction=GloveCtrl.direction&4095;
			pGlovePSA->world.rotate.vy=GloveCtrl.direction;

			tempVect.vz = BallBehaviour[BallCtrl.type].radius/2;
			tempVect.vy=0;
			tempVect.vx=0;
			RotateVector2D(&tempVect, &tempVect,GloveCtrl.direction );
			//glovePos.vx += tempVect.vx;//+gloveVel.vx;
			//glovePos.vz += tempVect.vz;//+gloveVel.vz;

			glovePos.vx=ballPos.vx+tempVect.vx;
			glovePos.vz=ballPos.vz+tempVect.vz;			

			if (BallCtrl.onConveyer==XPOS) glovePos.vx+=(BallCtrl.conveyerTimer*4096);
			if (BallCtrl.onConveyer==XNEG) glovePos.vx-=(BallCtrl.conveyerTimer*4096);
			if (BallCtrl.onConveyer==ZPOS) glovePos.vz+=(BallCtrl.conveyerTimer*4096);
			if (BallCtrl.onConveyer==ZNEG) glovePos.vz-=(BallCtrl.conveyerTimer*4096);

			if (GloveCtrl.flags&GLOVEMOVE)
			{
				gloveVel.vy-=gravity;
				ADDVECTOR(&glovePos, &glovePos, &gloveVel);
				glovePos.vy-=(gloveVel.vy*2);
			}

			

			//if (BallCtrl.ballStopMove!=TRUE)
			//{
			//	ballVel.vy-=BallBehaviour[BallCtrl.type].gravity;
			//	ADDVECTOR(&ballPos, &ballPos, &ballVel);
			//	ballPos.vy-=(ballVel.vy*2);
			//}

			TIMER_START(TIMER_COLLISION);

			//if ( collboxCheckSphere(&ballColl) ) 
			//{
			//	BallCtrl.ballOnGround=TRUE;
			//	ActorStartRoll(pBallPSA,ballVel.vx,ballVel.vz);
			//}
			//else BallCtrl.ballOnGround=FALSE;
			TIMER_STOP(TIMER_COLLISION);


			//pBallPSA->position.vx=ballPos.vx/4096;
			//pBallPSA->position.vy=ballPos.vy/4096;
			//pBallPSA->position.vz=ballPos.vz/4096;


			//TIMER_START(TIMER_COLLISION);
			//collboxCheckSphere(&gloveColl);
			//collboxCheckSphere(&gloveColl);
			//TIMER_STOP(TIMER_COLLISION);
			HandCollision();
			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			break;

		case HAND_THROW:
			if (GloveCtrl.throwDelay) // first time
			{
				GloveCtrl.throwDelay=FALSE;
				tempVect.vz = -BALLTHROWSPEED;
				ballVel.vy = BallBehaviour[BallCtrl.type].gravity*14;

				//tempVect.vz=0;
				//ballVel.vy=BallBehaviour[BallCtrl.type].gravity*30;	// These two line for testting only
				tempVect.vx = 0;
				RotateVector2D(&tempVect, &tempVect,GloveCtrl.direction );
				ballVel.vx = tempVect.vx;
				ballVel.vz = tempVect.vz;
			}

			if (GloveCtrl.flags&GLOVEMOVE)
			{
				gloveVel.vy-=gravity;
				ADDVECTOR(&glovePos, &glovePos, &gloveVel);
				glovePos.vy-=(gloveVel.vy*2);
			}

			moveBall(0,0);
			//ballVel.vy-=BallBehaviour[BallCtrl.type].gravity;
			//ADDVECTOR(&ballPos, &ballPos, &ballVel);
			//ballPos.vy-=(ballVel.vy*2);

			//TIMER_START(TIMER_COLLISION);

			//if ( collboxCheckSphere(&ballColl) ) 
			//{
			//	BallCtrl.ballOnGround=TRUE;
			//	ActorStartRoll(pBallPSA,ballVel.vx,ballVel.vz);
			//}
			//else BallCtrl.ballOnGround=FALSE;
			//TIMER_STOP(TIMER_COLLISION);
			

			//pBallPSA->position.vx=ballPos.vx/4096;
			//pBallPSA->position.vy=ballPos.vy/4096;
			//pBallPSA->position.vz=ballPos.vz/4096;


			//TIMER_START(TIMER_COLLISION);
			//collboxCheckSphere(&gloveColl);
			//collboxCheckSphere(&gloveColl);
			//TIMER_STOP(TIMER_COLLISION);
			HandCollision();
			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			break;


		case HAND_LOB:
			if (GloveCtrl.throwDelay) // first time
			{
				GloveCtrl.throwDelay=FALSE;
				tempVect.vz = LOBDISTANCE;
				ballVel.vy = LOBHEIGHT;
				tempVect.vx = 0;
				RotateVector2D(&tempVect, &tempVect,(GloveCtrl.direction+2048)&4095 );
				ballVel.vx = tempVect.vx;
				ballVel.vz = tempVect.vz;
			}

			if (GloveCtrl.flags&GLOVEMOVE)
			{
				gloveVel.vy-=gravity;
				ADDVECTOR(&glovePos, &glovePos, &gloveVel);
				glovePos.vy-=(gloveVel.vy*2);
			}

			moveBall(0,0);
			HandCollision();
			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			break;

/*		case HAND_PUSH:
			tempV.vx=abs(leftRight);
			tempV.vy=abs(upDown);
			tempV.vz=0;
			temp=Magnitude(&tempV);
			if (temp>4096) temp=4096;
			GloveCtrl.targetSpeed=(TOPSPEED*temp)/4096;
			pGlovePSA->world.rotate.vz=0;

			GloveCtrl.oldSpeed=GloveCtrl.speed;

			if (GloveCtrl.speed<GloveCtrl.targetSpeed)
			{
				if ( GloveCtrl.speed<(GloveCtrl.targetSpeed+( (4096*10)/4096)) ) 
					GloveCtrl.speed+=(4096*10)/4096;
				else 
					GloveCtrl.speed=GloveCtrl.targetSpeed;
			}
			else if (GloveCtrl.speed>GloveCtrl.targetSpeed)
			{
				if ( GloveCtrl.speed>(GloveCtrl.targetSpeed+((4096*10)/4096)) )
					GloveCtrl.speed-=(4096*10)/4096;
				else 
					GloveCtrl.speed=GloveCtrl.targetSpeed;
			}

			moveBall(0,0);
			UpdateGlovePos();
			HandCollision();
			break;
*/
		case HAND_IDLE:
		case HAND_WALK:
		case HAND_SKIDDING:
		case HAND_JUMP:
		case HAND_PUSH:

			if (GloveCtrl.forceSlide )
			{
				//if (GloveCtrl.action!=HAND_SKIDDING)
				//{
					GloveCtrl.action=HAND_SKIDDING;
					GloveCtrl.direction=calc_angle( GloveCtrl.slideData.vx,GloveCtrl.slideData.vz );
					GloveCtrl.active=FALSE;
					//GloveBehaviour.accel=4096*8;
					GloveBehaviour.accel=0;
					//if (GloveCtrl.forceSlide) GloveCtrl.forceSlideDelay=1;
					//GloveCtrl.forceSlideDelay++;
					GloveCtrl.speed=72;
				//}
				if (GloveCtrl.forceSlide) GloveCtrl.forceSlideDelay=1;
			}
			if (GloveCtrl.forceSlideDelay) GloveCtrl.forceSlideDelay++;
			if (GloveCtrl.forceSlideDelay>5)
			{
				GloveCtrl.action=HAND_SKIDDING;
				GloveBehaviour.accel=4096*14;
				GloveCtrl.forceSlideDelay=0;
			}

			
			tempV.vx=abs(leftRight);
			tempV.vy=abs(upDown);
			tempV.vz=0;
			temp=Magnitude(&tempV);
			if (temp>4096) temp=4096;
			GloveCtrl.targetSpeed=(TOPSPEED*temp)/4096;
			pGlovePSA->world.rotate.vz=0;

			if (temp)
			{
				temp=calc_angle( leftRight,upDown );
				targetAngle=(temp+CamVars.angle)&4095;
				temp = findShortestAngle(GloveCtrl.direction,targetAngle);
			}
			else
			{
				temp=0;
				targetAngle = GloveCtrl.direction;
			}

			if ( (abs(temp)>1536 && abs(temp)<2560) && GloveCtrl.speed>SKIDSPEED && GloveCtrl.action==HAND_WALK)
			{
				if (ActionAllowed(GloveCtrl.action,HAND_SKIDDING))
				{
					GloveCtrl.targetSpeed=0;	// stop glove if direction reversed
					GloveCtrl.action=HAND_SKIDDING;
					GloveCtrl.active=FALSE;
					GloveBehaviour.accel=4096*8;
				}
			}
			else
			{
				if (temp>0)
				{
					if ( temp>ROTATESPEED )
					{
						GloveCtrl.direction-=ROTATESPEED;
						if (GloveCtrl.action==HAND_WALK) pGlovePSA->world.rotate.vz = (LEANANGLE*GloveCtrl.speed)/TOPSPEED;
					}
					else 
					{
						GloveCtrl.direction=targetAngle;
						if (GloveCtrl.action==HAND_WALK) pGlovePSA->world.rotate.vz =  (((temp*LEANANGLE)/ROTATESPEED)*GloveCtrl.speed)/TOPSPEED;
						//(( (temp*4096)/ROTATESPEED )*LEANANGLE)/4096;
					}
				}
				else if (temp<0)
				{
					if ( temp<-ROTATESPEED )
					{
						GloveCtrl.direction+=ROTATESPEED;
						if (GloveCtrl.action==HAND_WALK) pGlovePSA->world.rotate.vz = -(LEANANGLE*GloveCtrl.speed)/TOPSPEED;
					}
					else 
					{
						GloveCtrl.direction=targetAngle;
						if (GloveCtrl.action==HAND_WALK) pGlovePSA->world.rotate.vz = - (((temp*LEANANGLE)/ROTATESPEED)*GloveCtrl.speed)/TOPSPEED;
					}
				}
			}

			GloveCtrl.oldSpeed=GloveCtrl.speed;
			if (GloveCtrl.speed<GloveCtrl.targetSpeed)
			{
				if ( GloveCtrl.speed<(GloveCtrl.targetSpeed+(GloveBehaviour.accel/4096)) ) 
					GloveCtrl.speed+=GloveBehaviour.accel/4096;
				else 
					GloveCtrl.speed=GloveCtrl.targetSpeed;
			}
			else if (GloveCtrl.speed>GloveCtrl.targetSpeed)
			{
				if ( GloveCtrl.speed>(GloveCtrl.targetSpeed+(GloveBehaviour.accel/4096)) )
					GloveCtrl.speed-=GloveBehaviour.accel/4096;
				else 
					GloveCtrl.speed=GloveCtrl.targetSpeed;
			}
			GloveCtrl.direction&=4095;

			if (GloveCtrl.action!=HAND_PUSH) pGlovePSA->world.rotate.vy=GloveCtrl.direction;
			else pGlovePSA->world.rotate.vy=GloveCtrl.pushDirection;

			gloveVel.vz=-(rcos(GloveCtrl.direction)*GloveCtrl.speed)/16;
			gloveVel.vx=-(rsin(GloveCtrl.direction)*GloveCtrl.speed)/16;
			// now need to set anim speed
			if (GloveCtrl.speed && GloveCtrl.action!=HAND_JUMP && GloveCtrl.action!=HAND_PUSH && !GloveCtrl.stopXZ)
			{
				if ( GloveCtrl.walkType==HANDWALK_TIPTOE )
				{
					ANIM_SPEED(Glover,(GloveCtrl.speed*650) );
				}
				else if ( GloveCtrl.walkType==HANDWALK_WALK )
				{
					ANIM_SPEED(Glover,(GloveCtrl.speed*136) );
				}
				else if ( GloveCtrl.walkType==HANDWALK_RUN )
				{
					ANIM_SPEED(Glover,(GloveCtrl.speed*58) );
				}

				

				/*
				if (GloveCtrl.speed<(TOPSPEED/2))
				{
					ANIM_SPEED(Glover,(GloveCtrl.speed*4048/(TOPSPEED/2)) );
				}
				
				else 
					ANIM_SPEED(Glover,(GloveCtrl.speed*1500/(TOPSPEED/2)) );

				ANIM_SPEED(Glover,2048 );
				*/
			}
			if (GloveCtrl.stopXZ)
			{
				GloveCtrl.speed=0;
				GloveCtrl.targetSpeed=0;
			}
			if (GloveCtrl.flags&GLOVEMOVE)
			{
				//gloveVel.vy-=GRAVITY;
				//ADDVECTOR(&glovePos, &glovePos, &gloveVel);
				//glovePos.vy-=(gloveVel.vy*2);
				UpdateGlovePos();
			}
			moveBall(0,0);

			//ballVel.vy-=BallBehaviour[BallCtrl.type].gravity;
			//ADDVECTOR(&ballPos, &ballPos, &ballVel);
			//ballPos.vy-=(ballVel.vy*2);

			//TIMER_START(TIMER_COLLISION);

			//if ( collboxCheckSphere(&ballColl) ) 
			//{
			//	BallCtrl.ballOnGround=TRUE;
			//	ActorStartRoll(pBallPSA,ballVel.vx,ballVel.vz);
			//}
			//else BallCtrl.ballOnGround=FALSE;
			//TIMER_STOP(TIMER_COLLISION);

			//pBallPSA->position.vx=ballPos.vx/4096;
			//pBallPSA->position.vy=ballPos.vy/4096;
			//pBallPSA->position.vz=ballPos.vz/4096;

			//pGlovePSA->position.vx=glovePos.vx/4096;
			//pGlovePSA->position.vy=glovePos.vy/4096;
			//pGlovePSA->position.vz=glovePos.vz/4096;

			//TIMER_START(TIMER_COLLISION);
			//collboxCheckSphere(&gloveColl);
			//collboxCheckSphere(&gloveColl);
			//TIMER_STOP(TIMER_COLLISION);
			HandCollision();
			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			break;

		case HAND_LOCATE:

			moveBall(0,0);
			//ballVel.vy-=BallBehaviour[BallCtrl.type].gravity;
			//ADDVECTOR(&ballPos, &ballPos, &ballVel);
			//ballPos.vy-=(ballVel.vy*2);

			//if ( collboxCheckSphere(&ballColl) ) 
			//{
			//	BallCtrl.ballOnGround=TRUE;
			//	ActorStartRoll(pBallPSA,ballVel.vx,ballVel.vz);
			//}
			//else BallCtrl.ballOnGround=FALSE;

			//pBallPSA->position.vx=ballPos.vx/4096;
			//pBallPSA->position.vy=ballPos.vy/4096;
			//pBallPSA->position.vz=ballPos.vz/4096;
			if (GloveCtrl.onIce)
			{
				ADDVECTOR(&glovePos, &glovePos, &gloveVel);
				//gloveVel.vx=0;
				//gloveVel.vz=0;
				HandCollision();
				printf ("vel x %d z %d pos %x z %d\n",(int)gloveVel.vx,(int)gloveVel.vz,(int)glovePos.vx,(int)glovePos.vz);
			}

			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			pGlovePSA->world.rotate.vy=GloveCtrl.direction;

			break;

		case HAND_THROWAIM:
		//case HAND_THROW2CUP:
			//if (GloveCtrl.flags==STOPGLOVEMOVE)
			//{	// put aim here
				tempV.vx=abs(leftRight);
				tempV.vy=abs(upDown);
				tempV.vz=0;
				temp=Magnitude(&tempV);

				if (temp)
				{
					temp=calc_angle( leftRight,upDown );
					targetAngle=(temp+CamVars.angle)&4095;
					temp = findShortestAngle(GloveCtrl.direction,targetAngle);
					if (temp>0)
					{
						if ( temp>ROTATESPEED ) GloveCtrl.direction-=ROTATESPEED;
						else GloveCtrl.direction=targetAngle;
					}
					else if (temp<0)
					{
						if ( temp<-ROTATESPEED ) GloveCtrl.direction+=ROTATESPEED;
						else GloveCtrl.direction=targetAngle;
					}
				}
//				else
//				{
//					temp=0;
//				}

			//}

			GloveCtrl.direction&=4095;
			pGlovePSA->world.rotate.vy=GloveCtrl.direction;

			//glovePos.vx=ballPos.vx;
			//glovePos.vz=ballPos.vz;			

			tempVect.vz = BallBehaviour[BallCtrl.type].radius/2;
			tempVect.vy=0;
			tempVect.vx=0;
			RotateVector2D(&tempVect, &tempVect,GloveCtrl.direction );

			glovePos.vx = oldGlovePos.vx+tempVect.vx;//+gloveVel.vx;
			glovePos.vz = oldGlovePos.vz+tempVect.vz;//+gloveVel.vz;

			ballPos.vx=oldGlovePos.vx;
			ballPos.vz=oldGlovePos.vz;

			if (GloveCtrl.flags&GLOVEMOVE)
			{
				gloveVel.vy-=gravity;
				ADDVECTOR(&glovePos, &glovePos, &gloveVel);
				glovePos.vy-=(gloveVel.vy*2);
			}

			//if (BallCtrl.ballStopMove!=TRUE)
			//{
			//	ballVel.vy-=BallBehaviour[BallCtrl.type].gravity;
			//	ADDVECTOR(&ballPos, &ballPos, &ballVel);
			//	ballPos.vy-=(ballVel.vy*2);
			//}
/*
			TIMER_START(TIMER_COLLISION);

			if ( collboxCheckSphere(&ballColl) ) 
			{
				BallCtrl.ballOnGround=TRUE;
				ActorStartRoll(pBallPSA,ballVel.vx,ballVel.vz);
				BallApplySquash();
			}
			else BallCtrl.ballOnGround=FALSE;
			TIMER_STOP(TIMER_COLLISION);
			BallUpdateSquash();
*/
			UpdateBallPos();
			pBallPSA->position.vx=ballPos.vx/4096;
			pBallPSA->position.vy=ballPos.vy/4096;
			pBallPSA->position.vz=ballPos.vz/4096;

			//TIMER_START(TIMER_COLLISION);
			//collboxCheckSphere(&gloveColl);
			//collboxCheckSphere(&gloveColl);
			//TIMER_STOP(TIMER_COLLISION);
			HandCollision();
			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			break;


		case HAND_ROTOR:

			moveBall(0,0);
			if (BallCtrl.ballOnGround && GloveCtrl.lastAction==HAND_JOINED)
			{
				gloveVel.vy-=GloveBehaviour.gravity;
				ADDVECTOR(&glovePos, &glovePos, &gloveVel);
				glovePos.vy-=(gloveVel.vy*2);

				glovePos.vy=ballPos.vy+(BallBehaviour[BallCtrl.type].radius-BallBehaviour[BALL_MODE_NORMAL].radius);
			}
			else
			{
				gloveVel.vy-=GloveBehaviour.gravity;
				ADDVECTOR(&glovePos, &glovePos, &gloveVel);
				glovePos.vy-=(gloveVel.vy*2);
			}

			tempV.vx=abs(leftRight);
			tempV.vy=abs(upDown);
			tempV.vz=0;

			temp=Magnitude(&tempV);
			if (temp>4096) temp=4096;

			if (temp)
			{
				temp=(calc_angle( leftRight,upDown ) &4095);
				targetAngle=(temp+CamVars.angle)&4095;
				temp = (findShortestAngle(GloveCtrl.direction,targetAngle) );
				//pGlovePSA->world.rotate.vz=512+1024;
				if (temp>0)
				{
					if ( temp>ROTATESPEED )	GloveCtrl.direction-=ROTATESPEED;
					else GloveCtrl.direction=targetAngle;
				}
				else if (temp<0)
				{
					if ( temp<-ROTATESPEED ) GloveCtrl.direction+=ROTATESPEED;
					else GloveCtrl.direction=targetAngle;
				}
			}

			temp=Magnitude(&tempV);
			if (temp>4096) temp=4096;
			GloveCtrl.targetSpeed=(TOPSPEED*temp)/4096;


			GloveCtrl.oldSpeed=GloveCtrl.speed;
			if (GloveCtrl.speed<GloveCtrl.targetSpeed)
			{
				if ( GloveCtrl.speed<(GloveCtrl.targetSpeed+(GloveBehaviour.accel/4096)) ) 
					GloveCtrl.speed+=GloveBehaviour.accel/4096;
				else
					GloveCtrl.speed=GloveCtrl.targetSpeed;
			}
			else if (GloveCtrl.speed>GloveCtrl.targetSpeed)
			{
				if ( GloveCtrl.speed>(GloveCtrl.targetSpeed+(GloveBehaviour.accel/4096)) )
					GloveCtrl.speed-=GloveBehaviour.accel/4096;
				else
					GloveCtrl.speed=GloveCtrl.targetSpeed;
			}
			GloveCtrl.direction&=4095;
			pGlovePSA->world.rotate.vy=GloveCtrl.direction;

			gloveVel.vz=-(rcos(GloveCtrl.direction)*GloveCtrl.speed)/16;
			gloveVel.vx=-(rsin(GloveCtrl.direction)*GloveCtrl.speed)/16;

			if (GloveCtrl.lastAction==HAND_JOINED)
			{
				ballPos.vx=glovePos.vx;
				ballPos.vy=glovePos.vy+(/*BallBehaviour[BallCtrl.type].radius-*/BallBehaviour[BALL_MODE_NORMAL].radius);
				ballPos.vz=glovePos.vz;

				ballVel.vx=gloveVel.vx;
				ballVel.vy=gloveVel.vy;
				ballVel.vz=gloveVel.vz;
			}

			GloveCtrl.direction=GloveCtrl.direction&4095;

			pGlovePSA->world.rotate.vy=GloveCtrl.direction;

			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			HandCollision();
			break;

	
		case HAND_JOINED:	// need to focus control on ball

			moveBall(upDown,leftRight);
			gloveVel.vy=ballVel.vy; // new

			// could this be the problem ?
			if (GloveCtrl.lastAction!=HAND_BALLWALK || GloveCtrl.actionTime>10)
			{
				glovePos.vy=ballPos.vy; // new
			}
			else
			{
				glovePos.vy=(( ballPos.vy*GloveCtrl.actionTime ) + ( GloveCtrl.move.vy* (10-GloveCtrl.actionTime) ) )/10;
			}
			glovePos.vx=ballPos.vx;
			glovePos.vz=ballPos.vz;

			tempV.vx=abs(leftRight);
			tempV.vy=abs(upDown);
			tempV.vz=0;
			temp=Magnitude(&tempV);
			if (temp>4096) temp=4096;

			if (temp)
			{
				temp=(calc_angle( leftRight,upDown ) &4095);
				targetAngle=(temp+CamVars.angle)&4095;
				temp = (findShortestAngle(GloveCtrl.direction,targetAngle) );
				if (temp>0)
				{
					if ( temp>ROTATESPEED )	GloveCtrl.direction-=ROTATESPEED;
					else GloveCtrl.direction=targetAngle;
				}
				else if (temp<0)
				{
					if ( temp<-ROTATESPEED ) GloveCtrl.direction+=ROTATESPEED;
					else GloveCtrl.direction=targetAngle;
				}
			}
//			else temp=0;

			GloveCtrl.direction=GloveCtrl.direction&4095;
			pGlovePSA->world.rotate.vy=GloveCtrl.direction;

			//tempVect.vz = BallBehaviour[BallCtrl.type].radius/2;
			if (GloveCtrl.lastAction!=HAND_BOUNCE)
			{
				tempVect.vz = BallBehaviour[BallCtrl.type].radius-GloveBehaviour.radius/3;
				tempVect.vy=0;
				tempVect.vx=0;
				RotateVector2D(&tempVect, &tempVect,GloveCtrl.direction );
				glovePos.vx += tempVect.vx;
				glovePos.vz += tempVect.vz;
			}
			else
			{
				if (GloveCtrl.actionTime<10)
				{
					tempVect.vx=(GloveCtrl.move.vx)/(GloveCtrl.actionTime+1);
					tempVect.vy=(GloveCtrl.move.vy)/(GloveCtrl.actionTime+1);
					tempVect.vz=(GloveCtrl.move.vz)/(GloveCtrl.actionTime+1);

					glovePos.vx += tempVect.vx;
					glovePos.vy += tempVect.vy;
					glovePos.vz += tempVect.vz;

					tempVect.vz = BallBehaviour[BallCtrl.type].radius-GloveBehaviour.radius/3;
					tempVect.vy=0;
					tempVect.vx=0;
					RotateVector2D(&tempVect, &tempVect,GloveCtrl.direction );

					glovePos.vx += (tempVect.vx*(GloveCtrl.actionTime))/10;
					glovePos.vz += (tempVect.vz*(GloveCtrl.actionTime))/10;
				}
				else GloveCtrl.lastAction=NULL;
			}

			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			HandCollision();

			break;

		case HAND_BOUNCE:

			gloveVel.vx=ballVel.vx;
			gloveVel.vz=ballVel.vz;

			glovePos.vx=ballPos.vx;
			glovePos.vz=ballPos.vz;			

			gloveVel.vy-=GloveBehaviour.gravity;
			ADDVECTOR(&glovePos, &glovePos, &gloveVel);
			glovePos.vy-=(gloveVel.vy*2);

			moveBall(upDown,leftRight);

			tempV.vx=abs(leftRight);
			tempV.vy=abs(upDown);
			tempV.vz=0;

			temp=Magnitude(&tempV);
			if (temp>4096) temp=4096;

			if (temp)
			{
				temp=(calc_angle( leftRight,upDown ) &4095);
				targetAngle=(temp+CamVars.angle)&4095;
				temp = (findShortestAngle(GloveCtrl.direction,targetAngle) );
				if (temp>0)
				{
					if ( temp>ROTATESPEED )	GloveCtrl.direction-=ROTATESPEED;
					else GloveCtrl.direction=targetAngle;
				}
				else if (temp<0)
				{
					if ( temp<-ROTATESPEED ) GloveCtrl.direction+=ROTATESPEED;
					else GloveCtrl.direction=targetAngle;
				}
			}
//			else temp=0;

			GloveCtrl.direction=GloveCtrl.direction&4095;

			pGlovePSA->world.rotate.vy=GloveCtrl.direction;

			tempVect.vz = 4096*2;
			tempVect.vy=0;
			tempVect.vx=0;
			RotateVector2D(&tempVect, &tempVect,GloveCtrl.direction );
			glovePos.vx += tempVect.vx;
			glovePos.vz += tempVect.vz;
			
			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			HandCollision();
			break;

//		case HAND_PUSH:
//			pGlovePSA->world.rotate.vy=GloveCtrl.direction;
//			moveBall(0,0);
//			HandCollision();
//			break;

//		case HAND_RELEASE:
//
//			break;

		default:
//			printf ("No update for this action using default\n");	// printf removed for running speed
			pGlovePSA->world.rotate.vy=GloveCtrl.direction;
			
			moveBall(0,0);

			gloveVel.vy-=gravity;
			ADDVECTOR(&glovePos, &glovePos, &gloveVel);
			glovePos.vy-=(gloveVel.vy*2);

			//pBallPSA->position.vx=ballPos.vx/4096;
			//pBallPSA->position.vy=ballPos.vy/4096;
			//pBallPSA->position.vz=ballPos.vz/4096;


			//TIMER_START(TIMER_COLLISION);
			//collboxCheckSphere(&gloveColl);
			//collboxCheckSphere(&gloveColl);
			//TIMER_STOP(TIMER_COLLISION);
			HandCollision();
			pGlovePSA->position.vx=glovePos.vx/4096;
			pGlovePSA->position.vy=glovePos.vy/4096;
			pGlovePSA->position.vz=glovePos.vz/4096;

			break;
	}
//	printf (",");
//	objectSetAnimation(pBallPSA, 0);
//	objectDrawWithShadow(pBallPSA,ballColl.radius >> 12,ballColl.radius >> 12,0);

}



void	UpdateGlovePos(void)
{
VECTOR	tempVect;
LONG	mag;

	if(!GloveCtrl.enabled)
		return;

	if (GloveCtrl.onIce)
	{
		//printf("%d\n",TRUE);
		if (GloveCtrl.onIceFlag==FALSE)	// first time?
		{
			GloveCtrl.iceData.vx=gloveVel.vx;
			GloveCtrl.iceData.vz=gloveVel.vz;
			GloveCtrl.onIceFlag=TRUE;
		}
		//if (GloveCtrl.iceData.vx<gloveVel.vx) GloveCtrl.iceData.vx+=(gloveVel.vx-GloveCtrl.iceData.vx)/4;
		//else if (GloveCtrl.iceData.vx>gloveVel.vx) GloveCtrl.iceData.vx+=(gloveVel.vx-GloveCtrl.iceData.vx)/4;
		mag=Magnitude(&gloveVel);

		GloveCtrl.iceData.vx-=(GloveCtrl.slideNormal.vx*1);
		GloveCtrl.iceData.vz-=(GloveCtrl.slideNormal.vz*1);

		if ( mag>ICESLIDESPEED)
		{
			GloveCtrl.iceData.vx+=(gloveVel.vx-GloveCtrl.iceData.vx)/30;
			GloveCtrl.iceData.vz+=(gloveVel.vz-GloveCtrl.iceData.vz)/30;
		}
		else
		{
			GloveCtrl.iceData.vx+=(gloveVel.vx-GloveCtrl.iceData.vx)/60;
			GloveCtrl.iceData.vz+=(gloveVel.vz-GloveCtrl.iceData.vz)/60;
		}
		gloveVel.vx=GloveCtrl.iceData.vx;
		gloveVel.vz=GloveCtrl.iceData.vz;
		if (GloveCtrl.action==HAND_CRAWL || GloveCtrl.action==HAND_THROWAIM)
		{
			GloveCtrl.iceData.vx=0;
			GloveCtrl.iceData.vz=0;	
		}
		GloveCtrl.onIce++;
	}
	else if (GloveCtrl.onIceFlag) GloveCtrl.onIceFlag=FALSE;

	if (GloveCtrl.onIce==7) GloveCtrl.onIce=FALSE;

	if (GloveCtrl.inWaterFlag==NOWHERENEARWATER || GloveCtrl.inWaterFlag==ABOVEWATER)
	{
		//HAND_THROWAIM
		COPYVECTOR(&oldGlovePos, &glovePos);
		gloveVel.vy-=gravity;
		ADDVECTOR(&glovePos, &glovePos, &gloveVel);
		glovePos.vy-=(gloveVel.vy*2);
		if (GloveCtrl.onConveyer==XPOS) glovePos.vx+=(GloveCtrl.conveyerTimer*4096);
		if (GloveCtrl.onConveyer==XNEG) glovePos.vx-=(GloveCtrl.conveyerTimer*4096);
		if (GloveCtrl.onConveyer==ZPOS) glovePos.vz+=(GloveCtrl.conveyerTimer*4096);
		if (GloveCtrl.onConveyer==ZNEG) glovePos.vz-=(GloveCtrl.conveyerTimer*4096);

		if (GloveCtrl.conveyerTimer) GloveCtrl.conveyerTimer--;
		if (!GloveCtrl.conveyerTimer) GloveCtrl.onConveyer=FALSE;
	}
	else
	{
		COPYVECTOR(&oldGlovePos, &glovePos);
		gloveVel.vy-=gravity;
		tempVect.vx=gloveVel.vx/2;
		tempVect.vy=gloveVel.vy;
		tempVect.vz=gloveVel.vz/2;
		ADDVECTOR(&glovePos, &glovePos, &tempVect);
		glovePos.vy-=(gloveVel.vy*2);
	}
}
















