#include "glover.h"

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

/***********************************************************************/
//#define	PRINTMESS	FALSE

COLLBOX		*collBox;
long		numCollBoxes;
COLLDATA	ballColl; //,gloveColl;

HITDATA 	pHitData[16]; // max number of hits


VECTOR ballVel, ballPos, ballRot ,ballOldPos;
VECTOR cameraVel, cameraPos, cameraRot;	// added for camera collision
VECTOR gloveVel,glovePos,oldGlovePos,oldBallPos;
NEWMODEL	*pBallPSA,*pCballPSA,*pOldBall;
NEWMODEL	*pCryFrag,*pSnowFrag;
NEWMODEL	*pBoulderPSA,*pGloveBoulderPSA;
NEWMODEL	*pGlovePSA;
NEWMODEL	*pRotorPSA;
NEWMODEL	*pPlasterPSA;
NEWMODEL	*pPhongPSA;
// Models for cabonus
NEWMODEL	*pCannonPSA;
NEWMODEL	*pRing01PSA,*pRing02PSA,*pRing03PSA;
NEWMODEL	*pPod01PSA;
NEWMODEL	*pCard01PSA,*pCard02PSA,*pCard03PSA;
NEWMODEL	*chuckBullet,*dennisBullet,*bugleBullet;


BOULDERDATA	BoulderData[10];
COLLDATA	BoulderColl[10];

COLLDATA	CancerColl[2];
VECTOR		CancerPos[2];
VECTOR		CancerVel[2];

long    ballRadius=(19*4096*NORMAL_SCALE)*1;
//long    ballGravity=4096;

//SETUP BALL DATA //
BALLCTRL	BallCtrl;

BALLCHANGE	BallChange;
SPRITEX		*ballTex[8];

/*	BALL_MODE_NORMAL,  0->1
	BALL_MODE_BOWLING, 1->3
	BALL_MODE_POWER,   2->2
	BALL_MODE_BEARING, 3->6
	BALL_MODE_BEACH,   4->4
	BALL_MODE_SNOW,    5->5
	BALL_MODE_CRYSTAL, 6->0
*/

char ballNextMode[] =
{
	1,3,2,6,4,5,0
};



IQUATERNION		PlasterQuat[4]={
	{  	-1874,2169,2548,-1265},
	{	-3657,-777,556,1504},
	{	-2494,1832,585,-2571},
	{	1359,2062,95,-3219},
};


BEHAVIOUR_PHYSICS	BoulderBallPhysics=
{
	18*4096,			// mass;
	GRAVITY,			// gravity;
	.6*4096,			// bounce
	4096*0.99,			// drag
	1*(19*4096*NORMAL_SCALE)*1.4, //
	(24*4096*NORMAL_SCALE)*1.4, 		// radius 	(may need to come back and remove floats)
	4096/1.98,			// accel
	0
};

BEHAVIOUR_PHYSICS	CannonBallPhysics=
{
	18*4096,			// mass;
	GRAVITY,			// gravity;
	4096,			// bounce
	4096,			// drag
	1*(19*4096*NORMAL_SCALE)*1.4, //
	(19*4096*NORMAL_SCALE)*1.4, 		// radius 	(may need to come back and remove floats)
	4096,			// accel
	0
};


BEHAVIOUR_PHYSICS	BoulderBallPhysicsVent=
{
	18*4096,			// mass;
	GRAVITY,			// gravity;
	.6*4096,			// bounce
	4096*0.99,			// drag
	1*(19*4096*NORMAL_SCALE)*1.4, //
	(24*4096*NORMAL_SCALE)*1.4, 		// radius 	(may need to come back and remove floats)
	4096/1.98,			// accel
	0
};

IQUATERNION		CancerQuat[2]={
	{  	-1874,2169,2548,-1265},
	{	-3657,-777,556,1504},
};



BEHAVIOUR_PHYSICS	CancerPart1=		// the data will be overwriten by current ball type
{
	18*4096,			// mass;
	GRAVITY,			// gravity;
	.6*4096,			// bounce
	4096*0.99,			// drag
	1*(19*4096*NORMAL_SCALE)*1.4, //
	(24*4096*NORMAL_SCALE)*1.4, 		// radius 	(may need to come back and remove floats)
	4096/1.98,			// accel
	0
};

BEHAVIOUR_PHYSICS	CancerPart2=		// the data will be overwriten by current ball type
{
	18*4096,			// mass;
	GRAVITY,			// gravity;
	.6*4096,			// bounce
	4096*0.99,			// drag
	1*(19*4096*NORMAL_SCALE)*1.4, //
	(24*4096*NORMAL_SCALE)*1.4, 		// radius 	(may need to come back and remove floats)
	4096/1.98,			// accel
	0
};


BEHAVIOUR_PHYSICS	BallBehaviour[NUM_BALL_MODES]=
{
	//NORMAL_BALL	0
	{
		10*4096,			// mass;
		GRAVITY,			// gravity;
		.9*4096,			// bounce
		4096*0.91,			//(4096-(4096*0.05)),	// drag
		1*(19*4096*NORMAL_SCALE)*1,			// maxspeed (radius*2)
		(19*4096*NORMAL_SCALE)*1,			// radius
		4096,				// accel
		(0.4*4096),			// max squash amount
	},
	//BOWLING_BALL	1
	{
		18*4096,			// mass;
		GRAVITY,			// gravity;
		.6*4096,			// bounce
		4096*0.91,			// drag
		//4096*0.99,			// drag (this gives the boulder
		1*(19*4096*NORMAL_SCALE)*1.4, //
		//4096*10,			// maxspeed
		(19*4096*NORMAL_SCALE)*1.4, 		// radius 	(may need to come back and remove floats)
		4096/1.98,			// accel
		0,
	},
	//POWER_BALL	2
	{
		7*4096,				// mass;
		GRAVITY,			// gravity;
		.9*4096,			// bounce
		4096 * 0.95,				// drag // was 0.91
//		.99*4096,			// bounce
//		4096*0.99,			// drag // was 0.91
		//4096*10,			// maxspeed
		1*(19*4096*NORMAL_SCALE)*0.6,
		(19*4096*NORMAL_SCALE)*0.6, 		// radius 	(may need to come back and remove floats)
		4096*1.5, 			// accel
		(0.45*4096),
	},
	//BALL_BEARING	3
	{
		10*4096,			// mass;
		GRAVITY,			// gravity;
		.6*4096,			// bounce
		4096*0.91,			// drag
		//4096*10,			// maxspeed
		1*(19*4096*NORMAL_SCALE)*0.6,
		(19*4096*NORMAL_SCALE)*0.6, 		// radius 	(may need to come back and remove floats)
		4096, 				// accel
		0,
	},
	//BEACH_BALL	4
	{
		3*4096,				// mass;
		GRAVITY,			// gravity;
		.9*4096,			// bounce
		4096*0.91,			// drag
		//4096*10,			// maxspeed
		1*(19*4096*NORMAL_SCALE)*2.5,
		(19*4096*NORMAL_SCALE)*2.5, 		// radius 	(may need to come back and remove floats)
		4096,	 			// accel
		(0.3*4096),
	},
	//CRYSTAL_BALL	5
	{
		12*4096,			// mass;
		GRAVITY,			// gravity;
		.6*4096,			// bounce
		4096*0.91,			// drag
		//4096*10,			// maxspeed
		1*(19*4096*NORMAL_SCALE)*0.9,
		(19*4096*NORMAL_SCALE)*0.9, 		// radius 	(may need to come back and remove floats)
		4096,	 			// accel
		(0.1*4096),
	},
	//SNOW_BALL		6
	{
		10*4096,			// mass;
		GRAVITY,			// gravity;
		.6*4096,			// bounce
		4096*0.91,			// drag
		//4096*10,			// maxspeed
		1*(19*4096*NORMAL_SCALE)*1,
		(19*4096*NORMAL_SCALE)*1, 		// radius 	(may need to come back and remove floats)
		4096,	 			// accel
		(0.01*4096)
	},
};



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

char *ballNames[]=
{
	"Normal",
	"Bowling",
	"Power",
	"Bearing",
	"Beach",
	"Snow",
	"Crystal"
};
SHORT	nextBoulderTimer=0;
SHORT	nextBoulderTimer2=0;
void
Load_And_Init_Ball(){	
/*
	pBallPSA=LoadPSA("TEST\\GBALL.PSA");
//	pBallPSA=LoadPSA("TEST\\GOODGLOV.PSA");
//	printf("read glove file\n");
	objectSetupSegmentSort(pBallPSA);
	pBallPSA->globalscale.vx=320;
	pBallPSA->globalscale.vy=320;
	pBallPSA->globalscale.vz=320;
	   
	ballColl.nBoxes=numCollBoxes;
	ballColl.bounce=4096;
	ballColl.radius=16*4096;
	ballColl.pCollBox=collBox;
	ballColl.pVel=&ballVel;
	ballColl.pPos=&ballPos;
	ballColl.pRot=&ballRot;	// changed from FVECTOR

	ZEROVECTOR(&ballVel);
	ZEROVECTOR(&ballPos);

	ballPos.vx=50*4096;
	ballPos.vy=-100*4096;
	ballPos.vz=10*4096;
	ZEROVECTOR(&ballRot);
*/

	BallCtrl.ballSmashed=FALSE;

	BallCtrl.boomerangActiveTime=0;
	BallCtrl.cancerActiveTime=0;
	BallCtrl.boomerangTime=0;

	BallChange.ambient.vx=127*16;
	BallChange.ambient.vy=127*16;
	BallChange.ambient.vz=127*16;

	BallChange.dimAmbient.vx=127*16;
	BallChange.dimAmbient.vy=127*16;
	BallChange.dimAmbient.vz=127*16;

	BallChange.dimAmount.vx=4096;
	BallChange.dimAmount.vy=4096;
	BallChange.dimAmount.vz=4096;

	BallChange.changeOn=FALSE;

	ballTex[0]=FindTexture("NEWBALL2"); // normal

	ballTex[1]=FindTexture("BOWLING");	// bowling ball
	//ballTex[2]=FindTexture("BOTBLUE");	// need power ball texture
	ballTex[2]=FindTexture("POWER");	// need power ball texture

	//modelctrl.specialFX=99;
	ballTex[3]=FindTexture("BEARING");	// ball bearing
	//modelctrl.specialFX=0;
	ballTex[4]=FindTexture("BEACH");	// beachball
	ballTex[5]=FindTexture("SNOW");	// need snow texture
	//ballTex[5]=FindTexture("WFALL3");	// need snow texture
	ballTex[6]=FindTexture("CBALL");	// crystal ball

	pOldBall=pBallPSA=BFF_IsModelLoaded("GBALL",NULL);
	pCballPSA=BFF_IsModelLoaded("CBALL",NULL);
	pPlasterPSA=BFF_IsModelLoaded("PLASTER",NULL);
	pPhongPSA=BFF_IsModelLoaded("SHINE",NULL);

	pCryFrag=BFF_IsModelLoaded("CSMASH",NULL);
	pSnowFrag=BFF_IsModelLoaded("SNOWFRAG",NULL);

	//if (level==PREHISTORIC2) pBoulderPSA=BFF_IsModelLoaded("BOULDER",NULL);

	if(!pOldBall || !pBallPSA || !pCballPSA || !pPlasterPSA ||!pPhongPSA)
	{
		printf("Ball problem\n");
		CRASH;
	}
//	pBallPSA=LoadPSA("test\\goodglov.psa");
//	printf("read glove file\n");
	objectSetupSegmentSort(pBallPSA);
	objectSetupSegmentSort(pCballPSA);
	objectSetupSegmentSort(pPlasterPSA);
	objectSetupSegmentSort(pPhongPSA);

	pBallPSA->globalscale.vx=(320*(NORMAL_SCALE) )*1;
	pBallPSA->globalscale.vy=(320*(NORMAL_SCALE) )*1;//(4096*NORMAL_SCALE);
	pBallPSA->globalscale.vz=(320*(NORMAL_SCALE) )*1;

	pBallPSA->world.qRot.x=-2896;
	pBallPSA->world.qRot.y=0;
	pBallPSA->world.qRot.z=0;
	pBallPSA->world.qRot.w=2896;

	pBallPSA->world.qRotVel.x=0;
	pBallPSA->world.qRotVel.y=0;
	pBallPSA->world.qRotVel.z=0;
	pBallPSA->world.qRotVel.w=4096;

	pBallPSA->world.qRotLight.x=-2896;
	pBallPSA->world.qRotLight.y=0;
	pBallPSA->world.qRotLight.z=0;
	pBallPSA->world.qRotLight.w=-2896;

	pBallPSA->world.qRotLightVel.x=0;
	pBallPSA->world.qRotLightVel.y=0;
	pBallPSA->world.qRotLightVel.z=0;
	pBallPSA->world.qRotLightVel.w=4096;

	pCballPSA->globalscale.vx=(320*(NORMAL_SCALE) )*1;
	pCballPSA->globalscale.vy=(320*(NORMAL_SCALE) )*1;
	pCballPSA->globalscale.vz=(320*(NORMAL_SCALE) )*1;

	pCballPSA->world.qRot.x=-2896;
	pCballPSA->world.qRot.y=0;
	pCballPSA->world.qRot.z=0;
	pCballPSA->world.qRot.w=2896;

	pCballPSA->world.qRotVel.x=0;
	pCballPSA->world.qRotVel.y=0;
	pCballPSA->world.qRotVel.z=0;
	pCballPSA->world.qRotVel.w=4096;

	pCballPSA->world.qRotLight.x=-2896;
	pCballPSA->world.qRotLight.y=0;
	pCballPSA->world.qRotLight.z=0;
	pCballPSA->world.qRotLight.w=-2896;

	pCballPSA->world.qRotLightVel.x=0;
	pCballPSA->world.qRotLightVel.y=0;
	pCballPSA->world.qRotLightVel.z=0;
	pCballPSA->world.qRotLightVel.w=4096;

	pBallPSA->world.rotate.vx=0;
	pBallPSA->world.rotate.vy=0;
	pBallPSA->world.rotate.vz=0;

	BallCtrl.snowAddition=0;
	ballColl.nBoxes=numCollBoxes;
//	ballColl.bounce=4096;	// now exzists in physics
	ballColl.radius=(19*4096*(NORMAL_SCALE) );
	ballColl.pCollBox=collBox;
	ballColl.pVel=&ballVel;
	ballColl.pPos=&ballPos;
	ballColl.pRot=&ballRot;	// changed from FVECTOR

	ballColl.physics=&BallBehaviour[0];		// behaviour's the base of the table, so should be 0
	ballColl.physicsModel=BALL_MODE_NORMAL;	// model is an index from physics, so should match the ball type

	ZEROVECTOR(&ballVel);
	ZEROVECTOR(&ballPos);

	ballPos.vx=215363;
	ballPos.vy=-202752;
	ballPos.vz=123356;

	BallCtrl.ballOnGround=TRUE;
	BallCtrl.type=BALL_MODE_NORMAL;
	BallCtrl.hurt=FALSE;	// set ball hurt off
	BallCtrl.health=4;
	BallCtrl.ballStopMove=FALSE;
	BallCtrl.nextHitCount=0;
	BallCtrl.inside_bugle = 0;

	BallCtrl.enabled = 0;	// start the level *without* the ball
	BallCtrl.snowTexChange=FALSE;
	BallCtrl.onIce=FALSE;
	BallCtrl.onIceFlag=FALSE;
	BallCtrl.onSnow=FALSE;
	BallCtrl.megaSticky=FALSE;

	BallCtrl.cancerFlag=FALSE;
	BallCtrl.cancerActiveTime=0;
	GloveCtrl.ballHurtTime=NULL;

	BallCtrl.boomerangActiveTime=0;
	BallCtrl.cancerActiveTime=0;
	BallCtrl.boomerangTime=0;
	BallCtrl.boomerangOn=0;
	BallCtrl.noBounce=FALSE;

	handpower_timer = 0;
	handpower_duration = 0;
	handpower_type = 0;

	ChangeBall(&pBallPSA->world,ballTex[BallCtrl.type]);
	ZEROVECTOR(&ballRot);
	ZEROVECTOR(&BallCtrl.squash);
	ZEROVECTOR(&BallCtrl.expand);
}

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

void	resetBall(void)
{

	//DB ("reseting ball\n");

	pBallPSA->globalscale.vx=(320*(NORMAL_SCALE) )*1;
	pBallPSA->globalscale.vy=(320*(NORMAL_SCALE) )*1;//(4096*NORMAL_SCALE);
	pBallPSA->globalscale.vz=(320*(NORMAL_SCALE) )*1;

	pBallPSA->world.qRot.x=-2896;
	pBallPSA->world.qRot.y=0;
	pBallPSA->world.qRot.z=0;
	pBallPSA->world.qRot.w=2896;

	pBallPSA->world.qRotVel.x=0;
	pBallPSA->world.qRotVel.y=0;
	pBallPSA->world.qRotVel.z=0;
	pBallPSA->world.qRotVel.w=4096;

	pBallPSA->world.qRotLight.x=-2896;
	pBallPSA->world.qRotLight.y=0;
	pBallPSA->world.qRotLight.z=0;
	pBallPSA->world.qRotLight.w=-2896;

	pBallPSA->world.qRotLightVel.x=0;
	pBallPSA->world.qRotLightVel.y=0;
	pBallPSA->world.qRotLightVel.z=0;
	pBallPSA->world.qRotLightVel.w=4096;

	pCballPSA->globalscale.vx=(320*(NORMAL_SCALE) )*1;
	pCballPSA->globalscale.vy=(320*(NORMAL_SCALE) )*1;
	pCballPSA->globalscale.vz=(320*(NORMAL_SCALE) )*1;

	pCballPSA->world.qRot.x=-2896;
	pCballPSA->world.qRot.y=0;
	pCballPSA->world.qRot.z=0;
	pCballPSA->world.qRot.w=2896;

	pCballPSA->world.qRotVel.x=0;
	pCballPSA->world.qRotVel.y=0;
	pCballPSA->world.qRotVel.z=0;
	pCballPSA->world.qRotVel.w=4096;

	pCballPSA->world.qRotLight.x=-2896;
	pCballPSA->world.qRotLight.y=0;
	pCballPSA->world.qRotLight.z=0;
	pCballPSA->world.qRotLight.w=-2896;

	pCballPSA->world.qRotLightVel.x=0;
	pCballPSA->world.qRotLightVel.y=0;
	pCballPSA->world.qRotLightVel.z=0;
	pCballPSA->world.qRotLightVel.w=4096;

	pBallPSA->world.rotate.vx=0;
	pBallPSA->world.rotate.vy=0;
	pBallPSA->world.rotate.vz=0;

	ballColl.nBoxes=numCollBoxes;
	ballColl.radius=(19*4096*(NORMAL_SCALE) );
	ballColl.pCollBox=collBox;
	ballColl.pVel=&ballVel;
	ballColl.pPos=&ballPos;
	ballColl.pRot=&ballRot;	// changed from FVECTOR
	BallCtrl.noBounce=FALSE;

	ballColl.physics=&BallBehaviour[0];
	ballColl.physicsModel=BALL_MODE_NORMAL;

	pBallPSA=pOldBall;
	ZEROVECTOR(&ballVel);
	ZEROVECTOR(&ballPos);

	ballPos.vx=BallStartPos.vx;
	ballPos.vy=BallStartPos.vy;
	ballPos.vz=BallStartPos.vz;

	BallCtrl.ballOnGround=TRUE;
	BallCtrl.type=BALL_MODE_NORMAL;
	BallCtrl.hurt=FALSE;	// set ball hurt off
	BallCtrl.health=4;
	BallCtrl.nextHitCount=0;
	BallCtrl.ballStopMove=FALSE;
	BallCtrl.onSnow=FALSE;
	BallCtrl.snowTexChange=FALSE;
	BallCtrl.enabled = 0;	// start the level *without* the ball

	BallCtrl.snowAddition=0;
	BallCtrl.onIce=FALSE;
	BallCtrl.onIceFlag=FALSE;
	BallCtrl.ballSmashed=FALSE;
	BallCtrl.megaSticky=FALSE;

	BallCtrl.cancerActiveTime=0;
	BallCtrl.cancerFlag=FALSE;
	GloveCtrl.ballHurtTime=NULL;

	BallCtrl.boomerangActiveTime=0;
	BallCtrl.cancerActiveTime=0;
	BallCtrl.boomerangTime=0;
	BallCtrl.boomerangOn=0;

	BallChange.changeOn=FALSE;
	ballColl.physics=&BallBehaviour[0];		// behaviour's the base of the table, so should be 0
	ballColl.physicsModel=BALL_MODE_NORMAL;	// model is an index from physics, so should match the ball type
	BallCtrl.type=BALL_MODE_NORMAL;
	ChangeBall(&pBallPSA->world,ballTex[BallCtrl.type]);

	BallCtrl.onIce=FALSE;
	BallCtrl.onIceFlag=FALSE;

	ZEROVECTOR(&BallCtrl.iceData);
	ZEROVECTOR(&BallCtrl.iceRollData);
	ZEROVECTOR(&BallCtrl.iceRollDataVel);

	handpower_timer = 0;
	handpower_duration = 0;
	handpower_type = 0;

	BallCtrl.ballSmashed=FALSE;

	ZEROVECTOR(&ballRot);
	ZEROVECTOR(&BallCtrl.squash);
	ZEROVECTOR(&BallCtrl.expand);
	ChangeBall(&pBallPSA->world,ballTex[BallCtrl.type]);
	ballStartRadius=ballRadius=BallBehaviour[BallCtrl.type].radius=ballColl.radius=(19*4096*(NORMAL_SCALE) );
}


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

// This is the N64 routine to roll the ball
// Note any commented out stuff was by me
// Converting to fixed format going to be a laugh!

void ActorStartRoll(NEWMODEL *actor,LONG x,LONG z) // will have to put quat stuff back in for models
{
	LONG	speed;
//	VECTOR	tempVect;

	if (x==0 && z==0) x=1;

	if (x>45000) x=45000;
	if (z>45000) z=45000;
	if (x<-45000) x=-45000;
	if (z<-45000) z=-45000;

	speed=Magnitude2D(x,z);

	//actor->world.qRotVel.w = speed/actor->maxRadius;

	actor->world.qRotVel.w = (speed*500)/ballColl.radius;
	if(speed)
	{
		actor->world.qRotVel.x = (z*4096)/speed;
		actor->world.qRotVel.z = -(x*4096)/speed;
		actor->world.qRotVel.y = 0;
	}
	else
	{
		actor->world.qRotVel.x = 0;
		actor->world.qRotVel.z = 0;
		actor->world.qRotVel.y = 0;
		actor->world.qRotVel.w = 4096;
	}
	//sprctrl.scalex=2048;
	//sprctrl.scaley=2048;

// Quats after a time go to zero

//	textPrintf ("Quat x %d\n",actor->world.qRot.x);
//	textPrintf ("Quat y %d\n",actor->world.qRot.y);
//	textPrintf ("Quat z %d\n",actor->world.qRot.z);
//	textPrintf ("Quat w %d\n",actor->world.qRot.w);

	speed=-speed;
	actor->world.qRotLightVel.w = ((speed*500)/ballColl.radius);
	if(speed)
	{
		actor->world.qRotLightVel.x = -(z*4096)/speed;	//-
		actor->world.qRotLightVel.z = 0;//(x*4096)/speed;	//+
		actor->world.qRotLightVel.y = -(x*4096)/speed;
	}
	else
	{
		actor->world.qRotLightVel.x = 0;
		actor->world.qRotLightVel.z = 0;
		actor->world.qRotLightVel.y = 0;
		actor->world.qRotLightVel.w = 4096;
	}
}
/************************************************************************************************/
void ActorRotateByAngle(NEWMODEL *actor,LONG y) // will have to put quat stuff back in for models
{
	LONG	speed;
	VECTOR	tempVect;

	tempVect.vx=0;
	tempVect.vy=y;
	tempVect.vz=0;
	speed=y;

	//actor->world.qRotVel.w = (speed*700)/ballColl.radius;
	actor->world.qRotVel.w = speed;
	if(speed)
	{
		actor->world.qRotVel.x = 0;
		actor->world.qRotVel.z = 0;
		actor->world.qRotVel.y = (y*4096)/speed;
	}
	else
	{
		actor->world.qRotVel.x = 0;
		actor->world.qRotVel.z = 0;
		actor->world.qRotVel.y = 0;
		actor->world.qRotVel.w = 4096;
	}
	sprctrl.scalex=2048;
	sprctrl.scaley=2048;

// Quats after a time go to zero

	speed=-speed;
	//actor->world.qRotLightVel.w = ((speed*700)/ballColl.radius);
	actor->world.qRotLightVel.w = speed;
	if(speed)
	{
		actor->world.qRotLightVel.x = 0;
		actor->world.qRotLightVel.z = (y*4096)/speed;
		actor->world.qRotLightVel.y = 0;
	}
	else
	{
		actor->world.qRotLightVel.x = 0;
		actor->world.qRotLightVel.z = 0;
		actor->world.qRotLightVel.y = 0;
		actor->world.qRotLightVel.w = 4096;
	}
}

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

// This is the N64 routine to roll the ball
// Note any commented out stuff was by me
// Converting to fixed format going to be a laught!
// This version works for y


void ActorStartRollSide(NEWMODEL *actor,LONG y) // will have to put quat stuff back in for models
{
	LONG	speed;
	VECTOR	tempVect;

	tempVect.vx=0;
	tempVect.vy=y;
	tempVect.vz=0;
	speed=y;

	actor->world.qRotVel.w = (speed*700)/ballColl.radius;
	if(speed)
	{
		actor->world.qRotVel.x = 0;
		actor->world.qRotVel.z = 0;
		actor->world.qRotVel.y = (y*4096)/speed;
	}
	else
	{
		actor->world.qRotVel.x = 0;
		actor->world.qRotVel.z = 0;
		actor->world.qRotVel.y = 0;
		actor->world.qRotVel.w = 4096;
	}
	sprctrl.scalex=2048;
	sprctrl.scaley=2048;

// Quats after a time go to zero

	speed=-speed;	 
	actor->world.qRotLightVel.w = ((speed*700)/ballColl.radius);
	if(speed)
	{
		actor->world.qRotLightVel.x = 0;
		actor->world.qRotLightVel.z = (y*4096)/speed;
		actor->world.qRotLightVel.y = 0;
	}
	else
	{
		actor->world.qRotLightVel.x = 0;
		actor->world.qRotLightVel.z = 0;
		actor->world.qRotLightVel.y = 0;
		actor->world.qRotLightVel.w = 4096;
	}
}




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



void ChangeBall(NEWOBJECT *world ,SPRITEX *spr)
{
	long		numVerts;
	long		primLeft;
	VERT		*vertTop;
	NORM		*normTop;
	TMD_P_TG4A	*op;
	TMD_P_TG3A	*opTG3;
	TMD_P_F4G	*opG4;

	unsigned char	*primPtr;
	int			*sortPtr;
//	VECTOR		vec1,vec2,vec3;
	long		xdiff,ydiff;
	
		
	sortPtr = world->meshdata->sorttable[0];
	primLeft = world->meshdata->sorttablesize[0];
	vertTop = world->meshdata->vertop;
	primPtr = (unsigned char*)world->meshdata->primtop;
	numVerts = world->meshdata->vern;
	normTop = world->meshdata->nortop;

	//printf("\nsegment %s",world->meshdata->name);
	//printf("\n%d verts",numVerts);
	//printf("\n%d polys",primLeft);


	op = (TMD_P_TG4A*)(primPtr);

	switch(op->cd & (0xff-2))
	{
		case GPU_COM_TG4:


			//op->spr=testTex1;

			xdiff=op->spr->x;
			ydiff=op->spr->y;

			xdiff-=spr->x;
			ydiff-=spr->y;

			break;

		case GPU_COM_TG3:
			//printf("\nfound a TG3");
			opTG3 = (TMD_P_TG3A*)op;

			xdiff=opTG3->spr->x;
			ydiff=opTG3->spr->y;

			xdiff-=spr->x;
			ydiff-=spr->y;

			opTG3->clut=spr->clut;
			opTG3->tpage=spr->tpage;
			opTG3->spr=(SPRITE*)spr;

			break;
		default:
			xdiff=ydiff=0;	// just to shut the warning up
			break;
	}

	
	while(primLeft)
	{
		op = (TMD_P_TG4A*)(primPtr);
		switch(op->cd & (0xff-2))
		{
			case GPU_COM_TG4:

				op->clut=spr->clut;
				op->tpage=spr->tpage;
				op->spr=(SPRITE*)spr;

				op->tu0-=xdiff;
				op->tv0-=ydiff;

				op->tu1-=xdiff;
				op->tv1-=ydiff;

				op->tu2-=xdiff;
				op->tv2-=ydiff;

				op->tu3-=xdiff;
				op->tv3-=ydiff;

				primPtr += sizeof(TMD_P_TG4A);
				break;

			case GPU_COM_TF4:
				BALL_PRINTF("\nunsupported poly type TF4");
				primPtr += sizeof(TMD_P_TF4A);
				break;

			case GPU_COM_G4:
				opG4 = (TMD_P_F4G *)op;
				//printf("\nfound a G4");
				primPtr += sizeof(TMD_P_F4G);
				break;
			case GPU_COM_F4:
				BALL_PRINTF("\nunsupported poly type F4");
				break;

			case GPU_COM_TG3:
				//printf("\nfound a TG3");
				opTG3 = (TMD_P_TG3A*)op;

				opTG3->clut=spr->clut;
				opTG3->tpage=spr->tpage;
				opTG3->spr=(SPRITE*)spr;

				opTG3->tu0-=xdiff;
				opTG3->tv0-=ydiff;

				opTG3->tu1-=xdiff;
				opTG3->tv1-=ydiff;

				opTG3->tu2-=xdiff;
				opTG3->tv2-=ydiff;

				primPtr += sizeof(TMD_P_TG3A);
				break;

			case GPU_COM_TF3:
				BALL_PRINTF("\nunsupported poly type TF3");
				primPtr += sizeof(TMD_P_TF3A);
				break;

			case GPU_COM_G3:
				//printf("\nfound a G3");
				
				primPtr += sizeof(TMD_P_F3G);
				break;

			case GPU_COM_F3:
				BALL_PRINTF("\nunsupported poly type F3");
				break;

			default:

				BALL_PRINTF("\nfound something nasty!");
				break;
		}
		primLeft--;
	}
}

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



void ChangeLscapeTex(NEWOBJECT *world ,SPRITEX *spr)
{
	long		numVerts;
	long		primLeft;
	VERT		*vertTop;
	NORM		*normTop;
	TMD_PTYPE_TG4	*op;
	TMD_PTYPE_TG3	*opTG3;

	unsigned char	*primPtr;
	int			*sortPtr;
//	VECTOR		vec1,vec2,vec3;
	long		xdiff,ydiff;
	
		
	sortPtr = world->meshdata->sorttable[0];
	primLeft = world->meshdata->sorttablesize[0];
	vertTop = world->meshdata->vertop;
	primPtr = (unsigned char*)world->meshdata->primtop;
	numVerts = world->meshdata->vern;
	normTop = world->meshdata->nortop;

	//printf("\nsegment %s",world->meshdata->name);
	//printf("\n%d verts",numVerts);
	//printf("\n%d polys",primLeft);


	op = (TMD_PTYPE_TG4*)(primPtr);

	switch(op->primtype & 1)
	{
		case PTYPE_TG4:
			//op->spr=testTex1;

			xdiff=op->spr->x;
			ydiff=op->spr->y;

			xdiff-=spr->x;
			ydiff-=spr->y;

			break;

		//case GPU_COM_TG3:
		case PTYPE_TG3:
			//printf("\nfound a TG3");
			opTG3 = (TMD_PTYPE_TG3*)op;

			xdiff=opTG3->spr->x;
			ydiff=opTG3->spr->y;

			xdiff-=spr->x;
			ydiff-=spr->y;

			opTG3->clut=spr->clut;
			opTG3->tpage=spr->tpage;
			opTG3->spr=(SPRITEX*)spr;

			break;
		default:
			xdiff=ydiff=0;	// just to shut the warning up
			break;
	}

	
	while(primLeft)
	{
		op = (TMD_PTYPE_TG4*)(primPtr);
		switch(op->primtype&1)
		{
			case PTYPE_TG4:

				op->clut=spr->clut;
				op->tpage=spr->tpage;
				op->spr=(SPRITEX*)spr;

				op->tu0-=xdiff;
				op->tv0-=ydiff;

				op->tu1-=xdiff;
				op->tv1-=ydiff;

				op->tu2-=xdiff;
				op->tv2-=ydiff;

				op->tu3-=xdiff;
				op->tv3-=ydiff;

				primPtr += sizeof(TMD_PTYPE_TG4);
				break;

			case GPU_COM_TF4:
				BALL_PRINTF("\nunsupported poly type TF4");
				primPtr += sizeof(TMD_P_TF4A);
				break;

			//case GPU_COM_G4:
			//	opG4 = (TMD_P_F4G *)op;
			//	//printf("\nfound a G4");
			//	primPtr += sizeof(TMD_P_F4G);
			//	break;
			case GPU_COM_F4:
				BALL_PRINTF("\nunsupported poly type F4");
				break;

			case PTYPE_TG3:
				//printf("\nfound a TG3");
				opTG3 = (TMD_PTYPE_TG3*)op;

				opTG3->clut=spr->clut;
				opTG3->tpage=spr->tpage;
				opTG3->spr=(SPRITEX*)spr;

				opTG3->tu0-=xdiff;
				opTG3->tv0-=ydiff;

				opTG3->tu1-=xdiff;
				opTG3->tv1-=ydiff;

				opTG3->tu2-=xdiff;
				opTG3->tv2-=ydiff;

				primPtr += sizeof(TMD_PTYPE_TG3);
				break;

			case GPU_COM_TF3:
				BALL_PRINTF("\nunsupported poly type TF3");
				primPtr += sizeof(TMD_P_TF3A);
				break;

			case GPU_COM_G3:
				//printf("\nfound a G3");
				
				primPtr += sizeof(TMD_P_F3G);
				break;

			case GPU_COM_F3:
				BALL_PRINTF("\nunsupported poly type F3");
				break;

			default:

				BALL_PRINTF("\nfound something nasty!");
				break;
		}
		primLeft--;
	}
}



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

// note - it's a spell type, not a ball control type
void ballHitBySpell(int spell_type,int time)
{

	//handpower_timer = time;
	//handpower_duration = time;
	//handpower_type = spell_type;

	if (BallChange.changeOn==SPELLCHANGE || (GloveCtrl.action==HAND_CASTSPELL && GloveCtrl.lastAction==HAND_JOINED) ) return;

	DB ("ball hit by spell\n");
	//BallCtrl.boomerangOn=FALSE;	// Turn off to stop fuck ups
	switch(spell_type)
	{

		case SPELL_CANCERBALL:
			//if (!BallCtrl.cancerFlag && !(BallCtrl.type==BALL_MODE_CRYSTAL) )

			handpower_timer = time;
			handpower_duration = time;
			handpower_type = spell_type;

			BallCtrl.cancerFlag=START;
			BallCtrl.cancerActiveTime=time;
			if (BallCtrl.type==BALL_MODE_CRYSTAL)
			{
				BallChange.fromBall=BallCtrl.type;
				BallCtrl.lastType=BallCtrl.type;
			
				//BallCtrl.type = spell_type - SPELL_BALL_NORMAL + BALL_MODE_NORMAL;
				BallCtrl.type = BALL_MODE_NORMAL;
				BallChange.toBall=BallCtrl.type;
				BallChange.timer=0;
				BallChange.changeOn=SPELLCHANGE;
				BallChange.startRadii=BallBehaviour[BallCtrl.type].radius;
				BallChange.endRadii=BallBehaviour[BallCtrl.lastType].radius;

				if (BallCtrl.type==BALL_MODE_CRYSTAL)
				{
					if (CamVars.targetmodel==pBallPSA) CamVars.targetmodel=pCballPSA;
					pBallPSA=pCballPSA;
				}
				
				if (BallCtrl.lastType==BALL_MODE_CRYSTAL)
				{
					if (CamVars.targetmodel==pBallPSA) CamVars.targetmodel=pOldBall;
					pBallPSA=pOldBall;
				}
			}

			return;

		case SPELL_DEATH:
		case SPELL_FROGGY:
			return;

		case SPELL_BOOMERANG:
// do stuff!
			if (!time)
			{
				DB("boomerang spell with no time set,setting time to 400\n");
				time=400;
			}
			handpower_timer = time;
			handpower_duration = time;
			handpower_type = spell_type;

			BallCtrl.boomerangOn=TRUE;
			BallCtrl.boomerangTime=0;
			BallCtrl.boomerangActiveTime=time;
			return;

		default:
			if (BallCtrl.type==BALL_MODE_CRYSTAL && spell_type == SPELL_BALL_CRYSTAL) return;
			//if (BallChange.changeOn) return;

			BallChange.fromBall=BallCtrl.type;
			BallCtrl.lastType=BallCtrl.type;
			BallCtrl.type = spell_type - SPELL_BALL_NORMAL + BALL_MODE_NORMAL;
			BallChange.toBall=BallCtrl.type;
			BallChange.timer=0;
			BallChange.changeOn=SPELLCHANGE;
			BallChange.startRadii=BallBehaviour[BallCtrl.type].radius;
			BallChange.endRadii=BallBehaviour[BallCtrl.lastType].radius;

			if (BallCtrl.type==BALL_MODE_CRYSTAL)
			{
				if (BallCtrl.cancerFlag)
				{
					BallCtrl.cancerFlag=NULL;
					handpower_timer = 0;
					handpower_duration = 0;
				}


				if (CamVars.targetmodel==pBallPSA) CamVars.targetmodel=pCballPSA;
				pBallPSA=pCballPSA;
			}
				
			if (BallCtrl.lastType==BALL_MODE_CRYSTAL)
			{
				if (CamVars.targetmodel==pBallPSA) CamVars.targetmodel=pOldBall;
				pBallPSA=pOldBall;
			}

			if (BallCtrl.type==BALL_MODE_BEACH)
			{
				handpower_timer = time;
				handpower_duration = time;
				handpower_type = spell_type;
			}


			//ballRadius=BallBehaviour[BallCtrl.type].radius;
			//ballColl.physicsModel=BallCtrl.type;

// this line was in gameflow, but only happened if the hand was doing its spell animation
// actions for this now moved to ball render ball.c
			//pBallPSA->globalscale.vx=ballRadius/152;
			//pBallPSA->globalscale.vy=ballRadius/152;
			//pBallPSA->globalscale.vz=ballRadius/152;

			//ChangeBall(&pBallPSA->world,ballTex[BallCtrl.type]);


			if(BallCtrl.inside_bugle)
			{
// This makes the ball rattle around in an interesting manner, and also prevents the beachball from falling out when
// you change to it.
				ballVel.vy = 10 * 4096;
			}


// the n64 just tweens the radius if it's a remote spell hit
// (& does the stars & twinkles if it's a spin-on-your-finger swap)

			New_StarRingDebris(&ballPos, 5);
			return;
	}
}


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

long	BallCloseToHand(void)
{
	VECTOR	tempVec;
	LONG	temp;
	int dist;

	if(!BallCtrl.enabled || level==CAVE || GloveCtrl.lastAction==HAND_CASTSPELL)
		return FALSE;

	tempVec.vx=ballPos.vx-glovePos.vx;
	tempVec.vy=ballPos.vy-glovePos.vy;
	tempVec.vz=ballPos.vz-glovePos.vz;

	temp=Magnitude(&tempVec);
	//temp=temp-(temp/2);

	if (BallCtrl.inWind || GloveCtrl.inWind)
	{
		if (GloveCtrl.action==HAND_THROW || GloveCtrl.action==HAND_WHACK || GloveCtrl.action==HAND_RELEASE || GloveCtrl.action==HAND_PREWHACK) return(FALSE);
		if (GloveCtrl.lastAction!=HAND_RELEASE) temp/=2;
	}

	if (BallCtrl.inside_bugle) return FALSE;

	
	
	if(GloveCtrl.onMovingPlat)
	{
		//DB("On moving plat\n");
		dist=ballColl.radius+GloveBehaviour.radius*2;
	}
	else
	{
		//DB("NOT on moving plat\n");
		dist=ballColl.radius+GloveBehaviour.radius+(GloveBehaviour.radius/2);
	}

	//if ( temp< (ballColl.radius+GloveBehaviour.radius+(GloveBehaviour.radius/2)) )
	if(temp<dist)
	{
		return(TRUE);
	}
	else
		return(FALSE);

}



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

void	moveBall(SHORT upDown,SHORT leftRight)
{
	VECTOR	tempV;
	LONG	temp,targetAngle,mag;


	if(!BallCtrl.enabled)
		return;

/*
	if (BallCtrl.onSticky)
	{
		drag=BallBehaviour[BallCtrl.type].drag;
		gravity=BallBehaviour[BallCtrl.type].gravity;
		accel=BallBehaviour[BallCtrl.type].accel;

		BallBehaviour[BallCtrl.type].drag/=2;
		BallBehaviour[BallCtrl.type].gravity/=10;
		BallBehaviour[BallCtrl.type].accel*=2;
	}
*/

	tempV.vx=leftRight;
	tempV.vz=upDown;
	tempV.vy=0;

//	tempV.vx-=tempV.vx/3;
//	tempV.vz-=tempV.vz/3;
	if(handpower_timer != 0 && handpower_type == SPELL_SPEEDUP)
	{
		tempV.vx *= 2;
		tempV.vz *= 2;
	}

	COPYVECTOR(&ballOldPos, &ballPos);

	RotateVector2D(&tempV, &tempV,CamVars.angle );			
	if (BallBehaviour[BallCtrl.type].accel!=4096)
		SCALEVECTOR(&tempV,BallBehaviour[BallCtrl.type].accel);	// This should modify speed by acceleration for ball type

	if (BallCtrl.nextHitCount) BallCtrl.nextHitCount--;
	if (BallCtrl.nextHitCount==0) CheckForNmeHitsBall();

	// Limit the balls max speed to below radius*2
	mag=Magnitude(&ballVel);

	if (mag<8*4096 && !BallCtrl.conveyerTimer)
	{
		ballVel.vx-=(tempV.vx*2);
		ballVel.vz-=(tempV.vz*2);
	}
	else
	{
		ballVel.vx-=(tempV.vx);
		ballVel.vz-=(tempV.vz);
	}


//	tempV.vx=ballVel.vx;
//	tempV.vy=0;
//	tempV.vz=ballVel.vz;
//	temp=Magnitude(&tempV);
	temp=Magnitude2D(ballVel.vx,ballVel.vz);

	BallCtrl.ballSpeed=temp;

	ballVel.vx=(ballVel.vx*BallBehaviour[BallCtrl.type].drag)/4096;

	if (!BallCtrl.onTrampoline) ballVel.vy=(ballVel.vy*(BallBehaviour[BallCtrl.type].drag+4096)/2)/4096;
	else ballVel.vy=(ballVel.vy*995)/1000;

	ballVel.vz=(ballVel.vz*BallBehaviour[BallCtrl.type].drag)/4096;

	if (GloveCtrl.handOnBall)
	{
		//temp=Magnitude(&tempV);
		//BallCtrl.ballSpeed=temp;
		if (temp>2048)
		{
			temp=(calc_angle( -ballVel.vx,-ballVel.vz ) &4095);

			if (temp)
			{
				temp=(calc_angle( -ballVel.vx,-ballVel.vz ) &4095);
				temp=(temp+2048) & 4095;
				targetAngle=temp;//(temp+CamVars.angle)&4095;
				temp = findShortestAngle(GloveCtrl.direction,targetAngle);
			}
			else temp=0;

			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=GloveCtrl.direction&4095;
			pGlovePSA->world.rotate.vy=GloveCtrl.direction;
		}
		else temp=0;
		gloveVel.vy=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;
	UpdateBallPos();

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

/*	if (drag)
	{
		BallBehaviour[BallCtrl.type].drag=drag;
		BallBehaviour[BallCtrl.type].gravity=gravity;
		BallBehaviour[BallCtrl.type].accel=accel;
	}
*/

}

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

void	doBallHurt(void)
{

long	loop,temp;
IQUATERNION squat1;

	if (BallCtrl.type==BALL_MODE_CRYSTAL || BallChange.changeOn) return;

	for (loop=0;loop<4-BallCtrl.health;loop++)
	{	
		pPlasterPSA->world.rotatekeys->vect.x=pBallPSA->world.qRot.x;
		pPlasterPSA->world.rotatekeys->vect.y=pBallPSA->world.qRot.y;//+(loop*2048);
		pPlasterPSA->world.rotatekeys->vect.z=pBallPSA->world.qRot.z;//-(loop*1234);
		pPlasterPSA->world.rotatekeys->vect.w=pBallPSA->world.qRot.w;


		if (loop>0 && loop<6)
		{
			QuaternionMultiplyDestNESrc(&squat1,&PlasterQuat[loop-1],&pBallPSA->world.qRot);
			pPlasterPSA->world.rotatekeys->vect.x=squat1.x;
			pPlasterPSA->world.rotatekeys->vect.y=squat1.y;
			pPlasterPSA->world.rotatekeys->vect.z=squat1.z;
			pPlasterPSA->world.rotatekeys->vect.w=squat1.w;
		}

		pPlasterPSA->globalscale.vx=pBallPSA->globalscale.vx;
		pPlasterPSA->globalscale.vy=pBallPSA->globalscale.vy;
		pPlasterPSA->globalscale.vz=pBallPSA->globalscale.vz;

		pPlasterPSA->position.vx=pBallPSA->position.vx;
		pPlasterPSA->position.vy=pBallPSA->position.vy;
		pPlasterPSA->position.vz=pBallPSA->position.vz;

		pPlasterPSA->world.qRotLight.x=pBallPSA->world.qRotLight.x;//-(loop*2048);
		pPlasterPSA->world.qRotLight.y=pBallPSA->world.qRotLight.y;
		pPlasterPSA->world.qRotLight.z=pBallPSA->world.qRotLight.z;//+(loop*1234);
		pPlasterPSA->world.qRotLight.w=pBallPSA->world.qRotLight.w;

		if (loop>0 && loop<6)
		{
			//squat.x=-1874;
			//squat.y=2169;
			//squat.z=2548;				
			//squat.w=-1265;
			PlasterQuat[loop-1].x=-PlasterQuat[loop-1].x;
			temp=PlasterQuat[loop-1].y;
			PlasterQuat[loop-1].y=PlasterQuat[loop-1].z;
			PlasterQuat[loop-1].z=temp;

			QuaternionMultiplyDestNESrc(&squat1,&PlasterQuat[loop-1],&pBallPSA->world.qRotLight);
			pPlasterPSA->world.qRotLight.x=squat1.x;
			pPlasterPSA->world.qRotLight.y=squat1.y;
			pPlasterPSA->world.qRotLight.z=squat1.z;
			pPlasterPSA->world.qRotLight.w=squat1.w;

			PlasterQuat[loop-1].x=-PlasterQuat[loop-1].x;
			temp=PlasterQuat[loop-1].y;
			PlasterQuat[loop-1].y=PlasterQuat[loop-1].z;
			PlasterQuat[loop-1].z=temp;

		}


		//pPlasterPSA->world.rotate.vz=pBallPSA->world.rotate.vx+(loop*1024);
		objectSetAnimation(pPlasterPSA, 0);
		objectDraw(pPlasterPSA);
		BallCtrl.ot_depth = modelctrl.lastdepth;
	}
}


/********************************************************************************/
/********************************************************************************/
/********************************************************************************/
void	doBallBurst(void)
{
	if (BallCtrl.type==BALL_MODE_CRYSTAL)
	{
		ballVel.vy=0;
		ballVel.vx=0;
		ballVel.vz=0;


		if (!BallCtrl.ballSmashed)
		{
			ballPos.vy-=BallBehaviour[BALL_MODE_CRYSTAL].radius;
			platformGenerateShrapnel(&ballPos, 10, 1, pBallPSA, pCryFrag);

			sfxPlay3D(globalFX,SFX_BALLBOUNCE_CRYSTAL_SMASH,&ballPos);
		}

		BallCtrl.ballSmashed=TRUE;
	}
	else
	{
		if(GloveCtrl.dieCount==45)
			sfxPlay3D(globalFX,SFX_BALL_BURST,&ballPos);

		if (!(GloveCtrl.dieCount%10))
		{
			BALL_PRINTF("changing vel\n");
			
			ballVel.vx=(RANDOM256()-128)*256;
			ballVel.vy=(RANDOM256()-128)*256;
			ballVel.vz=(RANDOM256()-128)*256;

			//ballVel.vx=randomInt(24576)-12288;
			//ballVel.vy=randomInt(24576)-12288;
			//ballVel.vz=randomInt(24576)-12288;
		}
	}
	//ballVel.vy-=BallBehaviour[BallCtrl.type].gravity;
	if (level==PREHISTORICBONUS) ballVel.vz-=10*4096;


	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;
}

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


void	BallApplySquash(void)
{
VECTOR	squash,expand;
LONG	mag,mag1;

	if (BallBehaviour[BallCtrl.type].squash==0) return;

	mag=BallBehaviour[BallCtrl.type].squash;

	//rotation.vx=ballColl.preVel.vx-ballColl.pVel->vx;
	//rotation.vy=ballColl.preVel.vy-ballColl.pVel->vy;
	//rotation.vz=ballColl.preVel.vz-ballColl.pVel->vz;
	//MakeUnitS(&rotation);

	squash.vx=abs(ballColl.preVel.vx-ballColl.pVel->vx);
	squash.vy=abs(ballColl.preVel.vy-ballColl.pVel->vy);
	squash.vz=abs(ballColl.preVel.vz-ballColl.pVel->vz); // work out axis to squash along

	mag1=Magnitude(&squash);
	mag1/=40;
	if (mag1>mag) mag1=mag;
	MakeUnit(&squash);
	//SCALEVECTOR(&squash,mag1);

	//RotMatrix(&rotation,&BallCtrl.rotation);
	//squash.vy=4096;
	//squash.vx=0;
	//squash.vz=0;

	SCALEVECTOR(&squash,mag1);
	expand.vx=mag1-squash.vx;	// work out axis to expand along
	expand.vy=mag1-squash.vy;	
	expand.vz=mag1-squash.vz;	

	if (Magnitude(&squash) < mag/6 ) return;
	if (Magnitude(&squash) < Magnitude(&BallCtrl.squash))return;
	//else if (BallCtrl.flag==FALSE) BallCtrl.flag=TRUE;

	BallCtrl.squashUpdate.vx=BallCtrl.squash.vx=squash.vx;
	BallCtrl.squashUpdate.vy=BallCtrl.squash.vy=squash.vy;	
	BallCtrl.squashUpdate.vz=BallCtrl.squash.vz=squash.vz;

	BallCtrl.expandUpdate.vx=BallCtrl.expand.vx=expand.vx;
	BallCtrl.expandUpdate.vy=BallCtrl.expand.vy=expand.vy;
	BallCtrl.expandUpdate.vz=BallCtrl.expand.vz=expand.vz;

	BallCtrl.expandDelta.vx=expand.vx/BALLCHANGERATE;
	BallCtrl.expandDelta.vy=expand.vy/BALLCHANGERATE;
	BallCtrl.expandDelta.vz=expand.vz/BALLCHANGERATE;

	BallCtrl.squashDelta.vx=squash.vx/BALLCHANGERATE;
	BallCtrl.squashDelta.vy=squash.vy/BALLCHANGERATE;
	BallCtrl.squashDelta.vz=squash.vz/BALLCHANGERATE;

/*
	squash.vx=abs(squash.vx*ballVel.vx/32768);
	if (squash.vx>BallBehaviour[BallCtrl.type].squash) squash.vx=BallBehaviour[BallCtrl.type].squash;

	squash.vy=abs(squash.vy*ballVel.vy/32768);
	if (squash.vy>BallBehaviour[BallCtrl.type].squash) squash.vy=BallBehaviour[BallCtrl.type].squash;

	squash.vz=abs(squash.vz*ballVel.vz/32768);
	if (squash.vz>BallBehaviour[BallCtrl.type].squash) squash.vz=BallBehaviour[BallCtrl.type].squash;
*/
/*
	if (squash.vx>=BallCtrl.squashX )
	{
		BallCtrl.squashXupdate=BallCtrl.squashX=squash.vx;
		BallCtrl.squashXdelta=BallCtrl.squashXupdate/5;
		BallCtrl.squashXdir=1;
	}
	if (squash.vy>=BallCtrl.squashY )
	{
		BallCtrl.squashYupdate=BallCtrl.squashY=squash.vy;
		BallCtrl.squashYdelta=BallCtrl.squashYupdate/5;
		BallCtrl.squashYdir=1;
	}
	if (squash.vz>=BallCtrl.squashZ )
	{
		BallCtrl.squashZupdate=BallCtrl.squashZ=squash.vz;
		BallCtrl.squashZdelta=BallCtrl.squashZupdate/5;
		BallCtrl.squashZdir=1;
	}
*/
}
/********************************************************************************/
/********************************************************************************/
/********************************************************************************/


void	BallUpdateSquash(void)
{
	if (BallBehaviour[BallCtrl.type].squash==0) return;

	pBallPSA->globalscale.vx=BallBehaviour[BallCtrl.type].radius/152;
	pBallPSA->globalscale.vy=BallBehaviour[BallCtrl.type].radius/152;
	pBallPSA->globalscale.vz=BallBehaviour[BallCtrl.type].radius/152;

	if (Magnitude(&BallCtrl.squash)<DAMPSTOP)
	{
		ZEROVECTOR(&BallCtrl.squash);
		return;
	}

	pBallPSA->globalscale.vx=(pBallPSA->globalscale.vx*( 4096-BallCtrl.squashUpdate.vx+BallCtrl.expandUpdate.vx ))/4096;
	pBallPSA->globalscale.vy=(pBallPSA->globalscale.vy*( 4096-BallCtrl.squashUpdate.vy+BallCtrl.expandUpdate.vy ))/4096;
	pBallPSA->globalscale.vz=(pBallPSA->globalscale.vz*( 4096-BallCtrl.squashUpdate.vz+BallCtrl.expandUpdate.vz ))/4096;

	BallCtrl.squashUpdate.vx-=BallCtrl.squashDelta.vx;
	BallCtrl.squashUpdate.vy-=BallCtrl.squashDelta.vy;
	BallCtrl.squashUpdate.vz-=BallCtrl.squashDelta.vz;

	BallCtrl.expandUpdate.vx-=BallCtrl.expandDelta.vx;
	BallCtrl.expandUpdate.vy-=BallCtrl.expandDelta.vy;
	BallCtrl.expandUpdate.vz-=BallCtrl.expandDelta.vz;

	if (BallCtrl.squashUpdate.vx<0) {BallCtrl.squashUpdate.vx=0;BallCtrl.squashDelta.vx=-BallCtrl.squashDelta.vx;}
	if (BallCtrl.squashUpdate.vy<0) {BallCtrl.squashUpdate.vy=0;BallCtrl.squashDelta.vy=-BallCtrl.squashDelta.vy;}
	if (BallCtrl.squashUpdate.vz<0) {BallCtrl.squashUpdate.vz=0;BallCtrl.squashDelta.vz=-BallCtrl.squashDelta.vz;}

	if (BallCtrl.squashUpdate.vx>BallCtrl.squash.vx){BallCtrl.squashUpdate.vx=BallCtrl.squash.vx;BallCtrl.squashDelta.vx=-BallCtrl.squashDelta.vx;}
	if (BallCtrl.squashUpdate.vy>BallCtrl.squash.vy){BallCtrl.squashUpdate.vy=BallCtrl.squash.vy;BallCtrl.squashDelta.vy=-BallCtrl.squashDelta.vy;}
	if (BallCtrl.squashUpdate.vz>BallCtrl.squash.vz){BallCtrl.squashUpdate.vz=BallCtrl.squash.vz;BallCtrl.squashDelta.vz=-BallCtrl.squashDelta.vz;}

	if (BallCtrl.expandUpdate.vx<0) {BallCtrl.expandUpdate.vx=0;BallCtrl.expandDelta.vx=-BallCtrl.expandDelta.vx;}
	if (BallCtrl.expandUpdate.vy<0) {BallCtrl.expandUpdate.vy=0;BallCtrl.expandDelta.vy=-BallCtrl.expandDelta.vy;}
	if (BallCtrl.expandUpdate.vz<0) {BallCtrl.expandUpdate.vz=0;BallCtrl.expandDelta.vz=-BallCtrl.expandDelta.vz;}

	if (BallCtrl.expandUpdate.vx>BallCtrl.expand.vx){BallCtrl.expandUpdate.vx=BallCtrl.expand.vx;BallCtrl.expandDelta.vx=-BallCtrl.expandDelta.vx;}
	if (BallCtrl.expandUpdate.vy>BallCtrl.expand.vy){BallCtrl.expandUpdate.vy=BallCtrl.expand.vy;BallCtrl.expandDelta.vy=-BallCtrl.expandDelta.vy;}
	if (BallCtrl.expandUpdate.vz>BallCtrl.expand.vz){BallCtrl.expandUpdate.vz=BallCtrl.expand.vz;BallCtrl.expandDelta.vz=-BallCtrl.expandDelta.vz;}

	SCALEVECTOR(&BallCtrl.squash,BALLDAMPENRATE);
	SCALEVECTOR(&BallCtrl.expand,BALLDAMPENRATE);

/*
	pBallPSA->globalscale.vx=ballRadius/152;
	pBallPSA->globalscale.vy=ballRadius/152;
	pBallPSA->globalscale.vz=ballRadius/152;

	pBallPSA->globalscale.vx=(pBallPSA->globalscale.vx*(4096-BallCtrl.squashXupdate))/4096;
	pBallPSA->globalscale.vy=(pBallPSA->globalscale.vy*(4096-BallCtrl.squashYupdate))/4096;
	pBallPSA->globalscale.vz=(pBallPSA->globalscale.vz*(4096-BallCtrl.squashZupdate))/4096;

	//pBallPSA->world.scalekeys->vect.x=4096-BallCtrl.squashXupdate;
	//pBallPSA->world.scalekeys->vect.y=4096-BallCtrl.squashYupdate;
	//pBallPSA->world.scalekeys->vect.z=4096-BallCtrl.squashZupdate;
	
	if ( BallCtrl.squashXdir==1 )
	{
		BallCtrl.squashXupdate-=BallCtrl.squashXdelta;
		if (BallCtrl.squashXupdate<0)
		{
			BallCtrl.squashXupdate=0;
			BallCtrl.squashXdir=-1;
		}
	}
	if ( BallCtrl.squashYdir==1 )
	{
		BallCtrl.squashYupdate-=BallCtrl.squashYdelta;
		if (BallCtrl.squashYupdate<0)
		{
			BallCtrl.squashYupdate=0;
			BallCtrl.squashYdir=-1;
		}
	}
	if ( BallCtrl.squashZdir==1 )
	{
		BallCtrl.squashZupdate-=BallCtrl.squashZdelta;
		if (BallCtrl.squashZupdate<0)
		{
			BallCtrl.squashZupdate=0;
			BallCtrl.squashZdir=-1;
		}
	}

	if ( BallCtrl.squashXdir==-1 )
	{
		BallCtrl.squashXupdate+=BallCtrl.squashXdelta;
		if (BallCtrl.squashXupdate>BallCtrl.squashX)
		{
			BallCtrl.squashXupdate=BallCtrl.squashX;
			BallCtrl.squashXdir=1;
		}
	}
	if ( BallCtrl.squashYdir==-1 )
	{
		BallCtrl.squashYupdate+=BallCtrl.squashYdelta;
		if (BallCtrl.squashYupdate>BallCtrl.squashY)
		{
			BallCtrl.squashYupdate=BallCtrl.squashY;
			BallCtrl.squashYdir=1;
		}
	}
	if ( BallCtrl.squashZdir==-1 )
	{
		BallCtrl.squashZupdate+=BallCtrl.squashZdelta;
		if (BallCtrl.squashZupdate>BallCtrl.squashZ)
		{
			BallCtrl.squashZupdate=BallCtrl.squashZ;
			BallCtrl.squashZdir=1;
		}
	}
	BallCtrl.squashX=BallCtrl.squashX-(BallCtrl.squashX/8);
	BallCtrl.squashY=BallCtrl.squashY-(BallCtrl.squashY/8);
	BallCtrl.squashZ=BallCtrl.squashZ-(BallCtrl.squashZ/8);



	//BallCtrl.squashXupdate=BallCtrl.squashXupdate/2;
	//BallCtrl.squashYupdate=BallCtrl.squashYupdate/2;
	//BallCtrl.squashZupdate=BallCtrl.squashZupdate/2;
*/
	//pBallPSA->globalscale.vx+=BallCtrl.snowAddition;
	//pBallPSA->globalscale.vx+=BallCtrl.snowAddition;
	//pBallPSA->globalscale.vx+=BallCtrl.snowAddition;
}

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

void	UpdateBallPos(void)
{
VECTOR	tempVel;
VECTOR	tempVel1;
BEHAVIOUR_PHYSICS	*Physics;
int		steps=1;
int		loop,tempy;
int		count=0,mag;
UBYTE	flag=FALSE;


	//if (gameCtrl.gameActive==FALSE) return;
	if (GloveCtrl.cameoDisableDamage)
	{
		ballVel.vx=ballVel.vz=0;
	}

	if (BallCtrl.onConveyer==XPOS)
	{
		if (ballColl.normal.vx)
		{
			ballPos.vx+=BallCtrl.conveyerTimer*BallCtrl.conveyerNormal.vy;
			ballPos.vy-=BallCtrl.conveyerTimer*BallCtrl.conveyerNormal.vx;

			ballOldPos.vx+=BallCtrl.conveyerTimer*BallCtrl.conveyerNormal.vy;
			ballOldPos.vy-=BallCtrl.conveyerTimer*BallCtrl.conveyerNormal.vx;
		}
		else
		{
			ballPos.vx+=(BallCtrl.conveyerTimer*4096);
			ballOldPos.vx+=(BallCtrl.conveyerTimer*4096);
		}
	}
	if (BallCtrl.onConveyer==XNEG)
	{
		if (ballColl.normal.vx)
		{
			ballPos.vx-=BallCtrl.conveyerTimer*BallCtrl.conveyerNormal.vy;
			ballPos.vy-=BallCtrl.conveyerTimer*BallCtrl.conveyerNormal.vx;

			ballOldPos.vx-=BallCtrl.conveyerTimer*BallCtrl.conveyerNormal.vy;
			ballOldPos.vy-=BallCtrl.conveyerTimer*BallCtrl.conveyerNormal.vx;
		}
		else
		{
			ballPos.vx-=(BallCtrl.conveyerTimer*4096);
			ballOldPos.vx-=(BallCtrl.conveyerTimer*4096);
		}
	}

	if (BallCtrl.onConveyer==ZPOS)
	{
		if (BallCtrl.conveyerNormal.vz)
		{
			ballPos.vz+=BallCtrl.conveyerTimer*BallCtrl.conveyerNormal.vy;
			ballPos.vy-=BallCtrl.conveyerTimer*BallCtrl.conveyerNormal.vz;

			ballOldPos.vz+=BallCtrl.conveyerTimer*BallCtrl.conveyerNormal.vy;
			ballOldPos.vy-=BallCtrl.conveyerTimer*BallCtrl.conveyerNormal.vz;
		}
		else
		{
			ballPos.vz+=(BallCtrl.conveyerTimer*4096);
			ballOldPos.vz+=(BallCtrl.conveyerTimer*4096);
		}
	}
		
	if (BallCtrl.onConveyer==ZNEG)
	{
		if (BallCtrl.conveyerNormal.vz)
		{
			ballPos.vz-=BallCtrl.conveyerTimer*BallCtrl.conveyerNormal.vy;
			ballPos.vy-=BallCtrl.conveyerTimer*BallCtrl.conveyerNormal.vz;

			ballOldPos.vz-=BallCtrl.conveyerTimer*BallCtrl.conveyerNormal.vy;
			ballOldPos.vy-=BallCtrl.conveyerTimer*BallCtrl.conveyerNormal.vz;
		}
		else
		{
			ballPos.vz-=(BallCtrl.conveyerTimer*4096);
			ballOldPos.vz-=(BallCtrl.conveyerTimer*4096);
		}
	}

	// Special case for boomerang returning ball
	// Call sfx from here
	if (BallCtrl.boomerangOn)
	{
		//printf ("ball in hand %d\n",GloveCtrl.ballWithHand);
		
		if (GloveCtrl.action==HAND_JOINED || GloveCtrl.action==HAND_BALLWALK || GloveCtrl.action==HAND_BOUNCE || GloveCtrl.action==HAND_THROWAIM || GloveCtrl.action==HAND_PREWHACK || GloveCtrl.action==HAND_SLAM)
		{
			BallCtrl.boomerangTime=-20;
			//BallCtrl.boomerangOn=FALSE;
			//handpower_timer = 0;
			//handpower_duration = 0;
			//handpower_type = 0;

		}
		
		/*if (BallCtrl.boomerangActiveTime) BallCtrl.boomerangActiveTime--;
		else
		{
			BallCtrl.boomerangActiveTime=0;
			BallCtrl.boomerangOn=FALSE;
			BallCtrl.boomerangTime=0;
		}
		*/
		if (BallCtrl.boomerangTime>=20)
		{
			//BallBehaviour[BallCtrl.type].gravity;
			tempVel.vx=glovePos.vx-ballPos.vx;
			if (BallBehaviour[BallCtrl.type].radius<GloveBehaviour.radius)
			{
				tempVel.vy=- ( (glovePos.vy-ballPos.vy)-(BallBehaviour[BallCtrl.type].radius-GloveBehaviour.radius) );
			}
			else tempVel.vy=-(glovePos.vy-ballPos.vy);
			tempVel.vz=glovePos.vz-ballPos.vz;

			loop=Magnitude(&tempVel);
			MakeUnit(&tempVel);		// give vector pointing to glove
			loop=(loop+(4*40960))/100000;	// Note scalevectornormal does not scale down by 4096 internally so should be faster

			//SCALEVECTORNORMAL( &tempVel, loop );
			tempVel.vx=tempVel.vx*loop;
			tempVel.vy=tempVel.vy*loop;
			tempVel.vz=tempVel.vz*loop;

			//tempVel.vy+=BallBehaviour[BallCtrl.type].gravity;
			COPYVECTOR(&ballVel,&tempVel);
		}
		else BallCtrl.boomerangTime++;
	}

	if (GloveCtrl.action==HAND_BOUNCE)
	{
		if ( ( (glovePos.vy >= (ballPos.vy- (BallBehaviour[BallCtrl.type].radius-GloveBehaviour.radius/3 )  ) )) )
		{
			glovePos.vy=ballPos.vy-(((BallBehaviour[BallCtrl.type].radius-GloveBehaviour.radius/3 )) );
		}

		if (!BallCtrl.bounceHoldFlag && !BallCtrl.ballOnCeiling)
		{
			if (ballVel.vy<=(8*4096) && ballVel.vy>0)
			{
				//printf ("Hold\n");
				BallCtrl.bounceHoldFlag=TRUE;
				BallCtrl.bounceHoldTime=16;
			}
		}
		else
		{
			if (BallCtrl.bounceHoldTime)
			{
				ballVel.vy=(BallCtrl.bounceHoldTime*2048);
				BallCtrl.bounceHoldTime--;
			}
		}
	}

	if (GloveCtrl.action==HAND_WHACK) BallCtrl.onIce=FALSE;
	//if (!BallCtrl.ballOnGround) BallCtrl.onIce=FALSE;
	if (BallCtrl.onIce)
	{
		if (BallCtrl.onIceFlag==FALSE)	// first time?
		{
			BallCtrl.iceData.vx=ballVel.vx;
			BallCtrl.iceData.vz=ballVel.vz;
			BallCtrl.iceRollData.vx=ballVel.vx;
			BallCtrl.iceRollData.vz=ballVel.vz;

			BallCtrl.onIceFlag=TRUE;

			BallCtrl.iceRollData.vx=ballColl.pPos->vx-ballOldPos.vx;
			BallCtrl.iceRollData.vz=ballColl.pPos->vz-ballOldPos.vz;
		}
		BallCtrl.iceData.vx-=(BallCtrl.slideNormal.vx*1);
		BallCtrl.iceData.vz-=(BallCtrl.slideNormal.vz*1);

		BallCtrl.iceData.vx+=(ballVel.vx-BallCtrl.iceData.vx)/5;
		BallCtrl.iceData.vz+=(ballVel.vz-BallCtrl.iceData.vz)/5;

		ballVel.vx=BallCtrl.iceData.vx;
		ballVel.vz=BallCtrl.iceData.vz;

		BallCtrl.iceRollData.vx+=(ballVel.vx-BallCtrl.iceRollData.vx)/8;
		BallCtrl.iceRollData.vz+=(ballVel.vz-BallCtrl.iceRollData.vz)/8;

		BallCtrl.iceRollDataVel.vx=BallCtrl.iceRollData.vx;
		BallCtrl.iceRollDataVel.vz=BallCtrl.iceRollData.vz;
		BallCtrl.onIce++;
	}
	else if (BallCtrl.onIceFlag) BallCtrl.onIceFlag=FALSE;
	if (BallCtrl.onIce==7) BallCtrl.onIce=FALSE;

	if (BallCtrl.snowAddition) BallChange.changeOn=SNOWCHANGE;

	if (BallCtrl.onSnow && BallCtrl.type!=BALL_MODE_CRYSTAL)
	{
		if (!BallCtrl.snowTexChange && BallCtrl.snowAddition)
		{
			//printf ("changing\n");
			BallChange.changeOn=SNOWCHANGE;
			BallCtrl.preSnowType=BallCtrl.type;
			BallCtrl.type=BALL_MODE_SNOW;

			BallChange.fromBall=BallCtrl.preSnowType;
			BallChange.toBall=BallCtrl.type;

			BallBehaviour[BallCtrl.type].radius=BallBehaviour[BallCtrl.preSnowType].radius;
			BallBehaviour[BallCtrl.type].mass=BallBehaviour[BallCtrl.preSnowType].mass;
			BallBehaviour[BallCtrl.type].drag=BallBehaviour[BallCtrl.preSnowType].drag;
			BallBehaviour[BallCtrl.type].bounce=BallBehaviour[BallCtrl.preSnowType].bounce;
			BallBehaviour[BallCtrl.type].accel=BallBehaviour[BallCtrl.preSnowType].accel;

			ballColl.physicsModel=BallCtrl.type;
			ballColl.radius=BallBehaviour[BallCtrl.preSnowType].radius;
			ZEROVECTOR(&BallCtrl.squash);
			ZEROVECTOR(&BallCtrl.expand);
			BallCtrl.snowTexChange=TRUE;
		}
		tempy=ballVel.vy;
		ballVel.vy=0;
		loop=Magnitude(&ballVel);
		ballVel.vy=tempy;
		if ( (loop>3*4096) && (BallBehaviour[BallCtrl.type].radius < (20*4096)) )
		{
			BallBehaviour[BallCtrl.type].accel=(BallBehaviour[BallCtrl.preSnowType].accel-BallCtrl.snowAddition/50);
			
			BallCtrl.snowAddition+=512;
			BallBehaviour[BallCtrl.type].radius+=512;
		}
	}
	BallCtrl.onSnow=FALSE;

	if(!BallCtrl.enabled)
		return;


	BallCtrl.justHitFlag=FALSE;
	TIMER_START(TIMER_COLLISION);

	ballColl.preVel.vx=ballVel.vx;
	ballColl.preVel.vy=ballVel.vy;
	ballColl.preVel.vz=ballVel.vz;
	if (BallCtrl.ballStopMove!=TRUE && GloveCtrl.action!=HAND_THROWAIM)
	{
		ballVel.vy-=gravity;
		COPYVECTOR(&tempVel, &ballVel);
		while ( Magnitude(&ballVel) > (BallBehaviour[BallCtrl.type].radius/2) )
		{
			ballVel.vx=ballVel.vx/2;
			ballVel.vy=ballVel.vy/2;
			ballVel.vz=ballVel.vz/2;
			steps=steps+steps;
			count++;
		}

		if (steps>1)
		{
			HITPLAT temp;	// slightly messy, but the platform & puzzle stuff need to know about the 1st platform hit
			int ctr;
			ctr = 0;

			for (loop=0;loop<steps;loop++)
			{
				ADDVECTOR(&ballPos, &ballPos, &ballVel);
				ballPos.vy-=(ballVel.vy*2);
				//ballPos.vy-=(ballVel.vy);

				ballVel.vx=-ballVel.vx;
				ballVel.vy=-ballVel.vy;
				ballVel.vz=-ballVel.vz;

				if (BallCtrl.cancerFlag==SET)
				{
					CancerPos[0].vx=ballPos.vx+(BallCtrl.cancerPos[0].vx*4096);
					CancerPos[0].vy=ballPos.vy+(BallCtrl.cancerPos[0].vy*4096);
					CancerPos[0].vz=ballPos.vz+(BallCtrl.cancerPos[0].vz*4096);

					CancerVel[0].vx=ballVel.vx;
					CancerVel[0].vy=ballVel.vy;
					CancerVel[0].vz=ballVel.vz;

					CancerPos[1].vx=ballPos.vx+(BallCtrl.cancerPos[1].vx*4096);
					CancerPos[1].vy=ballPos.vy+(BallCtrl.cancerPos[1].vy*4096);
					CancerPos[1].vz=ballPos.vz+(BallCtrl.cancerPos[1].vz*4096);

					CancerVel[1].vx=ballVel.vx;
					CancerVel[1].vy=ballVel.vy;
					CancerVel[1].vz=ballVel.vz;
					if ( collboxCheckSphere(&CancerColl[0]) && gameCtrl.gameActive!=FALSE )
					{
						mag=(Magnitude(&ballVel))*256;
						SCALEVECTOR(&BallCtrl.cancerPos[0],mag);
						ballVel.vx+=BallCtrl.cancerPos[0].vx;
						ballVel.vy+=BallCtrl.cancerPos[0].vy;
						ballVel.vz+=BallCtrl.cancerPos[0].vz;

					}
					if ( collboxCheckSphere(&CancerColl[1]) && gameCtrl.gameActive!=FALSE )
					{
						mag=(Magnitude(&ballVel))*256;
						SCALEVECTOR(&BallCtrl.cancerPos[1],mag);
						ballVel.vx+=BallCtrl.cancerPos[1].vx;
						ballVel.vy+=BallCtrl.cancerPos[1].vy;
						ballVel.vz+=BallCtrl.cancerPos[1].vz;
					}
					BallCtrl.cancerActiveTime--;
					if (!BallCtrl.cancerActiveTime) BallCtrl.cancerFlag=FALSE;
					//printf ("cancer time %d\n",BallCtrl.cancerActiveTime);
				}
	

				if ( collboxCheckSphere(&ballColl) )
				{
					/*
					if (level==CARNIVALBOSS)
					{
						if (ballColl.nHitPlats && !BodgeCtrl.hitPlat)
						{
							BodgeCtrl.carnivalPlat=ballColl.hitPlats[0].pPlatform;
							BodgeCtrl.hitPlat=TRUE;
						}
						else if (!ballColl.nHitPlats && BodgeCtrl.hitPlat)
						{
							ballColl.nHitPlats=1;
							ballColl.hitPlats[0].pPlatform=BodgeCtrl.carnivalPlat;
						}
					}
					*/
					if(!ctr && ballColl.nHitPlats>0)
					{
						ctr = 1;
						temp = ballColl.hitPlats[0];
					}

					//if (abs(ballVel.vy*steps*steps) < (2*4096) )ballVel.vy=0;

					flag=TRUE;
					BallCtrl.ballPosWhenHit.vx=ballPos.vx;
					BallCtrl.ballPosWhenHit.vy=ballPos.vy;
					BallCtrl.ballPosWhenHit.vz=ballPos.vz;
					BallCtrl.justHitFlag=TRUE;
					/*if (BallCtrl.noBounce)
					{
						BallCtrl.justHitFlag=FALSE;
					}
*/				}
				//else BallCtrl.justHitFlag=FALSE;
				ballVel.vx=-ballVel.vx;
				ballVel.vy=-ballVel.vy;
				ballVel.vz=-ballVel.vz;
			}

			if(ctr)
			{
				ballColl.nHitPlats = 1;
				ballColl.hitPlats[0] = temp;
			}
		}
		else
		{
			ADDVECTOR(&ballPos, &ballPos, &ballVel);
			ballPos.vy-=(ballVel.vy*2);

			ballVel.vx=-ballVel.vx;
			ballVel.vy=-ballVel.vy;
			ballVel.vz=-ballVel.vz;


			if (BallCtrl.cancerFlag==SET)
			{
				CancerPos[0].vx=ballPos.vx+(BallCtrl.cancerPos[0].vx*4096);
				CancerPos[0].vy=ballPos.vy+(BallCtrl.cancerPos[0].vy*4096);
				CancerPos[0].vz=ballPos.vz+(BallCtrl.cancerPos[0].vz*4096);

				CancerVel[0].vx=ballVel.vx;
				CancerVel[0].vy=ballVel.vy;
				CancerVel[0].vz=ballVel.vz;

				CancerPos[1].vx=ballPos.vx+(BallCtrl.cancerPos[1].vx*4096);
				CancerPos[1].vy=ballPos.vy+(BallCtrl.cancerPos[1].vy*4096);
				CancerPos[1].vz=ballPos.vz+(BallCtrl.cancerPos[1].vz*4096);

				CancerVel[1].vx=ballVel.vx;
				CancerVel[1].vy=ballVel.vy;
				CancerVel[1].vz=ballVel.vz;
				//if ( collboxCheckSphere(&CancerColl[0]) ) printf ("1 hit\n");
				//if ( collboxCheckSphere(&CancerColl[1]) ) printf ("2 hit\n");
				BallCtrl.cancerActiveTime--;
				if (!BallCtrl.cancerActiveTime) BallCtrl.cancerFlag=FALSE;
				//printf ("cancer time %d\n",BallCtrl.cancerActiveTime);
			}



			flag=collboxCheckSphere(&ballColl);

			if ( flag )
			{
				BallCtrl.ballPosWhenHit.vx=ballPos.vx;
				BallCtrl.ballPosWhenHit.vy=ballPos.vy;
				BallCtrl.ballPosWhenHit.vz=ballPos.vz;
				BallCtrl.justHitFlag=TRUE;
/*				if (BallCtrl.noBounce)
				{
					BallCtrl.justHitFlag=FALSE;
					BallCtrl.noBounce=FALSE;
				}
*/			}
			//else BallCtrl.noBounce=FALSE;

			if ( BallCtrl.cancerFlag==SET && gameCtrl.gameActive!=FALSE )
			{
				if ( collboxCheckSphere(&CancerColl[0]) )
				{
					mag=(Magnitude(&ballVel))*256;
					SCALEVECTOR(&BallCtrl.cancerPos[0],mag);
					ballVel.vx+=BallCtrl.cancerPos[0].vx;
					ballVel.vy+=BallCtrl.cancerPos[0].vy;
					ballVel.vz+=BallCtrl.cancerPos[0].vz;
				}
				if ( collboxCheckSphere(&CancerColl[1]) )
				{
					mag=(Magnitude(&ballVel))*256;
					SCALEVECTOR(&BallCtrl.cancerPos[1],mag);
					ballVel.vx+=BallCtrl.cancerPos[1].vx;
					ballVel.vy+=BallCtrl.cancerPos[1].vy;
					ballVel.vz+=BallCtrl.cancerPos[1].vz;
				}
			}
			ballVel.vx=-ballVel.vx;
			ballVel.vy=-ballVel.vy;
			ballVel.vz=-ballVel.vz;
		}

		//if (level==CARNIVALBOSS)
		//{
/*			loop=getHeightAt(ballPos.vx,ballPos.vy,ballPos.vz);
			if (ballColl.nHitPlats && !BodgeCtrl.hitPlat)
			{
				BodgeCtrl.carnivalPlat=ballColl.hitPlats[0].pPlatform;
				BodgeCtrl.hitPlat=TRUE;
			}
			else if (!ballColl.nHitPlats && BodgeCtrl.hitPlat && (GloveCtrl.action==HAND_SNATCH || ((abs(ballVel.vy)<(2*4096)) && loop<ballColl.radius*2)) )
			{
				//printf ("locking to plat\n");
				ballColl.nHitPlats=1;
				ballColl.hitPlats[0].pPlatform=BodgeCtrl.carnivalPlat;
			}
		//}
*/

/*		if (GloveCtrl.action==HAND_CASTSPELL || GloveCtrl.action==HAND_SNATCH || GloveCtrl.action==HAND_RELEASE)
		{
			if (ballColl.nHitPlats && !BodgeCtrl.hitPlat)
			{
				BodgeCtrl.carnivalPlat=ballColl.hitPlats[0].pPlatform;
				BodgeCtrl.hitPlat=TRUE;
			}
			else if (BodgeCtrl.hitPlat && !ballColl.nHitPlats)
			{
				ballColl.nHitPlats=1;
				ballColl.hitPlats[0].pPlatform=BodgeCtrl.carnivalPlat;
			}
		}
		else
		{
			BodgeCtrl.carnivalPlat=NULL;
			BodgeCtrl.hitPlat=FALSE;
		}
*/		
		if (steps>1)
		{
			for (loop=0;loop<count;loop++)
			{
				ballVel.vx=ballVel.vx*2;
				ballVel.vy=ballVel.vy*2;
				ballVel.vz=ballVel.vz*2;
			}
		}

	}
/*	else
	{
		if (GloveCtrl.action==HAND_CASTSPELL || GloveCtrl.action==HAND_SNATCH || GloveCtrl.action==HAND_RELEASE)
		{
			if (ballColl.nHitPlats && !BodgeCtrl.hitPlat)
			{
				BodgeCtrl.carnivalPlat=ballColl.hitPlats[0].pPlatform;
				BodgeCtrl.hitPlat=TRUE;
			}
			else if (BodgeCtrl.hitPlat && !ballColl.nHitPlats)
			{
				ballColl.nHitPlats=1;
				ballColl.hitPlats[0].pPlatform=BodgeCtrl.carnivalPlat;
			}
		}
		else
		{
			BodgeCtrl.carnivalPlat=NULL;
			BodgeCtrl.hitPlat=FALSE;
		}
	}
*/
// the enemy-splatting capability of the powerwhack is disabled if
// the ball hits the floor,
// or is in the hand,
// or if you change its state to non-bowling
// or (dealt with in enemies.c) if it stuns an enemy
	if(BallCtrl.powerwhack)
	{
		if(BallCtrl.powerwhack < POWERWHACK_START)
		{
			BallCtrl.powerwhack--;	// 1-tick counter so platform-collides can still pick up on stuff
		}
		else
		{
			if(flag
	//			|| GloveCtrl.handOnBall
	//			|| GloveCtrl.ballWithHand
				|| ( (BallCtrl.type != BALL_MODE_BOWLING && !cheat_any_ball_powerwhacks) && BallCtrl.preSnowType==BALL_MODE_BOWLING && !BallCtrl.snowAddition)
				)
			{
				BallCtrl.powerwhack--;
			}
		}
	}
	if(BallCtrl.anywhack)
	{
		if(BallCtrl.anywhack < POWERWHACK_START)
		{
			BallCtrl.anywhack--;	// 1-tick counter so platform-collides can still pick up on stuff
		}
		else
		{
			if(flag)
			{
				BallCtrl.anywhack--;
			}
		}
	}

	if ( flag )
	{
		/*if ( (BallCtrl.type==BALL_MODE_CRYSTAL && abs(ballVel.vy) > CRYSTALBALLSMASH) && GloveCtrl.action!=HAND_CATCH)
		{
			if (!GloveCtrl.hurtFlagBall && !GloveCtrl.deathTypeBall)
			{
				GloveCtrl.deathTypeBall=DEADFROMBALLBURST;
				GloveCtrl.hurtFlagBall=TRUE;
				ballPos.vx=BallCtrl.ballPosWhenHit.vx;
				ballPos.vy=BallCtrl.ballPosWhenHit.vy;
				ballPos.vz=BallCtrl.ballPosWhenHit.vz;
			}
		}*/
		if (BallCtrl.type==BALL_MODE_CRYSTAL && GloveCtrl.action!=HAND_CATCH)
		{
			tempVel1.vx=ballColl.preVel.vx-ballVel.vx;
			tempVel1.vy=ballColl.preVel.vy-ballVel.vy;
			tempVel1.vz=ballColl.preVel.vz-ballVel.vz;
			mag=Magnitude(&tempVel1);
			//DB ("crystal smash test %d \n",mag);

			if ( (mag>CRYSTALBALLSMASH) && !GloveCtrl.hurtFlagBall && !GloveCtrl.deathTypeBall )
			{
				GloveCtrl.deathTypeBall=DEADFROMBALLBURST;
				GloveCtrl.hurtFlagBall=TRUE;
				ballPos.vx=BallCtrl.ballPosWhenHit.vx;
				ballPos.vy=BallCtrl.ballPosWhenHit.vy;
				ballPos.vz=BallCtrl.ballPosWhenHit.vz;
			}
		}


		BallCtrl.ballOnCeiling=FALSE;
		if((tempVel.vy^ballVel.vy)&0x80000000)
		{
			//printf ("ball on ground\n");
			BallCtrl.ballOnGround=TRUE;
			//printf ("tempVel %d ballvel %d \n",tempVel.vy,ballVel.vy);
			if (tempVel.vy>0)
			{
				BallCtrl.ballOnCeiling=TRUE;
				BallCtrl.bounceHoldFlag=FALSE;
				BallCtrl.bounceHoldTime=0;
			}
		}

		if (BallCtrl.noBounce)
		{
			BallCtrl.ballOnGround=FALSE;
			BallCtrl.noBounce=FALSE;
			//printf ("not on ground\n");
		}
		
		if (GloveCtrl.action!=HAND_CATCH)
		{
			if (!BallCtrl.onIce)
			{
				ActorStartRoll(pBallPSA, (ballColl.pPos->vx-ballOldPos.vx) , (ballColl.pPos->vz-ballOldPos.vz) );
				BallApplySquash();
			}
			else
			{
				//ActorStartRoll(pBallPSA, (ballColl.pPos->vx-ballOldPos.vx)/2 , (ballColl.pPos->vz-ballOldPos.vz)/2 );
				ActorStartRoll(pBallPSA, BallCtrl.iceRollDataVel.vx/2 , BallCtrl.iceRollDataVel.vz/2 );
				BallApplySquash();
			}
		}
		else
		{
			ActorStartRoll(pBallPSA, 0 , 0 );
		}
	}
	else BallCtrl.ballOnGround=FALSE;

	tempVel.vx=ballPos.vx/4096;
	tempVel.vy=ballPos.vy/4096;
	tempVel.vz=ballPos.vz/4096;

	Physics=&ballColl.physics[ballColl.physicsModel];

//	BallCtrl.inWaterFlag=loadlndGetWaterInfo(&tempVel, Physics->radius/4096, &BallCtrl.waterHeight);
	{
		int flags;
		if(ballVel.vx > 4096 || ballVel.vx <-4096 || ballVel.vz >4096 || ballVel.vz <-4096)
			flags = BallCtrl.inWaterFlag + SPLASHY_MOVING;
		else
			flags = BallCtrl.inWaterFlag;

		if(BallCtrl.onWater)
			flags |= SPLASHY_WATERY;

		if (!BallCtrl.ballSmashed)
			BallCtrl.inWaterFlag = waterDoSplashiness(&tempVel,Physics->radius/4096, flags, &BallCtrl.waterHeight);
		if(used_water)
		{
//			printf("wvel = %d %d\n",used_water->vx,used_water->vz);
// (yes, the n64 doesn't impose a maxvel either, so you accelerate beyond the water speed)
			ballVel.vx += used_water->vx;
			ballVel.vz += used_water->vz;
		}
	}
	BallCtrl.waterHeight*=4096;//962560

	if (BallCtrl.inWaterFlag==INWATER || BallCtrl.inWaterFlag==BELOWWATER)
	{
		LONG	waterDepth;
		waterDepth=getHeightAt(ballPos.vx,BallCtrl.waterHeight,ballPos.vz);
		//printf ("water depth %d \n",waterDepth);
		if (waterDepth < (23*4096) ) BallCtrl.shallowWater=TRUE;
		else BallCtrl.shallowWater=FALSE;
	}


/*	{
		//VECTOR	waterDepth;

		//waterDepth.vx=ballPos.vx;
		//waterDepth.vz=ballPos.vz;
		//waterDepth.vy=BallCtrl.waterHeight;

		printf ("water depth %d \n",getHeightAt(ballPos.vx,BallCtrl.waterHeight,ballPos.vz) );

		if ( (BallCtrl.inWaterFlag==INWATER || BallCtrl.inWaterFlag==BELOWWATER) && BallCtrl.waterHeight<(250*4096) )
		{
			BallCtrl.shallowWater=TRUE;
		}
		else
			BallCtrl.shallowWater=FALSE;
	}
*/


	if (GloveCtrl.health==0 || BallCtrl.health==0 || BallCtrl.ballSmashed) BallCtrl.inWaterFlag=NOWHERENEARWATER;

	switch(BallCtrl.inWaterFlag)
	{
		case INWATER:

			if ((BallCtrl.type==BALL_MODE_BOWLING || BallCtrl.type==BALL_MODE_BEARING) /*|| (BallChange.changeOn==SPELLCHANGE && BallChange.fromBall==BALL_MODE_NORMAL )*/ ) break;

			tempVel.vy=(rsin(BallCtrl.ballBob) *2);
			
			if ( (ballPos.vy+tempVel.vy) > BallCtrl.waterHeight)
			{
				long	dist;
				dist=(ballPos.vy+tempVel.vy) - BallCtrl.waterHeight;
				if (dist>BallBehaviour[BallCtrl.type].radius)
					ballVel.vy+=gravity+(2*4096);
				else
					ballVel.vy+=(gravity+(2*4096)*dist)/BallBehaviour[BallCtrl.type].radius;
			}


			BallCtrl.ballBob = (BallCtrl.ballBob+128) & 4095;


			if (GloveCtrl.ballWithHand && GloveCtrl.action!=HAND_BALLWALK && GloveCtrl.action!=HAND_RELEASE && !BallCtrl.shallowWater && GloveCtrl.action!=HAND_CASTSPELL)
			{
				if (GloveCtrl.action==HAND_JOINED)
				{
					pGlovePSA->world.rotate.vz=0;
					AddToQueue(&Glover,HANDANIM_IDLE,YES,NO,2048);
					GloveCtrl.lastAction=GloveCtrl.action;
					GloveCtrl.action=HAND_BALLWALK;
					pGlovePSA->world.rotate.vx=0;
					pGlovePSA->world.rotate.vz=0;
					GloveCtrl.ballWithHand=TRUE;

					CamVars.oldTargetmodel=CamVars.targetmodel;
					CamVars.targetChangeTime=0;
					CamVars.targetChangeFlag=TRUE;

					CamVars.targetmodel=pBallPSA;
					GloveCtrl.currentAnim=HANDANIM_IDLE;
					GloveCtrl.handOnBall=TRUE;
				}
				else
				{
					AddToQueue(&Glover,HANDANIM_IDLE,YES,NO,2048);
					GloveCtrl.lastAction=GloveCtrl.action;
					GloveCtrl.action=HAND_BALLWALK;
					GloveCtrl.disableTimer=4;
					GloveCtrl.ballWithHand=TRUE;

					CamVars.oldTargetmodel=CamVars.targetmodel;
					CamVars.targetChangeTime=0;
					CamVars.targetChangeFlag=TRUE;
					CamVars.targetmodel=pBallPSA;
					GloveCtrl.currentAnim=HANDANIM_IDLE;
					GloveCtrl.handOnBall=TRUE;
					GloveCtrl.walkType=NULL;
				}

/*				AddToQueue(&Glover,HANDANIM_IDLE,YES,NO,2048);
				GloveCtrl.lastAction=GloveCtrl.action;
				//GloveCtrl.action=HAND_BALLWALK;
				GloveCtrl.action=HAND_IDLE;
				GloveCtrl.disableTimer=4;
				//GloveCtrl.ballWithHand=TRUE;
				GloveCtrl.ballWithHand=FALSE;

				CamVars.oldTargetmodel=CamVars.targetmodel;
				CamVars.targetChangeTime=0;
				CamVars.targetChangeFlag=TRUE;
				GloveCtrl.onGround=FALSE;
				GloveCtrl.positionHold=FALSE;
				GloveCtrl.hitBall=FALSE;

				//CamVars.targetmodel=pBallPSA;
				CamVars.targetmodel=pGlovePSA;
				GloveCtrl.currentAnim=HANDANIM_IDLE;
				//GloveCtrl.handOnBall=TRUE;
				GloveCtrl.handOnBall=FALSE;
				InputState.aStateHoldTime=FALSE;
				InputState.aStateChange=FALSE;

				InputState.bStateHoldTime=FALSE;
				InputState.bStateChange=FALSE;

				InputState.cStateHoldTime=FALSE;
				InputState.cStateChange=FALSE;

				GloveCtrl.flags=GLOVEMOVE;
				BallCtrl.ballStopMove=FALSE;
				GloveCtrl.ballWithHand=FALSE;
				InputState.throwWhenAble=FALSE;
				GloveCtrl.throwDelay=0;
				tempVel.vx=ballVel.vx;
				tempVel.vz=ballVel.vz;
				tempVel.vy=0;
				GloveCtrl.direction=calc_angle( (-ballVel.vx),(-ballVel.vz) );
				GloveCtrl.speed=Magnitude(&tempVel)/300;
				GloveCtrl.walkType=NULL;
*/
			}
			if (GloveCtrl.action!=HAND_BALLWALK) ActorStartRoll(pBallPSA, (ballColl.pPos->vx-ballOldPos.vx)/3 , (ballColl.pPos->vz-ballOldPos.vz)/3 );
			else ActorStartRoll(pBallPSA, (ballColl.pPos->vx-ballOldPos.vx) , (ballColl.pPos->vz-ballOldPos.vz) );
			break;

		case ABOVEWATER:

			//printf ("above water water height %d\n",waterHeight);
			break;

		case BELOWWATER:

			if (BallCtrl.type==BALL_MODE_BOWLING || BallCtrl.type==BALL_MODE_BEARING ) break;

			tempVel.vy=(rsin(BallCtrl.ballBob) *1);
			
			if ( (ballPos.vy+tempVel.vy) > BallCtrl.waterHeight)
			{
				if ( (ballPos.vy - BallCtrl.waterHeight) > (4096*3) ) ballPos.vy-=4096*3;
				else ballPos.vy = BallCtrl.waterHeight;
				//if (ballVel.vy<0) ballVel.vy=0;
				ballVel.vy+=gravity+(2*4096);

			}

			//ballPos.vy+=tempVel.vy;
			BallCtrl.ballBob= (BallCtrl.ballBob+128) & 4095;

			//printf ("water height b %d get height %d\n",BallCtrl.waterHeight,getHeightAt(ballPos.vx,ballPos.vy,ballPos.vz));
			{
				LONG	waterDepth;
				waterDepth=getHeightAt(ballPos.vx,BallCtrl.waterHeight,ballPos.vz);
				if (waterDepth < (50*4096) ) BallCtrl.shallowWater=TRUE;
				else
				{
					BallCtrl.shallowWater=FALSE;

					if (GloveCtrl.ballWithHand && GloveCtrl.action!=HAND_BALLWALK && GloveCtrl.action!=HAND_RELEASE && GloveCtrl.action!=HAND_CASTSPELL)
					{
						if (GloveCtrl.action==HAND_JOINED)
						{
							pGlovePSA->world.rotate.vz=0;
							AddToQueue(&Glover,HANDANIM_IDLE,YES,NO,2048);
							GloveCtrl.lastAction=GloveCtrl.action;
							GloveCtrl.action=HAND_BALLWALK;
							pGlovePSA->world.rotate.vx=0;
							pGlovePSA->world.rotate.vz=0;
							GloveCtrl.ballWithHand=TRUE;

							CamVars.oldTargetmodel=CamVars.targetmodel;
							CamVars.targetChangeTime=0;
							CamVars.targetChangeFlag=TRUE;

							CamVars.targetmodel=pBallPSA;
							GloveCtrl.currentAnim=HANDANIM_IDLE;
							GloveCtrl.handOnBall=TRUE;
						}
						else
						{
							AddToQueue(&Glover,HANDANIM_IDLE,YES,NO,2048);
							GloveCtrl.lastAction=GloveCtrl.action;
							GloveCtrl.action=HAND_BALLWALK;
							GloveCtrl.disableTimer=4;
							GloveCtrl.ballWithHand=TRUE;

							CamVars.oldTargetmodel=CamVars.targetmodel;
							CamVars.targetChangeTime=0;
							CamVars.targetChangeFlag=TRUE;
							CamVars.targetmodel=pBallPSA;
							GloveCtrl.currentAnim=HANDANIM_IDLE;
							GloveCtrl.handOnBall=TRUE;
							GloveCtrl.walkType=NULL;
						}
					}
				}
			}


/*			if ( (BallCtrl.inWaterFlag==INWATER || BallCtrl.inWaterFlag==BELOWWATER) && BallCtrl.waterHeight<(250*4096) )
			{
				BallCtrl.shallowWater=TRUE;
			}
			else
			{
				BallCtrl.shallowWater=FALSE;
				AddToQueue(&Glover,HANDANIM_IDLE,YES,NO,2048);
				GloveCtrl.lastAction=GloveCtrl.action;
				GloveCtrl.action=HAND_BALLWALK;
				GloveCtrl.disableTimer=4;
				GloveCtrl.ballWithHand=TRUE;

				CamVars.oldTargetmodel=CamVars.targetmodel;
				CamVars.targetChangeTime=0;
				CamVars.targetChangeFlag=TRUE;

				CamVars.targetmodel=pBallPSA;
				GloveCtrl.currentAnim=HANDANIM_IDLE;
				GloveCtrl.handOnBall=TRUE;
			}
*/


/*			if ( getHeightAt(ballPos.vx,ballPos.vy,ballPos.vz)<25*4096)
			{
				BallCtrl.shallowWater=TRUE;
				break;
			}
			else BallCtrl.shallowWater=FALSE;
*/
/*			if (GloveCtrl.ballWithHand && GloveCtrl.action!=HAND_BALLWALK && GloveCtrl.action!=HAND_RELEASE && GloveCtrl.action!=HAND_CASTSPELL)
			{
				//GloveCtrl.action=HAND_BALLWALK;
				//gloveVel.vy=ballVel.vy;
				AddToQueue(&Glover,HANDANIM_IDLE,YES,NO,2048);
				GloveCtrl.lastAction=GloveCtrl.action;
				GloveCtrl.action=HAND_BALLWALK;
				GloveCtrl.disableTimer=4;
				GloveCtrl.ballWithHand=TRUE;

				CamVars.oldTargetmodel=CamVars.targetmodel;
				CamVars.targetChangeTime=0;
				CamVars.targetChangeFlag=TRUE;

				CamVars.targetmodel=pBallPSA;
				GloveCtrl.currentAnim=HANDANIM_IDLE;
				GloveCtrl.handOnBall=TRUE;
				//ActorStartRoll(pBallPSA, (ballColl.pPos->vx-ballOldPos.vx) , (ballColl.pPos->vz-ballOldPos.vz) );
			}
*/			ActorStartRoll(pBallPSA, (ballColl.pPos->vx-ballOldPos.vx) , (ballColl.pPos->vz-ballOldPos.vz) );

			break;

		case NOWHERENEARWATER:
			//printf ("no water \n");
			break;
	}


	if (BallCtrl.conveyerTimer) BallCtrl.conveyerTimer--;
	if (!BallCtrl.conveyerTimer) BallCtrl.onConveyer=FALSE;

	if (BallCtrl.justHitFlag && BallCtrl.snowTexChange)
	//if (BallCtrl.ballOnGround && BallCtrl.snowTexChange)
	{
		if (abs(ballVel.vy)>WHACKSNOWSPEED && BallCtrl.lastHit>3)
		{
			//printf ("lose snow\n");
			BallBehaviour[BallCtrl.type].radius-=3*4096;
			BallCtrl.snowAddition-=3*4096;

			ballPos.vy-=BallBehaviour[BallCtrl.type].radius;
			platformGenerateShrapnel(&ballPos, 6, 1, pBallPSA, pSnowFrag);
			ballPos.vy+=BallBehaviour[BallCtrl.type].radius;
			if ( (BallBehaviour[BallCtrl.type].radius<BallBehaviour[BallCtrl.preSnowType].radius) || BallCtrl.snowAddition<=0)
			{
				removeSnow();
/*				BallCtrl.snowAddition=0;
				modelctrl.semitrans = 0;

				BallCtrl.snowAddition=0;
				BallCtrl.snowTexChange=0;
				BallCtrl.onSnow=0;

				BallChange.dimAmount.vx=4096;
				BallChange.dimAmount.vy=4096;
				BallChange.dimAmount.vz=4096;

				BallChange.dimAmbient.vx=2032;
				BallChange.dimAmbient.vy=2032;
				BallChange.dimAmbient.vz=2032;
				BallChange.timer=0;


				BallBehaviour[BallCtrl.type].radius=BallBehaviour[BallCtrl.preSnowType].radius;
				BallCtrl.type=BallCtrl.preSnowType;
				ChangeBall(&pBallPSA->world,ballTex[BallCtrl.type]);
				BallCtrl.snowTexChange=FALSE;
				BallCtrl.snowAddition=0;
				pBallPSA->globalscale.vx=BallBehaviour[BallCtrl.type].radius/152;
				pBallPSA->globalscale.vy=BallBehaviour[BallCtrl.type].radius/152;
				pBallPSA->globalscale.vz=BallBehaviour[BallCtrl.type].radius/152;
				
				BallBehaviour[BallCtrl.type].accel=(BallBehaviour[BallCtrl.preSnowType].accel-BallCtrl.snowAddition/50);
				
				BallBehaviour[BallCtrl.preSnowType].mass=BallBehaviour[BallCtrl.type].mass;
				BallBehaviour[BallCtrl.preSnowType].drag=BallBehaviour[BallCtrl.type].drag;
				BallBehaviour[BallCtrl.preSnowType].bounce=BallBehaviour[BallCtrl.type].bounce;
*/			}
			BallCtrl.lastHit=1;
		}
	}
	if (BallCtrl.lastHit<10) BallCtrl.lastHit++;

	if (GloveCtrl.action==HAND_JUMP && GloveCtrl.hitBall==TRUE && BallCtrl.type==BALL_MODE_SNOW)
	{
/*		BallBehaviour[BallCtrl.type].radius=BallBehaviour[BallCtrl.preSnowType].radius;
		GloveCtrl.hitBall=FALSE;
		BallCtrl.type=BallCtrl.preSnowType;
		ChangeBall(&pBallPSA->world,ballTex[BallCtrl.type]);
		BallCtrl.snowTexChange=FALSE;
		BallCtrl.snowAddition=0;
		pBallPSA->globalscale.vx=BallBehaviour[BallCtrl.type].radius/152;
		pBallPSA->globalscale.vy=BallBehaviour[BallCtrl.type].radius/152;
		pBallPSA->globalscale.vz=BallBehaviour[BallCtrl.type].radius/152;
		BallBehaviour[BallCtrl.preSnowType].mass=BallBehaviour[BallCtrl.type].mass;
		BallBehaviour[BallCtrl.preSnowType].drag=BallBehaviour[BallCtrl.type].drag;
		BallBehaviour[BallCtrl.preSnowType].bounce=BallBehaviour[BallCtrl.type].bounce;
		BallBehaviour[BallCtrl.preSnowType].accel=BallBehaviour[BallCtrl.type].accel;
*/
		removeSnow();
	}

	if ( GloveCtrl.action==HAND_CATCH )
	{
		if (BallCtrl.justHitFlag==TRUE)
		{
			//tempy=ballVel.vy;
			//ballVel.vy=-1;
			if ( CatchBallAllowed() )
			{
				ballPos.vx=BallCtrl.ballPosWhenHit.vx;
				ballPos.vy=glovePos.vy-BallBehaviour[BallCtrl.type].radius/2;
				ballPos.vz=BallCtrl.ballPosWhenHit.vz;
			}
			//else ballVel.vy=tempy;
		}
	}

	TIMER_STOP(TIMER_COLLISION);
	BallUpdateSquash();
}


// the bounce has some surface-dependant stuff (and there are loads of sfx for that kinda thing)
// oh, we we ought to mod the volume according to impact speed
void ballPlayBounceEffect(void)
{
	ULONG j,pitch,bank;
	static const char sfx_no[] =
	{
		SFX_BALLBOUNCE_RUBBER,
		SFX_BALLBOUNCE_BOWLING,
		SFX_BALLBOUNCE_POWER,
		SFX_BALLBOUNCE_BEARING,
		SFX_BALLBOUNCE_BEACH,
		SFX_BALLBOUNCE_SNOW,	// nb - only loaded if "music_bank_loaded" == PREHISTORIC
		SFX_BALLBOUNCE_CRYSTAL,
	};

	if(BallCtrl.type < 7)
	{

		if(BallCtrl.type == BALL_MODE_SNOW)
		{
			if(music_bank_loaded != PREHISTORIC)
				return;
			bank = levelFX;
		}
		else
		{
			bank = globalFX;
		}

		//SFXPlay3D(globalFX, sfx_no[BallCtrl.type],64, &ballPos, 46 + random(4), 100);
		//sampleBank[globalFX].samples[sfx_no[BallCtrl.type]].pitch=46 + random(4);
		j=sfx_no[BallCtrl.type];
		pitch=(DEFAULT_PITCH + (RANDOM256() & 31));
		sfxSetSamplePitch(bank,j,pitch);
		sfxPlay3D(bank,j,&ballPos);
	}
}

void ballRender()
{
LONG		time;
LONG		radiusStart,radiusEnd;
SVECTOR		tempVec;
VECTOR		oldPos,scale;
MATRIX		tempMat,tempMat1;
IQUATERNION temp;
LONG		restorePos=0;
LONG		drawFlag;

/*
VERT		vrt;
long		stz;

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

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

	gte_ldv0(&vrt);			//load (x,y,z) coord
	gte_rtps();				//MACRO	// RotTransPers 
	gte_stszotz(&stz);		//store Z


	DB("stz = %d\n", stz);

	modelctrl.depthoveride=(0x8000)|((ushort)stz);
*/

	if (gameCtrl.PauseActive)
	{
		//printf ("paused no ball\n");
		pausedBallRender();
		modelctrl.depthoveride=0;
		return;
	}

	if ( (GloveCtrl.action==HAND_CASTSPELL && GloveCtrl.lastAction==HAND_JOINED) || GloveCtrl.action==HAND_SNATCH || GloveCtrl.action==HAND_RELEASE || GloveCtrl.action==HAND_CATCH)
	{
		if (ballColl.nHitPlats && !BodgeCtrl.hitPlat)
		{
			BodgeCtrl.carnivalPlat=ballColl.hitPlats[0].pPlatform;
			BodgeCtrl.hitPlat=TRUE;
		}
		else if (BodgeCtrl.hitPlat && !ballColl.nHitPlats)
		{
			ballColl.nHitPlats=1;
			ballColl.hitPlats[0].pPlatform=BodgeCtrl.carnivalPlat;
		}
	}
	else
	{
		BodgeCtrl.carnivalPlat=NULL;
		BodgeCtrl.hitPlat=FALSE;
	}

	if (GloveCtrl.ballIdleAction==BALLPEDDLE )
	{
		restorePos=ballPos.vy;

		if (Glover.currentAnimation==HANDANIM_ROLL2PEDDLE)
		{
			ballPos.vy=glovePos.vy-( ((BallBehaviour[BallCtrl.type].radius*2) * Glover.animInfo->frame)/3);
			pBallPSA->position.vy=(glovePos.vy/4096)-(((( (GloveBehaviour.radius/2) + BallBehaviour[BallCtrl.type].radius) * Glover.animInfo->frame)/3) /4096);
		}
		else if (Glover.currentAnimation!=HANDANIM_ROLLBLINK)
		{
			ballPos.vy=glovePos.vy-(BallBehaviour[BallCtrl.type].radius*2) ;
			pBallPSA->position.vy=(glovePos.vy/4096)- (( (GloveBehaviour.radius/2) +BallBehaviour[BallCtrl.type].radius) /4096);
		}

		if (Glover.currentAnimation==HANDANIM_ROLL2PEDDLE || Glover.currentAnimation==HANDANIM_ROLLBLINK )
		{
			scale.vx=0;
			scale.vy=0;
			if (Glover.animInfo->frame==0) scale.vz=-(BallBehaviour[BallCtrl.type].radius-GloveBehaviour.radius/3);
			else
			{
				scale.vz=-(BallBehaviour[BallCtrl.type].radius-GloveBehaviour.radius/3 )/Glover.animInfo->frame;
			}
			RotateVector2D(&scale,&scale,GloveCtrl.direction);
			pBallPSA->position.vx=(glovePos.vx+scale.vx)/4096;
			pBallPSA->position.vz=(glovePos.vz+scale.vz)/4096;
		}
		else
		{
			pBallPSA->position.vx=glovePos.vx/4096;
			pBallPSA->position.vz=glovePos.vz/4096;
		}
		ballVel.vy=0;

		scale.vx=0;
		scale.vy=0;
		scale.vz=8*4096;
		RotateVector2D(&scale,&scale,GloveCtrl.direction);
		ActorStartRoll(pBallPSA,scale.vx,scale.vz);
	}

	if (GloveCtrl.ballIdleAction==BALLONFINGER )
	{
		restorePos=ballPos.vy;
		if (Glover.currentAnimation==HANDANIM_ROLL2SPIN)
		{
			if (Glover.animInfo->frame>12)
			{
				ballPos.vy=glovePos.vy-( ((BallBehaviour[BallCtrl.type].radius*2) * (Glover.animInfo->frame-12))/3);
				pBallPSA->position.vy=(glovePos.vy/4096)- (( ((BallBehaviour[BallCtrl.type].radius*2) * (Glover.animInfo->frame-12))/3)/4696);
			}
		}
		else if (Glover.currentAnimation!=HANDANIM_ROLLBLINK)
		{
			ballPos.vy=glovePos.vy-(BallBehaviour[BallCtrl.type].radius*2) ;
			pBallPSA->position.vy=(glovePos.vy/4096)- ((BallBehaviour[BallCtrl.type].radius*2) /4496);
			ActorStartRollSide(pBallPSA,20*4096);
		}
		//HANDANIM_ROLLBLINK
		if (Glover.currentAnimation==HANDANIM_ROLL2SPIN || Glover.currentAnimation==HANDANIM_ROLLBLINK )
		{
			scale.vx=0;
			scale.vy=0;
			if (Glover.animInfo->frame==0) scale.vz=-(BallBehaviour[BallCtrl.type].radius-GloveBehaviour.radius/3);
			else
			{
				scale.vz=-(BallBehaviour[BallCtrl.type].radius-GloveBehaviour.radius/3 )/Glover.animInfo->frame;
			}
			RotateVector2D(&scale,&scale,GloveCtrl.direction);
			pBallPSA->position.vx=(glovePos.vx+scale.vx)/4096;
			pBallPSA->position.vz=(glovePos.vz+scale.vz)/4096;
		}
		else
		{
			pBallPSA->position.vx=glovePos.vx/4096;
			pBallPSA->position.vz=glovePos.vz/4096;
		}
		ballVel.vy=0;
	}

	if (GloveCtrl.action==HAND_ROTOR && GloveCtrl.lastAction==HAND_JOINED)
	{
		//printf ("slow spin\n");
		pBallPSA->world.qRotVel.x -= pBallPSA->world.qRotVel.x/8;
		pBallPSA->world.qRotVel.y -= pBallPSA->world.qRotVel.y/8;
		pBallPSA->world.qRotVel.z -= pBallPSA->world.qRotVel.z/8;

		pBallPSA->world.qRotLightVel.x -= pBallPSA->world.qRotLightVel.x/8;
		pBallPSA->world.qRotLightVel.y -= pBallPSA->world.qRotLightVel.y/8;
		pBallPSA->world.qRotLightVel.z -= pBallPSA->world.qRotLightVel.z/8;
	}

//	Special case stuff

	if (level==PREHISTORIC2)
	{
		VECTOR	boulderPos;
		boulderPos.vx=4849664;
		boulderPos.vy=-(600*4096);
		boulderPos.vz=1773645;

		//if ( !(frame&7) )sfxPlay3D(levelFX,SFX_PR_CANNONBALL_WALK , &boulderPos);
		if (nextBoulderTimer>=70) 
		{
			addRampBoulder(&BoulderData[0]);
			nextBoulderTimer=0;
		}
		if (nextBoulderTimer2>=25) 
		{
			addVentBoulder(&BoulderData[0]);
			nextBoulderTimer2=0;
		}
		if (gameCtrl.gameActive==TRUE)
		{
			moveBoulder(&BoulderData[0]);
			nextBoulderTimer++;
			nextBoulderTimer2++;
		}
		drawBoulder(&BoulderData[0]);
		boulderHitCheck(&BoulderData[0]);
	}

	if (level==PREHISTORIC1)
	{
		if (nextBoulderTimer>=100) 
		{
			addSnowBoulder(&BoulderData[0]);
			nextBoulderTimer=0;
		}
		if (gameCtrl.gameActive==TRUE)
		{
			moveBoulder(&BoulderData[0]);
			nextBoulderTimer++;
		}
		drawBoulder(&BoulderData[0]);
		snowBoulderHitCheck(&BoulderData[0]);
		//nextBoulderTimer2++;
	}

	if (level==PIRATES1)
		cannonHandler();

	if (!CamVars.showBall || !BallCtrl.enabled)
	{
		if (GloveCtrl.ballIdleAction==BALLPEDDLE || GloveCtrl.ballIdleAction==BALLONFINGER) ballPos.vy=restorePos;
		return;
	}

	if(!BallCtrl.enabled)
	{
		if (GloveCtrl.ballIdleAction==BALLPEDDLE || GloveCtrl.ballIdleAction==BALLONFINGER) ballPos.vy=restorePos;
		return;
	}


	if (BallCtrl.ballSmashed)
	{
		if (GloveCtrl.ballIdleAction==BALLPEDDLE || GloveCtrl.ballIdleAction==BALLONFINGER) ballPos.vy=restorePos;
		return;
	}


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

	drawFlag=RadiusCheck4096(&ballPos,ballColl.radius,1500);

/*	if(!RadiusCheck4096(&ballPos,ballColl.radius,1500))
	{
		if (GloveCtrl.ballIdleAction==BALLPEDDLE || GloveCtrl.ballIdleAction==BALLONFINGER) ballPos.vy=restorePos;
		return;
	}
*/
	if(BallCtrl.hurt && drawFlag)
		doBallHurt();

	if (BallCtrl.type==BALL_MODE_BEACH && !handpower_timer && GloveCtrl.action!=HAND_CASTSPELL)
	{
		BallChange.fromBall=BallCtrl.type;
		BallCtrl.lastType=BallCtrl.type;
		BallCtrl.type = BALL_MODE_NORMAL;
		BallChange.toBall=BallCtrl.type;
		BallChange.timer=0;
		BallChange.changeOn=SPELLCHANGE;
		BallChange.startRadii=BallBehaviour[BallCtrl.type].radius;
		BallChange.endRadii=BallBehaviour[BallCtrl.lastType].radius;
	}
	


	if (BallCtrl.type!=BALL_MODE_CRYSTAL && drawFlag)
	{
		pPhongPSA->world.rotatekeys->vect.x=1946;
		pPhongPSA->world.rotatekeys->vect.y=371;
		pPhongPSA->world.rotatekeys->vect.z=-585;
		pPhongPSA->world.rotatekeys->vect.w=3531;

		pPhongPSA->globalscale.vx=pBallPSA->globalscale.vx;
		pPhongPSA->globalscale.vy=pBallPSA->globalscale.vy;
		pPhongPSA->globalscale.vz=pBallPSA->globalscale.vz;

		pPhongPSA->position.vx=pBallPSA->position.vx;
		pPhongPSA->position.vy=pBallPSA->position.vy;
		pPhongPSA->position.vz=pBallPSA->position.vz;

		pPhongPSA->world.qRotLight.x=1946;
		pPhongPSA->world.qRotLight.y=585;
		pPhongPSA->world.qRotLight.z=-371;
		pPhongPSA->world.qRotLight.w=-3520;

		objectSetAnimation(pPhongPSA, 0);
		objectDraw(pPhongPSA);
		BallCtrl.ot_depth = modelctrl.lastdepth;
	}

	if (BallChange.changeOn==SPELLCHANGE)
	{
		//if (GloveCtrl.lastAction==HAND_JOINED && GloveCtrl.action==HAND_CASTSPELL) // ball on finger ball change
		if (GloveCtrl.spellCast)
		{
			long	temp,temp1;

			DB ("joined spell change time %d\n",GloveCtrl.spellActionTime);

			temp=GloveCtrl.spellActionTime-9;
			BallChange.timer=11-temp;
			temp1=21-GloveCtrl.spellActionTime;
			ballColl.radius=ballRadius=BallBehaviour[BallCtrl.type].radius=((ballStartRadius*temp1)/12)+ ((ballEndRadius*temp)/12);
			ActorStartRollSide(pBallPSA,spinSpeed);
			spinSpeed-=spinSpeed/20;
			ballPos.vy+=GloveCtrl.move.vy/10;

			if (GloveCtrl.spellActionTime==15)
			{
				BallBehaviour[BallCtrl.type].radius=ballStartRadius;
				BallCtrl.lastType=BallCtrl.type;
				if (BallCtrl.type==BALL_MODE_BEACH)
				{
					BallCtrl.type=BALL_MODE_NORMAL;
					handpower_timer=0;
				}
				else BallCtrl.type=ballNextMode[BallCtrl.type];

				if (BallCtrl.type==BALL_MODE_CRYSTAL)
				{
					pBallPSA=pCballPSA;
					pBallPSA->position.vx=ballPos.vx/4096;
					pBallPSA->position.vy=ballPos.vy/4096;
					pBallPSA->position.vz=ballPos.vz/4096;
				}

				if (BallCtrl.lastType==BALL_MODE_CRYSTAL)
				{
					pBallPSA=pOldBall;
					pBallPSA->position.vx=ballPos.vx/4096;
					pBallPSA->position.vy=ballPos.vy/4096;
					pBallPSA->position.vz=ballPos.vz/4096;
				}

				CamVars.oldTargetmodel=CamVars.targetmodel;
				CamVars.targetChangeTime=0;
				CamVars.targetChangeFlag=TRUE;

				CamVars.targetmodel=pBallPSA;
				ballColl.physicsModel=BallCtrl.type;
				New_StarRingDebris(&ballPos, 5);
			}

			if (GloveCtrl.spellActionTime==20)
			{
				ballColl.radius=ballRadius=BallBehaviour[BallCtrl.type].radius=ballEndRadius;
				BallChange.changeOn=FALSE;
				GloveCtrl.spellCast=FALSE;
				//drawFlag=FALSE;

				BallBehaviour[0].radius=(19*4096*NORMAL_SCALE)*1;
				BallBehaviour[1].radius=(19*4096*NORMAL_SCALE)*1.4;
				BallBehaviour[2].radius=(19*4096*NORMAL_SCALE)*0.6;
				BallBehaviour[3].radius=(19*4096*NORMAL_SCALE)*0.6;
				BallBehaviour[4].radius=(19*4096*NORMAL_SCALE)*2.5;
				BallBehaviour[5].radius=(19*4096*NORMAL_SCALE)*0.9;
				BallBehaviour[6].radius=(19*4096*NORMAL_SCALE)*1;
				ChangeBall(&pBallPSA->world,ballTex[BallCtrl.type]);
			}

///////////////////////////////////

			time=BallChange.timer;
			modelctrl.semitrans = 2;
			BallChange.dimAmount.vx=409*(time*2);
			BallChange.dimAmount.vy=409*(time*2);
			BallChange.dimAmount.vz=409*(time*2);

			BallChange.dimAmbient.vx=203*time*2;
			BallChange.dimAmbient.vy=203*time*2;
			BallChange.dimAmbient.vz=203*time*2;

			ChangeBall(&pBallPSA->world,ballTex[BallChange.fromBall]);
			
			//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
			if (!GloveCtrl.spellCast) drawFlag=FALSE;

			if (drawFlag)
			{
				modelctrl.lastdepth = OFFSCREEN_DEPTH;
				modelctrl.lighting=LIGHTING_PARALLEL;

				objectSetAnimation(pBallPSA, 0);
				objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);
				BallCtrl.ot_depth = modelctrl.lastdepth;
			}

			if (!GloveCtrl.spellCast) drawFlag=TRUE;

			BallChange.dimAmount.vx=409*(10-time)*2;
			BallChange.dimAmount.vy=409*(10-time)*2;
			BallChange.dimAmount.vz=409*(10-time)*2;

			BallChange.dimAmbient.vx=203*(10-time)*2;
			BallChange.dimAmbient.vy=203*(10-time)*2;
			BallChange.dimAmbient.vz=203*(10-time)*2;
			ChangeBall(&pBallPSA->world,ballTex[BallChange.toBall]);

			//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
			if (drawFlag)
			{
				modelctrl.semitrans = 0;
				modelctrl.lighting=LIGHTING_PARALLEL;

				objectSetAnimation(pBallPSA, 0);
				objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);
				BallCtrl.ot_depth = modelctrl.lastdepth;
				if (BallCtrl.type!=BALL_MODE_CRYSTAL) modelctrl.semitrans = 0;
				if (BallChange.changeOn) GsSetAmbient(BallChange.ambient.vx,BallChange.ambient.vy,BallChange.ambient.vz);
				//BallChange.changeOn=FALSE;
			}
			//objectDraw(pBallPSA);
  			//BallChange.timer++;
			//if (BallChange.timer==11) BallChange.changeOn=FALSE;
		}
		else	// cast spell at ball change
		{
			DB ("hand cast spell change\n");

			time=10-BallChange.timer;
			radiusStart=BallChange.startRadii;
			radiusEnd=BallChange.endRadii;
			
			if (BallCtrl.type==BALL_MODE_CRYSTAL) pBallPSA=pCballPSA;
			if (BallCtrl.lastType==BALL_MODE_CRYSTAL) pBallPSA=pOldBall;

			ballRadius=BallBehaviour[BallCtrl.type].radius=((radiusStart*(10-time))/10)+ ((radiusEnd*(time))/10);
			ballColl.physicsModel=BallCtrl.type;
			pBallPSA->globalscale.vx=ballRadius/152;
			pBallPSA->globalscale.vy=ballRadius/152;
			pBallPSA->globalscale.vz=ballRadius/152;

			
			BallChange.dimAmount.vx=409*(time*2);
			BallChange.dimAmount.vy=409*(time*2);
			BallChange.dimAmount.vz=409*(time*2);

			BallChange.dimAmbient.vx=203*time*2;
			BallChange.dimAmbient.vy=203*time*2;
			BallChange.dimAmbient.vz=203*time*2;

			ChangeBall(&pBallPSA->world,ballTex[BallChange.fromBall]);
			
			//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
			if (drawFlag)
			{
				modelctrl.semitrans = 2;
				modelctrl.lastdepth = OFFSCREEN_DEPTH;
				modelctrl.lighting=LIGHTING_PARALLEL;

				objectSetAnimation(pBallPSA, 0);
				objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);
			}

			//objectDraw(pBallPSA);

			BallChange.dimAmount.vx=409*(10-time)*2;
			BallChange.dimAmount.vy=409*(10-time)*2;
			BallChange.dimAmount.vz=409*(10-time)*2;

			BallChange.dimAmbient.vx=203*(10-time)*2;
			BallChange.dimAmbient.vy=203*(10-time)*2;
			BallChange.dimAmbient.vz=203*(10-time)*2;
			ChangeBall(&pBallPSA->world,ballTex[BallChange.toBall]);

			//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
			if (drawFlag)
			{
				BallCtrl.ot_depth = modelctrl.lastdepth;
				modelctrl.semitrans = 0;
				modelctrl.lighting=LIGHTING_PARALLEL;

				objectSetAnimation(pBallPSA, 0);
				objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);
			}


			BallCtrl.ot_depth = modelctrl.lastdepth;
			if (BallCtrl.type!=BALL_MODE_CRYSTAL)modelctrl.semitrans = 0;
			if (BallChange.changeOn) GsSetAmbient(BallChange.ambient.vx,BallChange.ambient.vy,BallChange.ambient.vz);

			BallChange.timer++;
			if (BallChange.timer==11) BallChange.changeOn=FALSE;
		}
	}
	else if (BallChange.changeOn==SNOWCHANGE)
	{
		time=BallBehaviour[BallChange.toBall].radius-BallBehaviour[BallChange.fromBall].radius;
		
		time=BallCtrl.snowAddition;
		time/=1024;
		//printf ("time %d\n",time);
		if (time<=10 && time!=0)
		{
			//time=10-time;
			
			radiusStart=BallBehaviour[BallChange.fromBall].radius;
			radiusEnd=BallBehaviour[BallChange.toBall].radius;


			BallChange.dimAmount.vx=409*(time)*1;
			BallChange.dimAmount.vy=409*(time)*1;
			BallChange.dimAmount.vz=409*(time)*1;

			BallChange.dimAmbient.vx=203*(time)*1;
			BallChange.dimAmbient.vy=203*(time)*1;
			BallChange.dimAmbient.vz=203*(time)*1;

			modelctrl.lastdepth = OFFSCREEN_DEPTH;
			//ChangeBall(&pBallPSA->world,ballTex[BallChange.fromBall]);
			ChangeBall(&pBallPSA->world,ballTex[7]);

			//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
			if (drawFlag)
			{
				modelctrl.semitrans = 2;
				modelctrl.lighting=LIGHTING_PARALLEL;

				objectSetAnimation(pBallPSA, 0);
				objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);
			}


			//objectDraw(pBallPSA);

			BallChange.dimAmount.vx=409*(10-time)*1;
			BallChange.dimAmount.vy=409*(10-time)*1;
			BallChange.dimAmount.vz=409*(10-time)*1;

			BallChange.dimAmbient.vx=203*(10-time)*1;
			BallChange.dimAmbient.vy=203*(10-time)*1;
			BallChange.dimAmbient.vz=203*(10-time)*1;

			ChangeBall(&pBallPSA->world,ballTex[BallChange.fromBall]);

			//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
			if (drawFlag)
			{
				BallCtrl.ot_depth = modelctrl.lastdepth;
				modelctrl.semitrans = 0;
				modelctrl.lighting=LIGHTING_PARALLEL;

				objectSetAnimation(pBallPSA, 0);
				objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);

				BallCtrl.ot_depth = modelctrl.lastdepth;
				if (BallCtrl.type!=BALL_MODE_CRYSTAL)modelctrl.semitrans = 0;
				if (BallChange.changeOn) GsSetAmbient(BallChange.ambient.vx,BallChange.ambient.vy,BallChange.ambient.vz);
				//BallChange.changeOn=FALSE;
				ChangeBall(&pBallPSA->world,ballTex[BallChange.toBall]);

			}
		}
		else
		{
			//if (BallCtrl.type==BALL_MODE_CRYSTAL) modelctrl.semitrans = 2;
		
			//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
			if (drawFlag)
			{
				BallChange.changeOn=FALSE;
				modelctrl.lighting=LIGHTING_PARALLEL;
				modelctrl.lastdepth = OFFSCREEN_DEPTH;

				GsSetAmbient(BallChange.ambient.vx,BallChange.ambient.vy,BallChange.ambient.vz);
				objectSetAnimation(pBallPSA, 0);
				objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);
			}

			BallCtrl.ot_depth = modelctrl.lastdepth;
			//if (BallCtrl.type==BALL_MODE_CRYSTAL) modelctrl.semitrans = 0;
			BallChange.changeOn=SNOWCHANGE;
		}
	}
	else
	{

		//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
		if (drawFlag)
		{
			modelctrl.lastdepth = OFFSCREEN_DEPTH;
			if (BallCtrl.type==BALL_MODE_CRYSTAL) modelctrl.semitrans = 2;
			modelctrl.lighting=LIGHTING_PARALLEL;

			objectSetAnimation(pBallPSA, 0);
			objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);
			BallCtrl.ot_depth = modelctrl.lastdepth;
			if (BallChange.changeOn) GsSetAmbient(BallChange.ambient.vx,BallChange.ambient.vy,BallChange.ambient.vz);
		}


		if (BallCtrl.type==BALL_MODE_CRYSTAL) modelctrl.semitrans = 0;


		if (BallCtrl.cancerFlag==START)
		{
			setupCancerBall();
			BallCtrl.cancerFlag=SET;
		}

		if (BallCtrl.cancerFlag && drawFlag)
		{

			//RotateVectorByQuaternion(&tempVec,&tempVec,&pBallPSA->world.qRot);
			//RotateVectorByRotation(&tempVec,&tempVec,&pBallPSA->world.qRot);
			//pBallPSA->world.movekeys->vect.x=0;
			//pBallPSA->world.movekeys->vect.y=0;
			//pBallPSA->world.movekeys->vect.z=100;

		 	tempVec.vx=0;
			tempVec.vy=0;
			tempVec.vz=BallBehaviour[BallCtrl.type].radius/2048;

			QuaternionMultiply(&temp,&CancerQuat[0], &pBallPSA->world.qRot);
			quaternionGetMatrix(&temp, &tempMat);

			ReadRotMatrix(&tempMat1);
			SetRotMatrix(&tempMat);
			gte_ldsv(&tempVec);
			gte_rtir();
			gte_stsv(&tempVec);
			

			SetRotMatrix(&tempMat1);
			oldPos.vx=pBallPSA->position.vx;
			oldPos.vy=pBallPSA->position.vy;
			oldPos.vz=pBallPSA->position.vz;

			//if (gameCtrl.gameActive!=FALSE)
			//{
				pBallPSA->position.vx+=tempVec.vx/2;
				pBallPSA->position.vy+=tempVec.vy/2;
				pBallPSA->position.vz+=tempVec.vz/2;
			//}

			BallCtrl.cancerPos[0].vx=tempVec.vx/2;
			BallCtrl.cancerPos[0].vy=tempVec.vy/2;
			BallCtrl.cancerPos[0].vz=tempVec.vz/2;

			//objectSetAnimation(pBallPSA, 0);
			scale.vx=pBallPSA->globalscale.vx;
			scale.vy=pBallPSA->globalscale.vy;			
			scale.vz=pBallPSA->globalscale.vz;			

			pBallPSA->globalscale.vx/=3;
			pBallPSA->globalscale.vy/=3;
			pBallPSA->globalscale.vz/=3;

			modelctrl.lighting=LIGHTING_PARALLEL;

			//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
			objectSetAnimation(pBallPSA, 0);
			objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);

		 	tempVec.vx=0;
			tempVec.vy=0;
			tempVec.vz=BallBehaviour[BallCtrl.type].radius/2048;

			QuaternionMultiply(&temp,&CancerQuat[1], &pBallPSA->world.qRot);
			quaternionGetMatrix(&temp, &tempMat);


			ReadRotMatrix(&tempMat1);
			SetRotMatrix(&tempMat);
			gte_ldsv(&tempVec);
			gte_rtir();
			gte_stsv(&tempVec);
			

			SetRotMatrix(&tempMat1);
			BallCtrl.cancerPos[1].vx=tempVec.vx/2;
			BallCtrl.cancerPos[1].vy=tempVec.vy/2;
			BallCtrl.cancerPos[1].vz=tempVec.vz/2;

			//if (gameCtrl.gameActive!=FALSE)
			//{
				pBallPSA->position.vx=oldPos.vx+BallCtrl.cancerPos[1].vx;
				pBallPSA->position.vy=oldPos.vy+BallCtrl.cancerPos[1].vy;
				pBallPSA->position.vz=oldPos.vz+BallCtrl.cancerPos[1].vz;
			//}

			//objectSetAnimation(pBallPSA, 0);
			//pBallPSA->globalscale.vx/=3;
			//pBallPSA->globalscale.vy/=3;
			//pBallPSA->globalscale.vz/=3;

			modelctrl.lighting=LIGHTING_PARALLEL;

			//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
			objectSetAnimation(pBallPSA, 0);
			objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);

			pBallPSA->globalscale.vx=scale.vx;
			pBallPSA->globalscale.vy=scale.vy;
			pBallPSA->globalscale.vz=scale.vz;

			pBallPSA->position.vx=oldPos.vx;
			pBallPSA->position.vy=oldPos.vy;
			pBallPSA->position.vz=oldPos.vz;
		}
	}
	//BallChange.changeOn=FALSE;
	modelctrl.semitrans = 0;

	if (GloveCtrl.ballIdleAction==BALLPEDDLE )
	{
		if (Glover.currentAnimation!=HANDANIM_ROLL2PEDDLE && Glover.currentAnimation!=HANDANIM_PEDDLE)
			GloveCtrl.ballIdleAction=BALLPEDDLESTOP;
		if (Glover.currentAnimation==HANDANIM_ROLLBLINK)
			GloveCtrl.ballIdleAction=BALLPEDDLESTOP;

		ballPos.vy=restorePos;

	}
	if (GloveCtrl.ballIdleAction==BALLONFINGER )
	{
		if (Glover.currentAnimation!=HANDANIM_ROLL2SPIN && Glover.currentAnimation!=HANDANIM_SPIN)
			GloveCtrl.ballIdleAction=BALLONFINGERSTOP;
		if (Glover.currentAnimation==HANDANIM_ROLLBLINK)
			GloveCtrl.ballIdleAction=BALLONFINGERSTOP;

		ballPos.vy=restorePos;
	}

	modelctrl.depthoveride=0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
void	pausedBallRender(void)
{
LONG		time;
LONG		radiusStart,radiusEnd;
SVECTOR		tempVec;
VECTOR		oldPos,scale;
MATRIX		tempMat,tempMat1;
IQUATERNION temp;
LONG		restorePos=0;
LONG		drawFlag;

	if (!BallCtrl.enabled) return;

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

	drawFlag=RadiusCheck4096(&ballPos,ballColl.radius,1500);

	if (BallCtrl.type!=BALL_MODE_CRYSTAL && drawFlag)
	{
		pPhongPSA->world.rotatekeys->vect.x=1946;
		pPhongPSA->world.rotatekeys->vect.y=371;
		pPhongPSA->world.rotatekeys->vect.z=-585;
		pPhongPSA->world.rotatekeys->vect.w=3531;

		pPhongPSA->globalscale.vx=pBallPSA->globalscale.vx;
		pPhongPSA->globalscale.vy=pBallPSA->globalscale.vy;
		pPhongPSA->globalscale.vz=pBallPSA->globalscale.vz;

		pPhongPSA->position.vx=pBallPSA->position.vx;
		pPhongPSA->position.vy=pBallPSA->position.vy;
		pPhongPSA->position.vz=pBallPSA->position.vz;

		pPhongPSA->world.qRotLight.x=1946;
		pPhongPSA->world.qRotLight.y=585;
		pPhongPSA->world.qRotLight.z=-371;
		pPhongPSA->world.qRotLight.w=-3520;
		objectSetAnimation(pPhongPSA, 0);
		objectDraw(pPhongPSA);
	}


	if (BallChange.changeOn==SPELLCHANGE)
	{
		if (GloveCtrl.spellCast)
		{
			long	temp,temp1;


			if (drawFlag)
			{
				modelctrl.lastdepth = OFFSCREEN_DEPTH;
				modelctrl.lighting=LIGHTING_PARALLEL;

				objectSetAnimation(pBallPSA, 0);
				objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);
				BallCtrl.ot_depth = modelctrl.lastdepth;
			}

			if (!GloveCtrl.spellCast) drawFlag=TRUE;

			//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
			if (drawFlag)
			{
				modelctrl.semitrans = 0;
				modelctrl.lighting=LIGHTING_PARALLEL;

				objectSetAnimation(pBallPSA, 0);
				objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);
				BallCtrl.ot_depth = modelctrl.lastdepth;
				if (BallCtrl.type!=BALL_MODE_CRYSTAL) modelctrl.semitrans = 0;
				if (BallChange.changeOn) GsSetAmbient(BallChange.ambient.vx,BallChange.ambient.vy,BallChange.ambient.vz);
				//BallChange.changeOn=FALSE;

			}
		}
		else	// cast spell at ball change
		{
			if (drawFlag)
			{
				modelctrl.semitrans = 2;
				modelctrl.lastdepth = OFFSCREEN_DEPTH;
				modelctrl.lighting=LIGHTING_PARALLEL;

				objectSetAnimation(pBallPSA, 0);
				objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);
			}

			//objectDraw(pBallPSA);

			//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
			if (drawFlag)
			{
				BallCtrl.ot_depth = modelctrl.lastdepth;
				modelctrl.semitrans = 0;
				modelctrl.lighting=LIGHTING_PARALLEL;

				objectSetAnimation(pBallPSA, 0);
				objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);
			}


			BallCtrl.ot_depth = modelctrl.lastdepth;
			if (BallCtrl.type!=BALL_MODE_CRYSTAL)modelctrl.semitrans = 0;
			if (BallChange.changeOn) GsSetAmbient(BallChange.ambient.vx,BallChange.ambient.vy,BallChange.ambient.vz);
		}
	}
	else if (BallChange.changeOn==SNOWCHANGE)
	{
		//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
		time=BallCtrl.snowAddition;
		time/=1024;
		//printf ("time %d\n",time);
		//if (time<=10 && time!=0)
		//{
			//time=10-time;
			
			//radiusStart=BallBehaviour[BallChange.fromBall].radius;
			//radiusEnd=BallBehaviour[BallChange.toBall].radius;
		if (time>9) time=9;

		BallChange.dimAmount.vx=409*(time)*1;
		BallChange.dimAmount.vy=409*(time)*1;
		BallChange.dimAmount.vz=409*(time)*1;

		BallChange.dimAmbient.vx=203*(time)*1;
		BallChange.dimAmbient.vy=203*(time)*1;
		BallChange.dimAmbient.vz=203*(time)*1;
		//}

		ChangeBall(&pBallPSA->world,ballTex[7]);
		if (drawFlag)
		{
			modelctrl.semitrans = 2;
			modelctrl.lighting=LIGHTING_PARALLEL;
			objectSetAnimation(pBallPSA, 0);
			objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);
		}

		BallChange.dimAmount.vx=409*(10-time)*1;
		BallChange.dimAmount.vy=409*(10-time)*1;
		BallChange.dimAmount.vz=409*(10-time)*1;

		BallChange.dimAmbient.vx=203*(10-time)*1;
		BallChange.dimAmbient.vy=203*(10-time)*1;
		BallChange.dimAmbient.vz=203*(10-time)*1;

		ChangeBall(&pBallPSA->world,ballTex[BallChange.toBall]);
		if (drawFlag)
		{
			BallCtrl.ot_depth = modelctrl.lastdepth;
			modelctrl.semitrans = 0;
			modelctrl.lighting=LIGHTING_PARALLEL;

			objectSetAnimation(pBallPSA, 0);
			objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);

			BallCtrl.ot_depth = modelctrl.lastdepth;
			if (BallCtrl.type!=BALL_MODE_CRYSTAL)modelctrl.semitrans = 0;
			if (BallChange.changeOn) GsSetAmbient(BallChange.ambient.vx,BallChange.ambient.vy,BallChange.ambient.vz);
			//BallChange.changeOn=FALSE;
			ChangeBall(&pBallPSA->world,ballTex[BallChange.toBall]);
		}
		else
		{
			//if (BallCtrl.type==BALL_MODE_CRYSTAL) modelctrl.semitrans = 2;
		
			//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
			if (drawFlag)
			{
				BallChange.changeOn=FALSE;
				modelctrl.lighting=LIGHTING_PARALLEL;
				modelctrl.lastdepth = OFFSCREEN_DEPTH;

				GsSetAmbient(BallChange.ambient.vx,BallChange.ambient.vy,BallChange.ambient.vz);
				objectSetAnimation(pBallPSA, 0);
				objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);
			}

			BallCtrl.ot_depth = modelctrl.lastdepth;
			//if (BallCtrl.type==BALL_MODE_CRYSTAL) modelctrl.semitrans = 0;
			BallChange.changeOn=SNOWCHANGE;
		}
	}
	else
	{

		//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
		if (drawFlag)
		{
			modelctrl.lastdepth = OFFSCREEN_DEPTH;
			if (BallCtrl.type==BALL_MODE_CRYSTAL) modelctrl.semitrans = 2;
			modelctrl.lighting=LIGHTING_PARALLEL;

			objectSetAnimation(pBallPSA, 0);
			objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);
			BallCtrl.ot_depth = modelctrl.lastdepth;
			if (BallChange.changeOn) GsSetAmbient(BallChange.ambient.vx,BallChange.ambient.vy,BallChange.ambient.vz);
		}


		if (BallCtrl.type==BALL_MODE_CRYSTAL) modelctrl.semitrans = 0;


		if (BallCtrl.cancerFlag==START)
		{
			setupCancerBall();
			BallCtrl.cancerFlag=SET;
		}

		if (BallCtrl.cancerFlag && drawFlag)
		{

			//RotateVectorByQuaternion(&tempVec,&tempVec,&pBallPSA->world.qRot);
			//RotateVectorByRotation(&tempVec,&tempVec,&pBallPSA->world.qRot);
			//pBallPSA->world.movekeys->vect.x=0;
			//pBallPSA->world.movekeys->vect.y=0;
			//pBallPSA->world.movekeys->vect.z=100;

		 	tempVec.vx=0;
			tempVec.vy=0;
			tempVec.vz=BallBehaviour[BallCtrl.type].radius/2048;

			QuaternionMultiply(&temp,&CancerQuat[0], &pBallPSA->world.qRot);
			quaternionGetMatrix(&temp, &tempMat);

			ReadRotMatrix(&tempMat1);
			SetRotMatrix(&tempMat);
			gte_ldsv(&tempVec);
			gte_rtir();
			gte_stsv(&tempVec);
			

			SetRotMatrix(&tempMat1);
			oldPos.vx=pBallPSA->position.vx;
			oldPos.vy=pBallPSA->position.vy;
			oldPos.vz=pBallPSA->position.vz;

			//if (gameCtrl.gameActive!=FALSE)
			//{
				pBallPSA->position.vx+=tempVec.vx/2;
				pBallPSA->position.vy+=tempVec.vy/2;
				pBallPSA->position.vz+=tempVec.vz/2;
			//}

			BallCtrl.cancerPos[0].vx=tempVec.vx/2;
			BallCtrl.cancerPos[0].vy=tempVec.vy/2;
			BallCtrl.cancerPos[0].vz=tempVec.vz/2;

			//objectSetAnimation(pBallPSA, 0);
			scale.vx=pBallPSA->globalscale.vx;
			scale.vy=pBallPSA->globalscale.vy;			
			scale.vz=pBallPSA->globalscale.vz;			

			pBallPSA->globalscale.vx/=3;
			pBallPSA->globalscale.vy/=3;
			pBallPSA->globalscale.vz/=3;

			modelctrl.lighting=LIGHTING_PARALLEL;

			//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
			objectSetAnimation(pBallPSA, 0);
			objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);

		 	tempVec.vx=0;
			tempVec.vy=0;
			tempVec.vz=BallBehaviour[BallCtrl.type].radius/2048;

			QuaternionMultiply(&temp,&CancerQuat[1], &pBallPSA->world.qRot);
			quaternionGetMatrix(&temp, &tempMat);


			ReadRotMatrix(&tempMat1);
			SetRotMatrix(&tempMat);
			gte_ldsv(&tempVec);
			gte_rtir();
			gte_stsv(&tempVec);
			

			SetRotMatrix(&tempMat1);
			BallCtrl.cancerPos[1].vx=tempVec.vx/2;
			BallCtrl.cancerPos[1].vy=tempVec.vy/2;
			BallCtrl.cancerPos[1].vz=tempVec.vz/2;

			//if (gameCtrl.gameActive!=FALSE)
			//{
				pBallPSA->position.vx=oldPos.vx+BallCtrl.cancerPos[1].vx;
				pBallPSA->position.vy=oldPos.vy+BallCtrl.cancerPos[1].vy;
				pBallPSA->position.vz=oldPos.vz+BallCtrl.cancerPos[1].vz;
			//}

			//objectSetAnimation(pBallPSA, 0);
			//pBallPSA->globalscale.vx/=3;
			//pBallPSA->globalscale.vy/=3;
			//pBallPSA->globalscale.vz/=3;

			modelctrl.lighting=LIGHTING_PARALLEL;

			//objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);
			objectSetAnimation(pBallPSA, 0);
			objectDrawWithShadow(pBallPSA, ballColl.radius >> 12,ballColl.radius >> 12,1);

			pBallPSA->globalscale.vx=scale.vx;
			pBallPSA->globalscale.vy=scale.vy;
			pBallPSA->globalscale.vz=scale.vz;

			pBallPSA->position.vx=oldPos.vx;
			pBallPSA->position.vy=oldPos.vy;
			pBallPSA->position.vz=oldPos.vz;
		}
	}




}

//////////////////////////////////////////////////////////////////////////////////////////////
void ballComeOutOfHoop(VECTOR *pos, int ya)
{
	ballVel.vx = 0;
	ballVel.vy = 10 * 4096;	//HURTJUMPSPEED;
	ballVel.vz = 0;

	ballPos = ballColl.oldPos = *pos;
	ballPos.vy -= 10 * 4096;	// moved up a bit, coz the hand kept catching it
	ballColl.oldPos.vy -= 10 * 4096;

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

	BallCtrl.inside_bugle = NULL;
	BallCtrl.enabled = TRUE;
}
//////////////////////////////////////////////////////////////////////////////////////////////

// eg - levels where you don't start with the ball
void ballPlaceAt(VECTOR *pos)
{
	ballColl.oldPos = ballPos = BallStartPos = *pos;
	BallCtrl.enabled = TRUE;
	ballVel.vx = 0;
	ballVel.vy = 0;
	ballVel.vz = 0;
	ballColl.oldVel = ballVel;

// just make sure it's displayed at the right point, coz we may have already been through the ball-updating stuff
	pBallPSA->position.vx=ballPos.vx/4096;
	pBallPSA->position.vy=ballPos.vy/4096;
	pBallPSA->position.vz=ballPos.vz/4096;

	BallCtrl.inside_bugle = NULL;

	BallCtrl.onIce=FALSE;	// rqd by prehist boss and carnival in fact when ever we have ice
	BallCtrl.onIceFlag=FALSE;

	ZEROVECTOR(&BallCtrl.iceData);
	ZEROVECTOR(&BallCtrl.iceRollData);
	ZEROVECTOR(&BallCtrl.iceRollDataVel);



// Conditional, coz the monkeys call this
// ALL THE TIME
	if(BallCtrl.type == BALL_MODE_SNOW)
		removeSnow();
}
/***************************************************************************************/
void ballPowerWhackReturn()
{
	VECTOR pos;
	BallCtrl.powerwhack = 0;	// this is when it's hit an enemy & is being moved back to "reload"
	BallCtrl.anywhack = 0;
	if (GloveCtrl.action!=HAND_ROTOR)
	{
		pos = glovePos;
		pos.vy -= 150<<12;
		ballPlaceAt(&pos);
	}
}
/********************************************************************************************/
// Remove all snow from the ball, leaving it in it's pre-snow type
// (change by Fred so prehist boss stays in bowling ball mode - it used to revert to rubber)
void	removeSnow(void)
{
	int dest;

	//DB ("removing snow\n");

	modelctrl.semitrans = 0;
	BallChange.dimAmount.vx=4096;
	BallChange.dimAmount.vy=4096;
	BallChange.dimAmount.vz=4096;

	BallChange.dimAmbient.vx=2032;
	BallChange.dimAmbient.vy=2032;
	BallChange.dimAmbient.vz=2032;
	BallChange.timer=0;
	//modelctrl.lastdepth = OFFSCREEN_DEPTH;

	dest = BallCtrl.type;

	if(dest == BALL_MODE_SNOW)
	{
		dest = BallCtrl.preSnowType;
	}
			
	BallCtrl.type=dest;
	ChangeBall(&pBallPSA->world,ballTex[dest]);

// definitely not a wise move to draw the ball here
//	objectDrawCheckWaterShadow(pBallPSA,0,   ballColl.radius >> 12,ballColl.radius >> 12,1);

	BallCtrl.snowAddition=0;
	BallCtrl.snowTexChange=0;
	BallCtrl.onSnow=0;

	BallChange.changeOn=FALSE;
	
	ballRadius = ballColl.radius=BallBehaviour[dest].radius;
	BallBehaviour[BALL_MODE_SNOW].radius=ballColl.radius;
/*
	BallBehaviour[0].radius=(19*4096*NORMAL_SCALE)*1;
	BallBehaviour[1].radius=(19*4096*NORMAL_SCALE)*1.4;
	BallBehaviour[2].radius=(19*4096*NORMAL_SCALE)*0.6;
	BallBehaviour[3].radius=(19*4096*NORMAL_SCALE)*0.6;
	BallBehaviour[4].radius=(19*4096*NORMAL_SCALE)*2.5;
	BallBehaviour[5].radius=(19*4096*NORMAL_SCALE)*0.9;
	BallBehaviour[6].radius=(19*4096*NORMAL_SCALE)*1;
	ChangeBall(&pBallPSA->world,ballTex[BallCtrl.type]);
*/

	pBallPSA->globalscale.vx=ballRadius/152;
	pBallPSA->globalscale.vy=ballRadius/152;
	pBallPSA->globalscale.vz=ballRadius/152;

}

/*******************************************************************************************/
//LONG	rtest=1816653;

void	addRampBoulder(BOULDERDATA *data)
{
BOULDERDATA	*check=NULL;
ULONG	loop,flag=0;
//-496.000000 -361.000000 -1035.000000 
//1902.000000  571.000000   886.000000


	//if ( glovePos.vx>(-496*4096) && glovePos.vx< ( (-496+1902)*4096) );
	//else return;
	//if ( glovePos.vy>(372*4096) && glovePos.vx< ( (-372+571)*4096) );
	//else return;
	//if ( glovePos.vy>(1035*4096) && glovePos.vx< ( (-728+886)*4096) );
	//else return;

	for (loop=0;loop<10;loop++)
	{
		if (data->time==0)
		{
			check=data;
			flag=loop;
			break;
		}
		data++;
	}


	if (check==NULL)
	{
		DB ("no free slots for boulder\n");
		return;
	}
	//loop=randomInt(39587);

	loop=(RANDOM256()/85);

	BoulderColl[flag].radius=BoulderBallPhysics.radius;
	BoulderColl[flag].pVel=&check->vel;
	BoulderColl[flag].oldVel=check->vel;
	BoulderColl[flag].pPos=&check->pos;
	BoulderColl[flag].oldPos=check->pos;
	BoulderColl[flag].physics=&BoulderBallPhysics;

	check->pos.vx=4849664;
	
	//check->pos.vy=605-loop;
	//check->pos.vy=-(600-loop)*4096;
	check->pos.vy=-(600*4096);

	check->pos.vz=1773645;

	if (loop==0) check->pos.vz=1802317;
	else if (loop==1) check->pos.vz=1806413;
	else check->pos.vz=1824768;

	//check->pos.vz=rtest;

	check->vel.vx=0;
	check->vel.vy=0;
	check->vel.vz=0;
	check->oldPos.vx=check->pos.vx;
	check->oldPos.vy=check->pos.vy;
	check->oldPos.vz=check->pos.vz;
	check->firstHit=FALSE;
	check->qRot.x=-2896;
	check->qRot.y=0;
	check->qRot.z=0;
	check->qRot.w=2896;

	check->time=400;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void	addVentBoulder(BOULDERDATA *data)
{
BOULDERDATA	*check=NULL;

ULONG	loop,test,flag=0;


	//if ( glovePos.vx<(1855*4096) || glovePos.vx> ( (1855+325)*4096) ) return;
	//if ( glovePos.vy<(-372*4096) || glovePos.vx> ( (-372+557)*4096) ) return;
	//if ( glovePos.vy<(-728*4096) || glovePos.vx> ( (-728+607)*4096) ) return;


	for (loop=0;loop<10;loop++)
	{
		if (data->time==0)
		{
			check=data;
			flag=loop;
			break;
		}
		data++;
	}


	if (check==NULL)
	{
		DB ("no free slots for boulder\n");
		return;
	}
	//loop=randomInt(39587);
	loop=(RANDOM256()*1330);
	test=(RANDOM256()*128)-16384;

	BoulderColl[flag].radius=BoulderBallPhysicsVent.radius;
	BoulderColl[flag].pVel=&check->vel;
	BoulderColl[flag].oldVel=check->vel;
	BoulderColl[flag].pPos=&check->pos;
	BoulderColl[flag].oldPos=check->pos;
	BoulderColl[flag].physics=&BoulderBallPhysicsVent;

	check->firstHit=TRUE;
	check->pos.vx=8380470-loop;
	check->pos.vy=-491990;
	check->pos.vz=2539722;
	check->vel.vx=test;
	check->vel.vy=0;
	check->vel.vz=0;
	check->oldPos.vx=check->pos.vx;
	check->oldPos.vy=check->pos.vy;
	check->oldPos.vz=check->pos.vz;

	check->qRot.x=-2896;
	check->qRot.y=0;
	check->qRot.z=0;
	check->qRot.w=2896;

	check->time=130;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//LONG	btestx=1231027;
//LONG	btesty=1743778;
//LONG	btestz=7762008;

void	addSnowBoulder(BOULDERDATA *data)
{
BOULDERDATA	*check=NULL;
ULONG	loop,flag=0;


	for (loop=0;loop<10;loop++)
	{
		if (data->time==0)
		{
			check=data;
			flag=loop;
			break;
		}
		data++;
	}


	if (check==NULL)
	{
		printf ("no free slots for boulder\n");
		return;
	}
	//loop=randomInt(39587);
	//loop=RANDOM256()*696;

	BoulderColl[flag].radius=BoulderBallPhysics.radius;
	BoulderColl[flag].pVel=&check->vel;
	BoulderColl[flag].oldVel=check->vel;
	BoulderColl[flag].pPos=&check->pos;
	BoulderColl[flag].oldPos=check->pos;
	BoulderColl[flag].physics=&BoulderBallPhysics;


	check->pos.vx=-1231027;
	check->pos.vy=-1743778;
	check->pos.vz=7770200;

	//check->pos.vx=-btestx;
	//check->pos.vy=-btesty;
	//check->pos.vz=btestz;


	check->vel.vx=2*4096;
	check->vel.vy=0;
	check->vel.vz=0;
	check->oldPos.vx=check->pos.vx;
	check->oldPos.vy=check->pos.vy;
	check->oldPos.vz=check->pos.vz;

	check->firstHit=TRUE;
	//check->firstHit=FALSE;

	check->qRot.x=-2896;
	check->qRot.y=0;
	check->qRot.z=0;
	check->qRot.w=2896;

	check->time=340;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void	moveBoulder(BOULDERDATA *data)
{
ULONG	loop;
LONG	drag;
VECTOR	oldVel;
	//drag=BoulderBallPhysics.drag;

	for (loop=0;loop<10;loop++)
	{
		if (data->time>0)
		{

			drag=BoulderColl[loop].physics->drag;
			
			data->vel.vy-=GRAVITY*2;
			
			data->oldPos.vx=data->pos.vx;
			data->oldPos.vy=data->pos.vy;
			data->oldPos.vz=data->pos.vz;

			ADDVECTOR(&data->pos, &data->pos, &data->vel);
			data->pos.vy-=(data->vel.vy*2);
			data->vel.vx=-data->vel.vx;
			data->vel.vy=-data->vel.vy;
			data->vel.vz=-data->vel.vz;

			if ( !(frame&7) && level==PREHISTORIC2 )sfxPlay3D(levelFX,SFX_PR_CANNONBALL_WALK , &data->pos);

			if ( BoulderColl[loop].physics == &BoulderBallPhysicsVent )
			{
				oldVel.vx=data->vel.vx;
				oldVel.vy=data->vel.vy;
				oldVel.vz=data->vel.vz;
				data->hit=collboxCheckSphere(&BoulderColl[loop]);
				
				//data->vel.vx=( (oldVel.vx*17)+data->vel.vx)/18;
				//data->vel.vy=( (oldVel.vy*17)+data->vel.vy)/18;
				//data->vel.vz=( (oldVel.vz*17)+data->vel.vz)/18;

				//data->vel.vx+=( oldVel.vx-data->vel.vx);
				//data->vel.vy+=( oldVel.vy-data->vel.vy);
				data->vel.vz+=(( oldVel.vz-data->vel.vz )*750)/1000;
			}
			else data->hit=collboxCheckSphere(&BoulderColl[loop]);

			if (data->firstHit==FALSE && data->hit)
			{
				data->vel.vx=0;
				data->vel.vy=0;
				data->vel.vz=0;
				data->firstHit=TRUE;
			}

			data->vel.vx=-data->vel.vx;
			data->vel.vy=-data->vel.vy;
			data->vel.vz=-data->vel.vz;

			data->vel.vx=(data->vel.vx*drag)/4096;
			data->vel.vy=(data->vel.vy*drag)/4096;
			data->vel.vz=(data->vel.vz*drag)/4096;
			data->time--;

			if (data->pos.vy>1200000 && level==PREHISTORIC2)
			{
				data->time=0;

				oldVel.vx=data->pos.vx;
				oldVel.vy=data->pos.vy;
				oldVel.vz=data->pos.vz;
				New_Debris(DEBRIS_CANNON,&oldVel,1024);
				//New_Debris(DEBRIS_CANNON,&ballPos,1024);
				//DB ("boulder killed\n");
			}
		}
		else data->time=0;
		data++;
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void	drawBoulder(BOULDERDATA *data)
{
ULONG		loop;
IQUATERNION	tempQ;

	for (loop=0;loop<10;loop++)
	{
		if (data->time)
		{
			if (GloveCtrl.attachedBoulder==data)
			{
				pGloveBoulderPSA->position.vx=data->pos.vx/4096;
				pGloveBoulderPSA->position.vy=data->pos.vy/4096;
				pGloveBoulderPSA->position.vz=data->pos.vz/4096;

				if (gameCtrl.gameActive)
				{
					ActorStartRoll(pGloveBoulderPSA,data->pos.vx-data->oldPos.vx,data->pos.vz-data->oldPos.vz);
					GetQuaternionFromRotation(&tempQ,&pGloveBoulderPSA->world.qRotVel);
					QuaternionMultiply(&data->qRot,&data->qRot,&tempQ);
				}

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

				gte_SetRotMatrix(&GsWSMATRIX);
				gte_SetTransMatrix(&GsWSMATRIX);
				if(RadiusCheck4096(&data->pos,ballColl.radius,1500))
				{
					objectSetAnimation(pGloveBoulderPSA, 0);
					objectDraw(pGloveBoulderPSA);
				}
			}
			else
			{
				pBoulderPSA->position.vx=data->pos.vx/4096;
				pBoulderPSA->position.vy=data->pos.vy/4096;
				pBoulderPSA->position.vz=data->pos.vz/4096;

				if (gameCtrl.gameActive)
				{
					ActorStartRoll(pBoulderPSA,data->pos.vx-data->oldPos.vx,data->pos.vz-data->oldPos.vz);
					GetQuaternionFromRotation(&tempQ,&pBoulderPSA->world.qRotVel);
					QuaternionMultiply(&data->qRot,&data->qRot,&tempQ);
				}

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

				gte_SetRotMatrix(&GsWSMATRIX);
				gte_SetTransMatrix(&GsWSMATRIX);
				if(RadiusCheck4096(&data->pos,ballColl.radius,1500))
				{
					objectSetAnimation(pBoulderPSA, 0);
					objectDraw(pBoulderPSA);
				}
			}
		}
		data++;
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void	boulderHitCheck(BOULDERDATA *data)
{
ULONG	loop;
VECTOR	distcheck;
LONG	gloveBoulderRadius;
LONG	ballBoulderRadius;
LONG	mag;

	gloveBoulderRadius=GloveBehaviour.radius+BoulderBallPhysics.radius;
	ballBoulderRadius=BallBehaviour[BallCtrl.type].radius+BoulderBallPhysics.radius;

	for (loop=0;loop<10;loop++)
	{
		if (data->time)
		{
			distcheck.vx=data->pos.vx-glovePos.vx;
			distcheck.vy=data->pos.vy-glovePos.vy;
			distcheck.vz=data->pos.vz-glovePos.vz;
			if ( (abs(distcheck.vx)<gloveBoulderRadius) && (abs(distcheck.vy)<gloveBoulderRadius) && (abs(distcheck.vz)<gloveBoulderRadius) )
			{
				mag=Magnitude(&distcheck);
				if (mag < gloveBoulderRadius ) // glove has been hit
				{
					if (!GloveCtrl.hurtFlag && !GloveCtrl.deathType)
					{
						GloveCtrl.hurtFlag=TRUE;
						GloveCtrl.deathType=DEADFROMPAIN;
					}
				}
			}

			distcheck.vx=data->pos.vx-ballPos.vx;
			distcheck.vy=data->pos.vy-ballPos.vy;
			distcheck.vz=data->pos.vz-ballPos.vz;
			if ( (abs(distcheck.vx)<ballBoulderRadius) && (abs(distcheck.vy)<ballBoulderRadius) && (abs(distcheck.vz)<ballBoulderRadius) )
			{
				mag=Magnitude(&distcheck);
				if (mag < gloveBoulderRadius ) // glove has been hit
				{
					if (!GloveCtrl.hurtFlagBall && !GloveCtrl.deathTypeBall)
					{
						GloveCtrl.deathTypeBall=DEADFROMBALLBURST;
						GloveCtrl.hurtFlagBall=TRUE;
					}
				}
			}
		}
		data++;
	}
}
			

//////////////////////////////////////////////////////////////////////////////
void	snowBoulderHitCheck(BOULDERDATA *data)
{
ULONG	loop;
VECTOR	distcheck;
LONG	gloveBoulderRadius;
LONG	ballBoulderRadius;
LONG	mag;

	gloveBoulderRadius=GloveBehaviour.radius+BoulderBallPhysics.radius;
	ballBoulderRadius=BallBehaviour[BallCtrl.type].radius+BoulderBallPhysics.radius;

	for (loop=0;loop<10;loop++)
	{
		if (data->time)
		{
			distcheck.vx=data->pos.vx-glovePos.vx;
			distcheck.vy=data->pos.vy-glovePos.vy;
			distcheck.vz=data->pos.vz-glovePos.vz;
			if ( (abs(distcheck.vx)<gloveBoulderRadius) && (abs(distcheck.vy)<gloveBoulderRadius) && (abs(distcheck.vz)<gloveBoulderRadius) )
			{
				mag=Magnitude(&distcheck);
				if ( (mag < gloveBoulderRadius) && !GloveCtrl.insideSnowBall) // glove has been hit
				{
					if (GloveCtrl.ballWithHand==TRUE)
						DisconnectGloveFromBall(DISCONNECT_WHEN_JOINED|DISCONNECT_WHEN_BOUNCING|DISCONNECT_WHEN_WALKINGON);

					GloveCtrl.attachedBoulder=data;
					GloveCtrl.insideSnowBall=TRUE;
					GloveCtrl.onGround=FALSE;
					GloveCtrl.positionHold=FALSE;
				}
			}

			distcheck.vx=data->pos.vx-ballPos.vx;
			distcheck.vy=data->pos.vy-ballPos.vy;
			distcheck.vz=data->pos.vz-ballPos.vz;
			if ( (abs(distcheck.vx)<ballBoulderRadius) && (abs(distcheck.vy)<ballBoulderRadius) && (abs(distcheck.vz)<ballBoulderRadius) )
			{
				mag=Magnitude(&distcheck);
				if (mag < gloveBoulderRadius ) // ball has been hit
				{
					if (GloveCtrl.ballWithHand==TRUE)
						DisconnectGloveFromBall(DISCONNECT_WHEN_JOINED|DISCONNECT_WHEN_BOUNCING|DISCONNECT_WHEN_WALKINGON);
					else
					{
						MakeUnit(&distcheck);
						SCALEVECTOR(&distcheck,ballBoulderRadius);
						ballPos.vx-=distcheck.vx;
						ballPos.vy-=distcheck.vy;
						ballPos.vz-=distcheck.vz;
						ballVel.vx-=distcheck.vx;
						ballVel.vy-=distcheck.vy;
						ballVel.vz-=distcheck.vz;
					}
					//if (!GloveCtrl.hurtFlagBall && !GloveCtrl.deathTypeBall)
					//{
					//	GloveCtrl.deathTypeBall=DEADFROMBALLBURST;
					//	GloveCtrl.hurtFlagBall=TRUE;
					//}
				}
			}
		}
		data++;
	}
}

//////////////////////////////////////////////////////////////////////////////

void	standAloneBall()
{
SHORT	leftRight,upDown;
USHORT	padIn;

	if (!GloveCtrl.padDisableTimer)
	{
		leftRight=(nleftx[0]);
		upDown=-(nlefty[0]);
		padIn=pad[0];
	}
	else
	{
		leftRight=0;
		upDown=0;
		padIn=0;
	}
	
	CamVars.targetmodel=pBallPSA;
	GloveCtrl.enabled=FALSE;
	if (padIn&PAD_CROSS)
	{
		if (BallCtrl.ballOnGround)
		{
			ballVel.vy+=(8*gravity*BallBehaviour[BallCtrl.type].bounce)/4096;
		}
	}
	moveBall(upDown,leftRight);

	if (GloveCtrl.hurtFlagBall==TRUE)
	{
		//BallCtrl.health=255;
		//BallCtrl.hurt=TRUE;
		//printf ("ball is dead\n");
		doBallBurst();
		BallCtrl.hurt++;
		if (BallCtrl.hurt==50 && !gameCtrl.dropOutFlag)
		{
			MenuFadeOut();
			gameCtrl.dropOutFlag=GAME_FAILEDBONUS;
			NextLevelBasics();
		}
	}
}



//////////////////////////////////////////////////////////////////////////////
void	setupCancerBall(void)
{

	CancerColl[0].radius=BallBehaviour[BallCtrl.type].radius/3;
	CancerColl[0].pCollBox=collBox;
	CancerColl[0].pVel=&CancerVel[0];
	CancerColl[0].pPos=&CancerPos[0];
	CancerColl[0].pRot=&ballRot;
	CancerColl[0].physics=&CancerPart1;

	CancerColl[1].radius=BallBehaviour[BallCtrl.type].radius/3;
	CancerColl[1].pCollBox=collBox;
	CancerColl[1].pVel=&CancerVel[1];
	CancerColl[1].pPos=&CancerPos[1];
	CancerColl[1].pRot=&ballRot;
	CancerColl[1].physics=&CancerPart2;

	CancerPart1.bounce=BallBehaviour[BallCtrl.type].bounce;
	CancerPart1.drag=BallBehaviour[BallCtrl.type].drag;
	CancerPart1.radius=BallBehaviour[BallCtrl.type].radius/3;

	CancerPart2.bounce=BallBehaviour[BallCtrl.type].bounce;
	CancerPart2.drag=BallBehaviour[BallCtrl.type].drag;
	CancerPart2.radius=BallBehaviour[BallCtrl.type].radius/3;
}