#include "glover.h"

//#define CAMBOXES
//#define PRINTHITPOS	TRUE

//#define TESTALL


//#define PRECALC_COLLISION


//#define	SHITLOADSOFDEBUG

#define COLLMARGIN (4)
//#define COLLMARGIN (40)
#define COLLMARGINBIG (4096*256)

#define PRINTHITPOS	FALSE
#define PRINTERROR	TRUE
#define	PRINTRAMP	FALSE

//#define MOVPLATDIST (8*4096)

//#define CDB if((pD->dbug)&1) DB

//Point3DType pTempW[16]; 

#define STARTPOLY ctr=0
#define DRAWPOLY(R,G,B)	lscapeDrawBoundPoly3D(ctr, pTempW, R,G,B)
#define ADDVERT(X,Y,Z) {pTempW[ctr].x=(X)/4096;pTempW[ctr].y=((Y)/4096);pTempW[ctr++].z=(Z)/4096;}

//int	g=4000/4; 

BFF_CollHeader *WorldBFFcoll = NULL;
ULONG	*reducedCollBox;

HITDATA *swap[16];
long gravity=GRAVITY; // default gravity

#define CYLIN_X		TRUE
#define CYLIN_Y		TRUE
#define CYLIN_Z		TRUE


//ULONG	pTestFaces[]={0x00021000};  // Tri with verts 0,1&2
//VECTOR	pTestVerts[]={	{0,0,0},
//						{100,0,0},
//						{100,-30,100}
//};

//char sBuff[128];

static ULONG *tempFile;
/****************************************************************************************/

COLLBOX *collisionLoadMeshCRC(long crc)
{
	ULONG offMesh;
	void *firstRamp=NULL;
	ULONG *pM;
	int loop;
	COLLBOX *collBox;
	BFF_CollHeader *bffcoll;
	bffcoll=(BFF_CollHeader *)BFF_FindObject(BFF_COLL_ID, crc);

	if(bffcoll)
	{
		tempFile = ADD2POINTER(bffcoll,bffcoll->base_mesh_offset);

	// This should only be the case on the level mesh...
/*
		if(bffcoll->red_mesh_offset)
		{
			WorldBFFcoll = bffcoll;
			reducedCollBox = ADD2POINTER(bffcoll,bffcoll->red_mesh_offset);
		}
*/
	}
	else
	{
/*		char *tf;
		//PRINTF("raw %s not found in BFF\n",sFN);
		tf = MALLOC(128,"temp");
		ASSERT(tf);
		strcpy(tf, sFN);
		strcat(tf, ".RAW");
		tempFile=(ULONG *)LoadFile(tf);
		FREE(tf);

		if(!tempFile)*/
			return(0);
	}



/*
	tempFile=(ULONG *)LoadFile(sBuff);
	if(!tempFile)
		return(0);
*/

	numCollBoxes=*tempFile;


	collBox=(COLLBOX *)(tempFile+1);


	offMesh=(sizeof(COLLBOX)*numCollBoxes)+sizeof(ULONG);
	//collBox=(COLLBOX*)MALLOC(sizeof(COLLBOX)*numCollBoxes, "COLLISION BOXES"); // get mem for coll cubes
	
	//FMEMCPY(collBox,tempFile,(sizeof(COLLBOX)*numCollBoxes)); //copy tmd structure

	for(loop=0;loop<numCollBoxes;loop++)
	{
/*		if(((collBox[loop].flags)&TYPEPART)==RAMP)
		{
			pM=(ULONG *)(((ULONG)offMesh)+((ULONG)tempFile)+((ULONG)collBox[loop].generalPtr));
			collBox[loop].generalPtr=pM;

			if(!firstRamp)
			{
				firstRamp=pM;
			}

			pM[1]+=(ULONG)firstRamp;
			pM[2]+=(ULONG)firstRamp;

			pFaces=(ULONG *)(pM[1]);
			nFaces=pM[0]>>16;

			pVerts=(VECTOR *)(pM[2]);
			nVerts=pM[0]&0xffff;


			DB("\nFound Ramp: BBOX (%d,%d,%d) to (%d,%d,%d) ",
				collBox[loop].pX, collBox[loop].pY, collBox[loop].pZ,
				collBox[loop].pX+collBox[loop].sX,
				collBox[loop].pY+collBox[loop].sY,
				collBox[loop].pZ+collBox[loop].sZ);
			DB("size (%d,%d,%d)\n", collBox[loop].sX, collBox[loop].sY, collBox[loop].sZ);

			for(p=0; p<nFaces; p++)
			{
				f=pFaces[p]>>8;
				DB("Face[%d/%d]", p, nFaces);

				errorr=FALSE;
				for(v=0; v<3; v++)
				{
					pV=pVerts+(f&0xf);
					f=f>>4;
					
					DB(" (%d,%d,%d)", pV->vx, pV->vy, pV->vz);

					if((pV->vx>collBox[loop].sX)||(pV->vy>collBox[loop].sY)||(pV->vz>collBox[loop].sZ))
						errorr=TRUE;
				}
				DB("\n");
				if(errorr)
				{
					DB("!!!! This one's ruined !!!!\n");
					CRASH;
				}
			}
		}
		*/


		if(((collBox[loop].flags)&TYPEPART)==RAMP)
		{
			pM=(ULONG *)(((ULONG)offMesh)+((ULONG)tempFile)+((ULONG)collBox[loop].rampheader));
			(ULONG*)collBox[loop].rampheader=pM;

			if(!firstRamp)
			{
				firstRamp=pM;
			}

			pM[1]+=(ULONG)firstRamp;
			pM[2]+=(ULONG)firstRamp;

		}
		if (((collBox[loop].flags) & TYPEPART) == SPHERE)
		{
			collBox[loop].sY= collBox[loop].sY;
			collBox[loop].sX=-collBox[loop].sX;
			collBox[loop].sZ=-collBox[loop].sZ;
		}

	}
	return collBox;
}
/***************************************************************************************/
COLLBOX *pMeshColl;
int nMeshColl;

SVECTOR *precalcdNormals;

void setupCollision(char *sFN)
{
//	ULONG *pM;
//	ULONG *pFaces;
//	VECTOR *pVerts;
//	ULONG f,p;
//	int vp;
//	ULONG nFaces, nVerts;
//	VECTOR vrt[3];
//	VECTOR v1,v2,n;
//	int vp;

//	ULONG f;
//	int j;
//	int flags;
//	long pX,pY,pZ;

	ULONG	loop;
	pMeshColl=collBox=collisionLoadMeshCRC(str2CRC(sFN));
	if(!pMeshColl)
	{
		printf("BFF collision %s not present\n",sFN);
		CRASH;
	}
	nMeshColl=numCollBoxes;
//	precalcdNormals=MALLOC(sizeof(SVECTOR)*numCollBoxes,"PRECALCD NORMALS");

	DB("\n%ld Collision boxes\n",numCollBoxes);

// the collision reduction is now performed on the PC, and the offset-2-pointer
// stuff is in the BFF loader

//	strcpy(sBuff, sFN);
//	strcat(sBuff, ".DAT");
//	ReduceCollision(&collBox[0], (64*4096),sBuff);
//	ReduceCollision(&collBox[0]);	//&collBox[0], (64*4096),sBuff);

	// After reduction reduce radius
	for (loop=0;loop<numCollBoxes;loop++)
	{
		/*if ((collBox+loop)->flags==CYLINDER_X)
		{
			(collBox+loop)->sY=(collBox+loop)->sY/2;
			(collBox+loop)->sZ=(collBox+loop)->sZ/2;
			//(collBox+loop)->pX+=(collBox+loop)->sZ;
			(collBox+loop)->pY-=(collBox+loop)->sZ;
			(collBox+loop)->pZ+=(collBox+loop)->sZ;
		}
		if ((collBox+loop)->flags==CYLINDER_Y)
		{
			(collBox+loop)->sX=(collBox+loop)->sX/2;
			(collBox+loop)->sZ=(collBox+loop)->sZ/2;
			(collBox+loop)->pX+=(collBox+loop)->sX;
			(collBox+loop)->pZ+=(collBox+loop)->sZ;
		}
		if ((collBox+loop)->flags==CYLINDER_Z)
		{
			(collBox+loop)->sX=(collBox+loop)->sX/2;
			(collBox+loop)->sY=(collBox+loop)->sY/2;
		}*/


// Moved to "LoadMeshCRC", so it works for platforms, too
/*
		if ( ((collBox+loop)->flags&TYPEPART) ==SPHERE)
		{
			(collBox+loop)->sY=(collBox+loop)->sY;
			(collBox+loop)->sX=-(collBox+loop)->sX;
			(collBox+loop)->sZ=-(collBox+loop)->sZ;
		}
*/



/*		if ( ((collBox+loop)->flags&TYPEPART) ==RAMP)
		{
		(collBox+loop)->boxnum=loop;
		pX=(collBox+loop)->pX/4096;
		pY=(collBox+loop)->pY/4096;
		pZ=(collBox+loop)->pZ/4096;

		pM=(ULONG *)((collBox+loop)->generalPtr);
		nVerts=pM[0]&0xffff;
		nFaces=pM[0]>>16;
		pFaces=(ULONG *)(pM[1]);
		pVerts=(VECTOR *)(pM[2]);


		f=pFaces[0];
		flags=f&6;
		f=f>>8;
		if ((flags==4)||(flags==0)){
			for(j=0; j<3; j++)
				{
				vp=f&(0x0f);
				f=f>>4;
				vrt[j].vx=pVerts[vp].vx/4096;
				vrt[j].vy=pVerts[vp].vy/4096;
				vrt[j].vz=pVerts[vp].vz/4096;


			}
		}
				//this makes a normalised vector 
				SUBVECTOR(&v1, vrt, vrt+1);
				SUBVECTOR(&v2, vrt, vrt+2);
				n.vx=(v1.vy * v2.vz - v1.vz * v2.vy);
				n.vy=(v1.vz * v2.vx - v1.vx * v2.vz);
				n.vz=(v1.vx * v2.vy - v1.vy * v2.vx);
				MakeUnit(&n);
				
				v1.vx = vrt->vx + pX;
				v1.vy = vrt->vy + pY;
				v1.vz = vrt->vz + pZ;

				
				j=DotProduct(&n, &v1); //height of plane at point  

		   precalcdNormals[loop].vx=n.vx;
		   precalcdNormals[loop].vy=n.vy;
		   precalcdNormals[loop].vz=n.vz;
		   precalcdNormals[loop].pad=j;
	}
*/
	}

}
void FreeCollision(){
		FREE(precalcdNormals);
}

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


long FindRampHeight(COLLBOX *pB, long x, long z, long y)   //Improved by ANO  30/6/99
{
	RAMPHEADER *pRampHeader;
	static ULONG *pFaces;
	static VECTOR *pVerts;
	ULONG f,p;
	int vp;
	 ULONG nFaces, nVerts;
	int j,t,flags;
	static VECTOR vrt[3];
	static VECTOR n;
	static VECTOR iPos;
//	long pX=pB->pX, pY=pB->pY, pZ=pB->pZ;
	static VECTOR v1,v2,a; //needed for non-precalc'd normals!!!

	
	int touch=FALSE;
	int htHt=0x7fffffff;
	int htBig=0x7fffffff;
//	#define p2D ((Point2DType*)SCRATCHPAD)
	static Point2DType twoDpoints[4];
	Point2DType *p2D=twoDpoints;
//	SVECTOR *pPrecalcdNormals;
	pRampHeader=pB->rampheader; //generalPtr);

	iPos.vx=x/4096;
	iPos.vy=y/4096;
	iPos.vz=z/4096;

	nVerts=pRampHeader->nVerts;
	nFaces=pRampHeader->nFaces;
	pFaces=pRampHeader->pFaces;
	pVerts=pRampHeader->pVerts;

	for(p=0; p<nFaces; p++)
	{
		f=pFaces[p];

		flags=f&6;
		f=f>>8;

		if ((flags==4)||(flags==0))
		{
			for(j=0; j<3; j++)
			{
				vp=f&(0x0f);
//				v[j]=vp;
				f=f>>4;
				vrt[j].vx=pVerts[vp].vx/4096;
				vrt[j].vy=pVerts[vp].vy/4096;
				vrt[j].vz=pVerts[vp].vz/4096;

				p2D[j].x=(vrt[j].vx)+(pB->pX/4096);
				p2D[j].y=(vrt[j].vz)+(pB->pZ/4096);

			}
			touch=pointInTri(iPos.vx,iPos.vz,p2D);

		}
		else
		{
			touch = 0;
		}
		if (touch)
		{

			if(flags==4)   
			{ // we're only interested in XZ polys for find height
				//DB("Inside XZ, ht=%d\n", htHt);
				htHt = ((vrt[0].vy << 12) + pB->pY) - y;	// must be a vert on the top plane
//				htHt=((pVerts->vy)+pY)-y;
			}
			else //  must be (flags==0)
			{ // test ramp then ...

#ifdef PRECALC_COLLISION

				j=pRampHeader->plane;
				n.vx=pRampHeader->normal_x;	  //would be good, not to have to copy this stuff!
				n.vy=pRampHeader->normal_y;
				n.vz=pRampHeader->normal_z;
				t=DotProduct(&n, &iPos)-j; //height of entry x,y,z
#else
//#ifndef PRECALC_COLLISION
//#endif

				SUBVECTOR(&v1, vrt, vrt+1);
				SUBVECTOR(&v2, vrt, vrt+2);
				n.vx=(v1.vy * v2.vz - v1.vz * v2.vy);
				n.vy=(v1.vz * v2.vx - v1.vx * v2.vz);
				n.vz=(v1.vx * v2.vy - v1.vy * v2.vx);
				MakeUnit(&n);
				a.vx = vrt->vx + pB->pX/4096;
				a.vy = vrt->vy + pB->pY/4096;
				a.vz = vrt->vz + pB->pZ/4096;
				j=DotProduct(&n, &a); //height of plane at point  
				t=DotProduct(&n, &iPos)-j; //height of entry x,y,z
#endif
// 	 	printf("real x,y,z,j=(%d,%d,%d,%d),precalcd=(%d,%d,%d,%d)\n",n.vx,n.vy,n.vz,j,
//		   pRampHeader->normal_x,pRampHeader->normal_y,
//		   pRampHeader->normal_z,pRampHeader->plane);

				if(n.vy) //temp bodge to stop div by zero
				{
					t=t*4096;
					t=t/n.vy;
				}
				else	t=0;
				htHt=-(t*4096);
			}
			if(htHt<htBig) htBig=htHt; //under plane, sets on plane
		}
	}
	//DB("Above %d\n", htBig);
	return(htBig);
} 

/***************************************************************************************/
void getHeightOfOneBox(COLLBOX *pB, long *pVal,VECTOR *vect)
{
	long diff1,diff2,temp;
//	VECTOR d;

	//if ( (pD==&cameraColl || pD==&cameraProbeColl[0] || pD==&cameraProbeColl[1]) && (pB->flags&SPECIALPART)==C_NOCAMCOLLISION )
	//{
	//	//printf ("cam ignor\n");
	//	return;
	//}

	switch(pB->flags&TYPEPART)
	{
		case BOX:
			if ( (vect->vx>=pB->pX) && (vect->vx<=(pB->pX+pB->sX)) ) // inside on x
			{
				if ( (vect->vz>=pB->pZ) && (vect->vz<=(pB->pZ+pB->sZ)) ) // inside on z
				{
					temp=(pB->pY+pB->sY)-vect->vy;
					if ( ((*pVal) > temp ) && temp>-40960) (*pVal)=temp;	// the -10 (*4096) is an under-the-roof frig
				}
			}
			break;

		case RAMP:
			if ( (vect->vx>=pB->pX) && (vect->vx<=(pB->pX+pB->sX)) ) // inside on x
			{
				if ( (vect->vz>=(pB->pZ)) && (vect->vz<=(pB->pZ+pB->sZ)) ) // inside on z
				{
					temp=FindRampHeight(pB, vect->vx,vect->vz,vect->vy);  //YES, these are in a funny order!
					if((*pVal)>temp && temp>-40960) (*pVal)=temp;	// the -10 (*4096) is an under-the-roof frig
				}
			}
			break;

		case CYLINDER_X:
			if ( (vect->vx>=pB->pX) && (vect->vx<=(pB->pX+pB->sX)) ) // inside on x
			{
				if ( (vect->vz>=pB->pZ) && (vect->vz<=(pB->pZ+pB->sZ)) ) // inside on z
				{
					diff1=vect->vz-(pB->pZ+(pB->sZ/2));
					diff2=FindHeight( (pB->sZ/2) , diff1);
					temp=(pB->pY+pB->sY/2)-diff2-vect->vy;
					if ( ((*pVal) > temp) && temp>-40960) (*pVal)=temp;	// the -10 (*4096) is an under-the-roof frig
				}
			}
			break;

		case CYLINDER_Z:
			if ( (vect->vz>pB->pZ) && (vect->vz<(pB->pZ+pB->sZ)) ) // inside on z
			{
				if ( (vect->vx>(pB->pX-pB->sX)) && (vect->vx<(pB->pX+pB->sX)) ) // inside on x
				{
					diff1=vect->vx-(pB->pX+(pB->sX/2));
					diff2=FindHeight( (pB->sX/2) , diff1);
					temp=(pB->pY+pB->sY/2)-diff2-vect->vy;
					if ( ((*pVal) > temp) && temp>-40960)  (*pVal)=temp;	// the -10 (*4096) is an under-the-roof frig
				}
			}
			break;

		case CYLINDER_Y:
			if ( (vect->vx>(pB->pX)) && (vect->vx<(pB->pX+pB->sX)) ) // inside on x
			{
				if ( (vect->vz>(pB->pZ)) && (vect->vz<(pB->pZ+pB->sZ)) ) // inside on z
				{
					temp=(pB->pY+pB->sY)-vect->vy;
					if ( ((*pVal) > temp) && temp>-40960) (*pVal)=temp;	// the -10 (*4096) is an under-the-roof frig
				}
			}
			break;

		case SPHERE:

			if ( (vect->vx>=pB->pX) && (vect->vx<=(pB->pX-pB->sX)) ) // inside on x
			{
				if ( (vect->vz>=(pB->pZ)) && (vect->vz<=(pB->pZ-pB->sZ)) ) // inside on z
				{
					//d.vx=x2-(pB->pX-(pB->sX/2));
					//d.vz=z2-(pB->pZ-(pB->sZ/2));
					//d.vy=0;
					//diff1=Magnitude(&d);
					diff1 = Magnitude2D(vect->vx-(pB->pX-(pB->sX/2)),vect->vz-(pB->pZ-(pB->sZ/2)));
					
					diff2=FindHeight( (pB->sX/2) , diff1);
					temp=( ((pB->pY+pB->sY/2)-diff2)-vect->vy);
					if ( ((*pVal) > temp) && temp>-40960) (*pVal)=temp;	// the -10 (*4096) is an under-the-roof frig
				}
			}
			break;
		default:
			ASSERT(0); // This assert is set to always fail because we shouldn't ever be here
			break;
  	}

}
/////////////////////////////////////////////////////////////////////////////////////////
long getHeightAt(long x,long y,long z)
{
	long	x1,y1,z1,value;//,diff1,diff2;
	VECTOR vect2;
	long	rval;
//	COLLBOX	*pB;
	ULONG	collBoxPos;
	static ULONG	*collptr,*collptr1;

	static DYNCOLLBOX *ptr;

	static COLLBOX cB;  //too big to be a normal local (fast stack issue!)
	static COLLBOX *pB=&cB;
	static COLLBOX *pB1;

	vect2.vx=x;
	vect2.vy=y;
	vect2.vz=z;
	x-=WorldBFFcoll->startX;
	y-=WorldBFFcoll->startY;
	z-=WorldBFFcoll->startZ;		   

	x1=x/WorldBFFcoll->xStepLen;
	y1=y/WorldBFFcoll->yStepLen;
	z1=z/WorldBFFcoll->zStepLen;

	if (x1<0 || x1>=WorldBFFcoll->xSteps) return(-1);	// Out of bounds can not hit anything
//	if (y1<0 || y1>=WorldBFFcoll->ySteps) return(-1);
	if (y1>=WorldBFFcoll->ySteps) return(-1);
	if (z1<0 || z1>=WorldBFFcoll->zSteps) return(-1);


	if (y1 < 0) y1 = 0;

/* does this actually do anything?  */

// Yes it does...Get height of moving platforms, natch
// Um. Except it doesn;t work & never has AFAIK.

	{
		rval = 0x7fffffff;
		value = 0x7fffffff;
		for(ptr = dyncollList.head.next; ptr != &dyncollList.head; ptr = ptr->next)
		{
			int l;

			if(!(ptr->active))
				continue;

			for(l=0; l<ptr->nCollBoxes; l++)
			{
				pB1=(ptr->pBoxes) + l;

				pB->flags = pB1->flags;
				pB->sX = pB1->sX;
				pB->sY = pB1->sY;
				pB->sZ = pB1->sZ;
				pB->rampheader = pB1->rampheader;
				pB->pX = pB1->pX + ptr->cumPos.vx;
				pB->pY = pB1->pY + ptr->cumPos.vy;
				pB->pZ = pB1->pZ + ptr->cumPos.vz;

				getHeightOfOneBox(pB, &value,&vect2);
				if(value < rval)
					rval = value;

//				getHeightOfOneBox((ptr->pBoxes)+l, &value,&vect2);
			}
		}
	}

	while(y1 < WorldBFFcoll->ySteps)
	{
		collBoxPos=( x1+(z1*WorldBFFcoll->xSteps)+(y1*(WorldBFFcoll->xSteps*WorldBFFcoll->zSteps)) );
		collptr=(ULONG *)reducedCollBox[collBoxPos];

		//if (collptr==NULL) return(-1);	// No boxes in this voxel to test (this may need to change)

		if (collptr)
		{
			if (((ULONG)collptr)<0x80000000)	// Check for one or >one
			{

//				value=99999999;

				collptr=(ULONG *)(reducedCollBox[collBoxPos]);
//				pB=(COLLBOX*)collptr;
				// Check if point can fall on box
				// Need to add checks for different types

				getHeightOfOneBox((COLLBOX*)collptr, &value,&vect2);
//				if(value != 99999999)
				if(value < rval)
					rval = value;


			}
			else
			{	// multiple boxes to deal with
//				value=99999999;

				collptr = (ULONG *)(  ((ULONG)(collptr)) & 0x7fffffff);	// mask off collptr's top bit
				collptr1= (ULONG *)(*collptr);

				do	// the "none" case has already been dealt with
				{
					//pB=(COLLBOX*)collptr1;
					// Check if point can fall on box
					// Need to add checks for different types

					getHeightOfOneBox((COLLBOX*)collptr1, &value,&vect2);
					if(value < rval)
						rval = value;

					collptr++;
					collptr1=(ULONG *)(*collptr);
				}
				while (collptr1!=NULL);

//				if(value != 99999999)
//					return value;
			}

			if(rval < 0x7fffffff)	// if we've got a valid height within this zone, ok, return
				return rval;

		}
		y1++;
	}
//	return(-1);
	return rval;
}

/////////////////////////////////////////////////////////////////////////////////////////
long getHeightAtCam(long x,long y,long z)
{
	long	x1,y1,z1,value;//,diff1,diff2;
	VECTOR vect2;
	COLLBOX	*pB;
	ULONG	collBoxPos;
	ULONG	*collptr,*collptr1;
//	DYNCOLLBOX *ptr;
	vect2.vx=x;
	vect2.vy=y;
	vect2.vz=z;
	x-=WorldBFFcoll->startX;
	y-=WorldBFFcoll->startY;
	z-=WorldBFFcoll->startZ;		   

	x1=x/WorldBFFcoll->xStepLen;
	y1=y/WorldBFFcoll->yStepLen;
	z1=z/WorldBFFcoll->zStepLen;

	if (x1<0 || x1>=WorldBFFcoll->xSteps) return(-1);	// Out of bounds can not hit anything
//	if (y1<0 || y1>=WorldBFFcoll->ySteps) return(-1);
	if (y1>=WorldBFFcoll->ySteps) return(-1);
	if (z1<0 || z1>=WorldBFFcoll->zSteps) return(-1);

	if (y1 < 0) y1 = 0;

	while(y1 < WorldBFFcoll->ySteps)
	{
		collBoxPos=( x1+(z1*WorldBFFcoll->xSteps)+(y1*(WorldBFFcoll->xSteps*WorldBFFcoll->zSteps)) );
		collptr=(ULONG *)reducedCollBox[collBoxPos];

		//if (collptr==NULL) return(-1);	// No boxes in this voxel to test (this may need to change)

		if (collptr)
		{
			if (((ULONG)collptr)<0x80000000)	// Check for one or >one
			{
				value=99999999;
				collptr=(ULONG *)(reducedCollBox[collBoxPos]);
				pB=(COLLBOX*)collptr;

				// Check if point can fall on box
				// Need to add checks for different types
				if ( (pB->flags&SPECIALPART)!=C_NOCAMCOLLISION)
					getHeightOfOneBox(pB, &value,&vect2);
				if(value != 99999999)
					return value;


			}
			else
			{	// multiple boxes to deal with
				value=99999999;

				collptr = (ULONG *)(  ((ULONG)(collptr)) & 0x7fffffff);	// mask off collptr's top bit
				collptr1= (ULONG *)(*collptr);

				do	// the "none" case has already been dealt with
				{
					pB=(COLLBOX*)collptr1;
					// Check if point can fall on box
					// Need to add checks for different types

					if ( (pB->flags&SPECIALPART)!=C_NOCAMCOLLISION)
						getHeightOfOneBox(pB, &value,&vect2);


					collptr++;
					collptr1=(ULONG *)(*collptr);
				}
				while (collptr1!=NULL);

				if(value != 99999999)
					return value;
			}
		}
		y1++;
	}
	return(-1);
}

/*****************************************************************************************/
long getHeightAtSlow(long x,long y,long z)
{
	long	x1,y1,z1,value;//,diff1,diff2;
	VECTOR vect2;
	COLLBOX	*pB;
	ULONG	collBoxPos;
	ULONG	*collptr,*collptr1;
//	DYNCOLLBOX *ptr;
	vect2.vx=x;
	vect2.vy=y;
	vect2.vz=z;
	x-=WorldBFFcoll->startX;
	y-=WorldBFFcoll->startY;
	z-=WorldBFFcoll->startZ;		   

	x1=x/WorldBFFcoll->xStepLen;
	y1=y/WorldBFFcoll->yStepLen;
	z1=z/WorldBFFcoll->zStepLen;

	if (x1<0 || x1>=WorldBFFcoll->xSteps) return(-1);	// Out of bounds can not hit anything
	if (y1>=WorldBFFcoll->ySteps) return(-1);
	if (z1<0 || z1>=WorldBFFcoll->zSteps) return(-1);


	if (y1 < 0) y1 = 0;

/*	does this actually do anything?
	for(ptr = dyncollList.head.next; ptr != &dyncollList.head; ptr = ptr->next)
	{
		int l;
		if(!(ptr->active))
			continue;
		for(l=0; l<ptr->nCollBoxes; l++)
			getHeightOfOneBox((ptr->pBoxes)+l, &value,&vect2);
	}
*/


	while(y1 < WorldBFFcoll->ySteps)
	{
		collBoxPos=( x1+(z1*WorldBFFcoll->xSteps)+(y1*(WorldBFFcoll->xSteps*WorldBFFcoll->zSteps)) );
		collptr=(ULONG *)reducedCollBox[collBoxPos];

		if (collptr==NULL) return(-1);	// No boxes in this voxel to test (this may need to change)

		if (((ULONG)collptr)<0x80000000)	// Check for one or >one
		{
			value=99999999;
			collptr=(ULONG *)(reducedCollBox[collBoxPos]);
			pB=(COLLBOX*)collptr;
			getHeightOfOneBox(pB, &value,&vect2);
			if(value != 99999999)
				return value;
		}
		else
		{	// multiple boxes to deal with
			value=99999999;

			collptr = (ULONG *)(  ((ULONG)(collptr)) & 0x7fffffff);	// mask off collptr's top bit
			collptr1= (ULONG *)(*collptr);

			do	// the "none" case has already been dealt with
			{
				pB=(COLLBOX*)collptr1;
				getHeightOfOneBox(pB, &value,&vect2);
				collptr++;
				collptr1=(ULONG *)(*collptr);
			}
			while (collptr1!=NULL);

			if(value != 99999999)
				return value;
		}
		y1++;
	}
	return(-1);
}



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

// at the moment, this just treats all boxes as boxes. tbd - do properly (!)
// the thing that uses this is Bovva's missiles

long isPointSolid(long x,long y,long z)
{
	long	x1,y1,z1,x2,y2,z2,value;
	COLLBOX	*pB;
	ULONG	collBoxPos;
	ULONG	*collptr,*collptr1;

	x2=x;
	y2=y;
	z2=z;
	x-=WorldBFFcoll->startX;
	y-=WorldBFFcoll->startY;
	z-=WorldBFFcoll->startZ;		   

	x1=x/WorldBFFcoll->xStepLen;
	y1=y/WorldBFFcoll->yStepLen;
	z1=z/WorldBFFcoll->zStepLen;

	if (x1<0 || x1>=WorldBFFcoll->xSteps) return(0);	// Out of bounds can not hit anything
	if (y1<0 || y1>=WorldBFFcoll->ySteps) return(0);
	if (z1<0 || z1>=WorldBFFcoll->zSteps) return(0);


#ifdef TESTALL
	for(collBoxPos = 0; collBoxPos < nMeshColl; collBoxPos++)
	{
		pB=pMeshColl+collBoxPos;
		collptr = (ULONG *)pB;

#else
	collBoxPos=( x1+(z1*WorldBFFcoll->xSteps)+(y1*(WorldBFFcoll->xSteps*WorldBFFcoll->zSteps)) );
	collptr=(ULONG *)reducedCollBox[collBoxPos];

	if (collptr==NULL)
	{
		return(0);	// No boxes in this voxel to test - the point isn't solid
	}

	if (((ULONG)collptr)<0x80000000)	// Check for one or >one
	{
		collptr=(ULONG *)(reducedCollBox[collBoxPos]);
		pB=(COLLBOX*)collptr;
#endif
		// Check if point can fall on box
		// Need to add checks for different types

//		if( (pB->flags&TYPEPART)==BOX )
		{
			if ( (x2>pB->pX) && (x2<(pB->pX+pB->sX)) ) // inside on x
			{
				if ( (z2>pB->pZ) && (z2<(pB->pZ+pB->sZ)) ) // inside on z
				{
					if ( (y2<pB->pY) && (y2>(pB->pY+pB->sY)) ) // inside on z
					{
						if( (pB->flags&TYPEPART)==BOX )
						{
							return 1;
						}
						else
						{
							VECTOR pos;
							pos.vx = x;
							pos.vy = y;
							pos.vz = z;
							value=0x7fffffff;
							getHeightOfOneBox(pB, &value, &pos);

							if(value != 0x7fffffff && value + pos.vy <= pB->pY)
							{
								return 1;
							}
						}
					}
				}
			}
		}
	}

#ifndef TESTALL

	else
	{	// multiple boxes to deal with
//		value=99999999;
		value=0x7fffffff;

		collptr = (ULONG *)(  ((ULONG)(collptr)) & 0x7fffffff);	// mask off collptr's top bit
		collptr1= (ULONG *)(*collptr);

		do	// the "none" case has already been dealt with
		{
			pB=(COLLBOX*)collptr1;	// Check if point can fall on box
									// Need to add checks for different types
//			if( (pB->flags&TYPEPART)==BOX )
			{
				if ( (x2>pB->pX) && (x2<(pB->pX+pB->sX)) ) // inside on x
				{
					if ( (z2>pB->pZ) && (z2<(pB->pZ+pB->sZ)) ) // inside on z
					{
						if ( (y2<pB->pY) && (y2>(pB->pY+pB->sY)) ) // inside on y
						{
							if( (pB->flags&TYPEPART)==BOX )
							{
								return 1;
							}
							else	// do a height check for ramps
							{
								VECTOR pos;
								pos.vx = x;
								pos.vy = y;
								pos.vz = z;
								getHeightOfOneBox(pB, &value, &pos);

								if(value != 0x7fffffff && value + pos.vy <= pB->pY)
								{
									return 1;
								}
							}
						}
					}
				}
			}
			collptr++;
			collptr1=(ULONG *)(*collptr);
		}
		while (collptr1!=NULL);
	}
#endif
	return(0);
}


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

//Not if these need to be globals!
VECTOR	slideNormal;
VECTOR v0v2, v0v1, velDiff;
VECTOR vRebound[MAXCOLLOSIONS], planeRebound;

void collboxCheckOneBox(COLLBOX *pB, COLLDATA *pD, int *pnPolysHit)
{
	long cx=pD->pPos->vx;
//	long cy=pD->pPos->vy;
	long cz=pD->pPos->vz;
	long radius=pD->radius;
	if ( (pD==&cameraColl || pD==&cameraProbeColl[0] || pD==&cameraProbeColl[1]) && (pB->flags&SPECIALPART)==C_NOCAMCOLLISION )
	{
		//printf ("cam ignor\n");
		return;
	}

//This simple box check only works on Boxes & ramps. (which is most cases!)
	//if ( ((pB->flags&TYPEPART)!=(

	 if ( ((pB->flags&TYPEPART)==RAMP)||((pB->flags&TYPEPART)==BOX) )
	{
		if (cx+radius < pB->pX)
		{
			if (pD->oldPos.vx+radius < pB->pX)
				return; 			//too far left
		}
		if (cx-radius > (pB->pX+pB->sX))
		{
			if (pD->oldPos.vx-radius > (pB->pX+pB->sX))
				return;  //too far right
		}
		if (cz+radius < pB->pZ)
		{
			if (pD->oldPos.vz+radius < pB->pZ)
				return; 			//too near
		}
		if (cz-radius > (pB->pZ+pB->sZ))
		{
			if (pD->oldPos.vz-radius > (pB->pZ+pB->sZ))

			return; 	//too far
		}
	}

//		if (cy+radius>pB->pY)return;  //y is odd!	//too low
//		if (cy-radius<(pB->pY+pB->sY)) return; 		//too high

	if((pB->flags&TYPEPART)==BOX)
	{
		if(CheckCorners(pB, pD, &pHitData[*pnPolysHit]))
		{
			pD->nCornerHits++;
			(*pnPolysHit)++;
			pD->flags|=pB->flags>>8;
			if (pD==&gloveColl)
			{
				if ( (pB->flags&SPECIALPART) & (C_CONVEYERXP|C_CONVEYERXN|C_CONVEYERZP|C_CONVEYERZN) )
				{
					//printf ("glove on conveyer\n");
					GloveCtrl.onConveyer=doConveyerStuff(pD->flags);
					GloveCtrl.conveyerTimer=6;
					GloveCtrl.conveyerNormal.vx=0;
					GloveCtrl.conveyerNormal.vz=0;
				}
			}
			else if (pD==&ballColl)
			{
				if ( (pB->flags&SPECIALPART) & (C_CONVEYERXP|C_CONVEYERXN|C_CONVEYERZP|C_CONVEYERZN) )
				{
					//printf ("ball on conveyer\n");
					BallCtrl.onConveyer=doConveyerStuff(pD->flags);
					BallCtrl.conveyerTimer=7;
					BallCtrl.conveyerNormal.vx=0;
					BallCtrl.conveyerNormal.vz=0;
				}
			}
		}
		// Check Edges
		else if(CheckEdges(pB, pD, &pHitData[*pnPolysHit]))
		{
			(*pnPolysHit)++;
			pD->flags|=pB->flags>>8;
			if (pD==&gloveColl)
			{
				if ( (pB->flags&SPECIALPART) & (C_CONVEYERXP|C_CONVEYERXN|C_CONVEYERZP|C_CONVEYERZN) )
				{
					//printf ("glove on conveyer\n");
					GloveCtrl.onConveyer=doConveyerStuff(pD->flags);
					GloveCtrl.conveyerTimer=6;
					GloveCtrl.conveyerNormal.vx=0;
					GloveCtrl.conveyerNormal.vz=0;
				}
			}
			else if (pD==&ballColl)
			{
				if ( (pB->flags&SPECIALPART) & (C_CONVEYERXP|C_CONVEYERXN|C_CONVEYERZP|C_CONVEYERZN) )
				{
					//printf ("ball on conveyer\n");
					BallCtrl.onConveyer=doConveyerStuff(pD->flags);
					BallCtrl.conveyerTimer=7;
					BallCtrl.conveyerNormal.vx=0;
					BallCtrl.conveyerNormal.vz=0;
				}
			}
		}
		// Check Planes
		else if(CheckPlanes(pB, pD, &pHitData[*pnPolysHit]))
		{
			(*pnPolysHit)++;
			pD->nPlaneHits++;
			pD->flags|=pB->flags>>8;
			if (pD==&gloveColl)
			{
				if ( (pB->flags&SPECIALPART) & (C_CONVEYERXP|C_CONVEYERXN|C_CONVEYERZP|C_CONVEYERZN) )
				{
					//printf ("glove on conveyer\n");
					GloveCtrl.onConveyer=doConveyerStuff(pD->flags);
					GloveCtrl.conveyerTimer=6;
					GloveCtrl.conveyerNormal.vx=0;
					GloveCtrl.conveyerNormal.vz=0;
				}
			}
			else if (pD==&ballColl)
			{
				if ( (pB->flags&SPECIALPART) & (C_CONVEYERXP|C_CONVEYERXN|C_CONVEYERZP|C_CONVEYERZN) )
				{
					//printf ("ball on conveyer\n");
					BallCtrl.onConveyer=doConveyerStuff(pD->flags);
					BallCtrl.conveyerTimer=7;
					BallCtrl.conveyerNormal.vx=0;
					BallCtrl.conveyerNormal.vz=0;
				}
			}
		}
	}
	else if ( (pB->flags&TYPEPART)==RAMP )
	{
		// check RAMPS (PITA)
		if(CheckRamps(pB, pD, &pHitData[*pnPolysHit]))
		{
			//(*pnPolysHit)++;

			if ( (pB->flags&SPECIALPART)==C_ICE)
			{
				slideNormal.vx+=pHitData[*pnPolysHit].normal.vx;
				slideNormal.vy+=pHitData[*pnPolysHit].normal.vy;
				slideNormal.vz+=pHitData[*pnPolysHit].normal.vz;
				//slideNormal.vx=pHitData[*pnPolysHit].normal.vx;
				//slideNormal.vy=pHitData[*pnPolysHit].normal.vy;
				//slideNormal.vz=pHitData[*pnPolysHit].normal.vz;

				MakeUnit(&slideNormal);
			}


			pD->flags|=pB->flags>>8;
			pD->nRampHits++;
			if (pD==&gloveColl)
			{
				if ( (pB->flags&SPECIALPART) & (C_CONVEYERXP|C_CONVEYERXN|C_CONVEYERZP|C_CONVEYERZN) )
				{
					//printf ("glove on conveyer\n");
					GloveCtrl.onConveyer=doConveyerStuff(pD->flags);
					GloveCtrl.conveyerTimer=6;
					GloveCtrl.conveyerNormal.vx=pHitData[*pnPolysHit].normal.vx;
					GloveCtrl.conveyerNormal.vy=pHitData[*pnPolysHit].normal.vy;
					GloveCtrl.conveyerNormal.vz=pHitData[*pnPolysHit].normal.vz;
				}
			}
			else if (pD==&ballColl)
			{
				if ( (pB->flags&SPECIALPART) & (C_CONVEYERXP|C_CONVEYERXN|C_CONVEYERZP|C_CONVEYERZN) )
				{
					//printf ("ball on conveyer\n");
					BallCtrl.onConveyer=doConveyerStuff(pD->flags);
					BallCtrl.conveyerTimer=7;
					BallCtrl.conveyerNormal.vx=pHitData[*pnPolysHit].normal.vx;
					BallCtrl.conveyerNormal.vy=pHitData[*pnPolysHit].normal.vy;
					BallCtrl.conveyerNormal.vz=pHitData[*pnPolysHit].normal.vz;
				}
			}
			(*pnPolysHit)++;
		}
	}
	else if ( ((pB->flags&TYPEPART)==CYLINDER_X) || ((pB->flags&TYPEPART)==CYLINDER_Y) || ((pB->flags&TYPEPART)==CYLINDER_Z) )
	{
		if(CheckCylinders(pB, pD, &pHitData[*pnPolysHit]))
		{
			(*pnPolysHit)++;
			pD->flags|=pB->flags>>8;
		}
	}
	else if ( (pB->flags&TYPEPART)==SPHERE )
	{
		if(CheckSpheres(pB, pD, &pHitData[*pnPolysHit]))
		{
			(*pnPolysHit)++;
			pD->flags|=pB->flags>>8;
		}
	}
}

/******************************************************************************************/
void collboxCheckOneMovingBox(COLLBOX *pB1, COLLDATA *pD, int *pnPolysHit, VECTOR *pCumPos, VECTOR *pOldPos)
{
static COLLBOX cB;

	if ( (pD==&cameraColl || pD==&cameraProbeColl[0] || pD==&cameraProbeColl[1]) && (cB.flags&SPECIALWITHMOVE)==C_NOCAMCOLLISION ){
		//if (pD==&cameraColl){printf ("cam ignor flags %d nocam %d\n",(cB.flags&SPECIALWITHMOVE),C_NOCAMCOLLISION);}
		return;
	}

	//if (pD==&cameraColl) printf ("hmm\n");


// copy the stuff that doesn't get modified
	cB.sX = pB1->sX;
	cB.sY = pB1->sY;
	cB.sZ = pB1->sZ;
	cB.flags = pB1->flags;
	cB.rampheader = pB1->rampheader;

// do the maths for the stuff that changes during the copy...
// add offset to collbox, so it is movable

	cB.pX = pB1->pX + pCumPos->vx;
	cB.pY = pB1->pY + pCumPos->vy;
	cB.pZ = pB1->pZ + pCumPos->vz;

	cB.oldpX = pB1->pX + pOldPos->vx;
	cB.oldpY = pB1->pY + pOldPos->vy;
	cB.oldpZ = pB1->pZ + pOldPos->vz;

	
	switch(cB.flags&TYPEPART){

		case BOX:
					if(CheckCorners(&cB, pD, &pHitData[*pnPolysHit]))
					{
						pD->nCornerHits++;
						(*pnPolysHit)++;
						pD->flags|=(cB.flags&SPECIALWITHMOVE)>>8;

						if (pD==&gloveColl)
						{
							if ( (cB.flags&SPECIALPART) & (C_CONVEYERXP|C_CONVEYERXN|C_CONVEYERZP|C_CONVEYERZN) )
							{
								//printf ("glove on conveyer\n");
								GloveCtrl.onConveyer=doConveyerStuff(pD->flags);
								GloveCtrl.conveyerTimer=6;
								GloveCtrl.conveyerNormal.vx=0;
								GloveCtrl.conveyerNormal.vz=0;
							}
						}
						else if (pD==&ballColl)
						{
							if ( (cB.flags&SPECIALPART) & (C_CONVEYERXP|C_CONVEYERXN|C_CONVEYERZP|C_CONVEYERZN) )
							{
								//printf ("ball on conveyer\n");
								BallCtrl.onConveyer=doConveyerStuff(pD->flags);
								BallCtrl.conveyerTimer=7;
								BallCtrl.conveyerNormal.vx=0;
								BallCtrl.conveyerNormal.vz=0;
							}
						}
					}
					// Check Edges
					else if(CheckEdges(&cB, pD, &pHitData[*pnPolysHit]))
					{
						(*pnPolysHit)++;
						pD->flags|=(cB.flags&SPECIALWITHMOVE)>>8;
						if (pD==&gloveColl)
						{
							if ( (cB.flags&SPECIALPART) & (C_CONVEYERXP|C_CONVEYERXN|C_CONVEYERZP|C_CONVEYERZN) )
							{
								//printf ("glove on conveyer\n");
								GloveCtrl.onConveyer=doConveyerStuff(pD->flags);
								GloveCtrl.conveyerTimer=6;
								GloveCtrl.conveyerNormal.vx=0;
								GloveCtrl.conveyerNormal.vz=0;
							}
						}
						else if (pD==&ballColl)
						{
							if ( (cB.flags&SPECIALPART) & (C_CONVEYERXP|C_CONVEYERXN|C_CONVEYERZP|C_CONVEYERZN) )
							{
								//printf ("ball on conveyer\n");
								BallCtrl.onConveyer=doConveyerStuff(pD->flags);
								BallCtrl.conveyerTimer=7;
								BallCtrl.conveyerNormal.vx=0;
								BallCtrl.conveyerNormal.vz=0;
							}
						}
			
					}
					// Check Planes
					else if(CheckPlanes(&cB, pD, &pHitData[*pnPolysHit]))
					{
						(*pnPolysHit)++;
						pD->nPlaneHits++;
						pD->flags|=(cB.flags&SPECIALWITHMOVE)>>8;
						if (pD==&gloveColl)
						{
							if ( (cB.flags&SPECIALPART) & (C_CONVEYERXP|C_CONVEYERXN|C_CONVEYERZP|C_CONVEYERZN) )
							{
								//printf ("glove on conveyer\n");
								GloveCtrl.onConveyer=doConveyerStuff(pD->flags);
								GloveCtrl.conveyerTimer=6;
								GloveCtrl.conveyerNormal.vx=0;
								GloveCtrl.conveyerNormal.vz=0;
								}
						}
						else if (pD==&ballColl)
						{
							if ( (cB.flags&SPECIALPART) & (C_CONVEYERXP|C_CONVEYERXN|C_CONVEYERZP|C_CONVEYERZN) )
							{
								//printf ("ball on conveyer\n");
								BallCtrl.onConveyer=doConveyerStuff(pD->flags);
								BallCtrl.conveyerTimer=7;
								BallCtrl.conveyerNormal.vx=0;
								BallCtrl.conveyerNormal.vz=0;
							}
						}
		
					}
			break;
			
			case  RAMP:
					if(CheckRamps(&cB, pD, &pHitData[*pnPolysHit]))
					{
						pD->flags|=(cB.flags&SPECIALWITHMOVE)>>8;
						pD->nRampHits++;
						if (pD==&gloveColl)
						{
							if ( (cB.flags&SPECIALPART) & (C_CONVEYERXP|C_CONVEYERXN|C_CONVEYERZP|C_CONVEYERZN) )
							{
								//printf ("glove on conveyer\n");
								GloveCtrl.onConveyer=doConveyerStuff(pD->flags);
								GloveCtrl.conveyerTimer=6;
								GloveCtrl.conveyerNormal.vx=pHitData[*pnPolysHit].normal.vx;
								GloveCtrl.conveyerNormal.vy=pHitData[*pnPolysHit].normal.vy;
								GloveCtrl.conveyerNormal.vz=pHitData[*pnPolysHit].normal.vz;
							}
						}
						else if (pD==&ballColl)
						{
							if ( (cB.flags&SPECIALPART) & (C_CONVEYERXP|C_CONVEYERXN|C_CONVEYERZP|C_CONVEYERZN) )
							{
								//printf ("ball on conveyer\n");
								BallCtrl.onConveyer=doConveyerStuff(pD->flags);
								BallCtrl.conveyerTimer=7;
								BallCtrl.conveyerNormal.vx=pHitData[*pnPolysHit].normal.vx;
								BallCtrl.conveyerNormal.vy=pHitData[*pnPolysHit].normal.vy;
								BallCtrl.conveyerNormal.vz=pHitData[*pnPolysHit].normal.vz;
							}
						}
						(*pnPolysHit)++;
					}
			break;
			case CYLINDER_X:
			case CYLINDER_Y:
			case CYLINDER_Z:
					if(CheckCylinders(&cB, pD, &pHitData[*pnPolysHit]))
					{
						(*pnPolysHit)++;
						pD->flags|=(cB.flags&SPECIALWITHMOVE)>>8;
					}
			break;
			case SPHERE:
					if(CheckSpheres(&cB, pD, &pHitData[*pnPolysHit]))
					{
						(*pnPolysHit)++;
						pD->flags|=(cB.flags&SPECIALWITHMOVE)>>8;
					}
			break;
			default:
					//printf("Error - single moving box had a coll box. not described properly!\n");
			break;
			}
}


/*************************************************************************************/
int collboxCheckSphere(COLLDATA *pD)
{
	COLLBOX	*pB;
	long	x1;
	long	y1;
	long	z1,loop;
	int		nPolysHit=0;
	int		i,p,hi,low;
	static VECTOR	collPos; //,tempVel,tempVec,tempVec1;
	long	magv0v1;
	int		reboundcount; //,ctr;
	ULONG	flag=FALSE;
	ULONG	collBoxPos;
	ULONG	*collptr,*collptr1;
//	HITDATA *phitdata;
	BEHAVIOUR_PHYSICS	*Physics;
	DYNCOLLBOX *ptr;
	static VECTOR vTempRebound;

	if (pD==&ballColl)
	{
		BallCtrl.onSticky=FALSE;
	}

	pD->nRampHits=0;
	pD->nPlaneHits=0;
	pD->nCornerHits=0;
	pD->nEdgeHits=0;
	pD->flags=0;
	pD->nHitPlats=0;

	slideNormal.vx=0;
	slideNormal.vy=0;
	slideNormal.vz=0;

	x1=pD->pPos->vx-WorldBFFcoll->startX;
	y1=pD->pPos->vy-WorldBFFcoll->startY;
	z1=pD->pPos->vz-WorldBFFcoll->startZ;

	if (pad[0]&PAD_SELECT) flag=1;

	x1/=WorldBFFcoll->xStepLen;
	y1/=WorldBFFcoll->yStepLen;
	z1/=WorldBFFcoll->zStepLen;

#ifdef SHITLOADSOFDEBUG
	if (pD==&gloveColl) printf ("glove starting collision run\n");
#endif

#ifndef TESTALL
	if (x1<0 || x1>=WorldBFFcoll->xSteps) return (FALSE);
	if (y1<0 || y1>=WorldBFFcoll->ySteps) return (FALSE);
	if (z1<0 || z1>=WorldBFFcoll->zSteps) return (FALSE);
#else
	printf("startxyz = %d %d %d\n",WorldBFFcoll->startX,WorldBFFcoll->startY,WorldBFFcoll->startZ);
	printf("slenxyz  = %d %d %d\n",WorldBFFcoll->xStepLen,WorldBFFcoll->yStepLen,WorldBFFcoll->zStepLen);
	printf("xyza = %d %d %d\n",pD->pPos->vx,pD->pPos->vy,pD->pPos->vz);
	printf("xyz1 = %d %d %d\n",x1,y1,z1);
#endif

	pD->normal.vx=0;
	pD->normal.vy=0;
	pD->normal.vz=0;

	collBoxPos=( x1+(z1*WorldBFFcoll->xSteps)+(y1*(WorldBFFcoll->xSteps*WorldBFFcoll->zSteps)) );

	collptr=(ULONG *)reducedCollBox[collBoxPos];

	//DB("collBoxPos= %d, collptr=%p\n", collBoxPos, collptr);
	//pD->preVel.vx=pD->pVel->vx;
	//pD->preVel.vy=pD->pVel->vy;
	//pD->preVel.vz=pD->pVel->vz;

#ifdef CAMBOXES
	STARTPOLY;
	ADDVERT(pD->pPos->vx-pD->radius, pD->pPos->vy-pD->radius, pD->pPos->vz+pD->radius);
	ADDVERT(pD->pPos->vx-pD->radius, pD->pPos->vy+pD->radius, pD->pPos->vz+pD->radius);
	ADDVERT(pD->pPos->vx+pD->radius, pD->pPos->vy+pD->radius, pD->pPos->vz+pD->radius);
	ADDVERT(pD->pPos->vx+pD->radius, pD->pPos->vy-pD->radius, pD->pPos->vz+pD->radius);
	DRAWPOLY(255,255,255);

	STARTPOLY;
	ADDVERT(pD->pPos->vx-pD->radius, pD->pPos->vy-pD->radius, pD->pPos->vz-pD->radius);
	ADDVERT(pD->pPos->vx-pD->radius, pD->pPos->vy+pD->radius, pD->pPos->vz-pD->radius);
	ADDVERT(pD->pPos->vx+pD->radius, pD->pPos->vy+pD->radius, pD->pPos->vz-pD->radius);
	ADDVERT(pD->pPos->vx+pD->radius, pD->pPos->vy-pD->radius, pD->pPos->vz-pD->radius);
	DRAWPOLY(255,255,255);

	STARTPOLY;
	ADDVERT(pD->pPos->vx-pD->radius, pD->pPos->vy-pD->radius, pD->pPos->vz-pD->radius);
	ADDVERT(pD->pPos->vx-pD->radius, pD->pPos->vy-pD->radius, pD->pPos->vz+pD->radius);
	DRAWPOLY(255,255,255);

	STARTPOLY;
	ADDVERT(pD->pPos->vx-pD->radius, pD->pPos->vy+pD->radius, pD->pPos->vz-pD->radius);
	ADDVERT(pD->pPos->vx-pD->radius, pD->pPos->vy+pD->radius, pD->pPos->vz+pD->radius);
	DRAWPOLY(255,255,255);

	STARTPOLY;
	ADDVERT(pD->pPos->vx+pD->radius, pD->pPos->vy-pD->radius, pD->pPos->vz-pD->radius);
	ADDVERT(pD->pPos->vx+pD->radius, pD->pPos->vy-pD->radius, pD->pPos->vz+pD->radius);
	DRAWPOLY(255,255,255);

	STARTPOLY;
	ADDVERT(pD->pPos->vx+pD->radius, pD->pPos->vy+pD->radius, pD->pPos->vz-pD->radius);
	ADDVERT(pD->pPos->vx+pD->radius, pD->pPos->vy+pD->radius, pD->pPos->vz+pD->radius);
	DRAWPOLY(255,255,255);
#endif
	if (pD==&gloveColl)
	{	
		GloveCtrl.forceSlide=FALSE;
	}


	if (pD->physics==NULL)
	{
		printf ("ERROR no physics model exists\n");
		CRASH;
	}
	Physics=&pD->physics[pD->physicsModel];

	pD->radius=Physics->radius;

	// Clear hit array
	for(i=0; i<16; i++)
	{
		pHitData[i].type=FALSE;
		pHitData[i].plane=FALSE;
		//hitRecord[i]=0;
	}

//check for any moving platforms in the area. (very Slow!)

	if(frame>0)	 // bodge because platform collision goes wrong on frame 0
	{
	for(ptr = dyncollList.head.next; ptr != &dyncollList.head; ptr = ptr->next)
	{
		long dX,dY,dZ;

		if(!(ptr->active))
			continue;
		
		if((ptr->pPlatDef->head.flags)&PLATFLAG_NOCOLLISION)
			continue;

		dX=((pD->pPos->vx)-(ptr->cumPos.vx))/4096;
		dY=((pD->pPos->vy)-(ptr->cumPos.vy))/4096;
		dZ=((pD->pPos->vz)-(ptr->cumPos.vz))/4096;

		if((((dX*dX)+(dY*dY)+(dZ*dZ))/4096)<((pPlatsLoaded[ptr->platNumber].collRadiusSqr)+COLLMARGIN)) // dist squared
		{
			int i,oldPolysHit;

		//DB("%d, %d, %d\n", ((dX*dX)+(dY*dY)+(dZ*dZ))/4096, pPlatsLoaded[ptr->platNumber].collRadiusSqr, COLLMARGIN);
			oldPolysHit=nPolysHit;

// note that bugle's dynamic collisionbox doesn't have a platform number (so it's set to -1)
			if(ptr->platNumber >= 0)
			{
				//DB("checking plat (%d)\n", ptr->pPlatDef->head.tag);

				for(i=0; i<ptr->nCollBoxes; i++)
				{
/*					int maxX=ptr->cumPos.vx-ptr->pBoxes[i].pX;
					int minX=maxX-ptr->pBoxes[i].sX;

					int maxZ=ptr->cumPos.vz-ptr->pBoxes[i].pZ;
					int minZ=maxZ-ptr->pBoxes[i].sZ;

					if((pD->pPos->vx > (minX-COLLMARGINBIG)) && ( pD->pPos->vx < (maxX+COLLMARGINBIG)) && (pD->pPos->vz > (minZ-COLLMARGINBIG)) && ( pD->pPos->vz < (maxZ+COLLMARGINBIG)))
*/					{
						collboxCheckOneMovingBox((ptr->pBoxes)+i, pD, &nPolysHit, &(ptr->cumPos), &(ptr->oldPos));

						//if(nPolysHit>oldPolysHit)
						//	DB("Have hit platform box %p, %d\n", ptr, i);
					}
				}
			}
			else
			{
				// temporarily commented out by Chris
				//collboxCheckOneBox(&ptr->cb, pD, &nPolysHit);
			}

			if(nPolysHit>oldPolysHit)
			{// there must have been a hit on this platform, so record it
				if(pD->nHitPlats==MAXPLATHITS)
				{
					DB("ERROR: Too many PLATFORMS were hit!\n");
					continue;
				}
				pD->hitPlats[pD->nHitPlats].pPlatform=ptr;
				(pD->nHitPlats)++;
			}
		}
	}
	}

/*
	if(pD->nHitPlats)
	{
		DYNCOLLBOX *pCollBox=(DYNCOLLBOX *)(pD->hitPlats[0].pPlatform);
		VECTOR platMoved;

		if(pCollBox->move.moving)
		//if(CompareVectors((VECTOR *)&(pCollBox->cb.pX), (VECTOR *)&(pCollBox->cb.oldpX)))
		{
			//DB("Have hit %d moving platforms!\n", pD->nHitPlats);
			// got to move the glove and/or ball by amount platform has moved
			SUBVECTOR(&platMoved,	(VECTOR *)&(pCollBox->cb.pX),
									(VECTOR *)&(pCollBox->cb.oldpX));

			//DB("V= %d,%d,%d\n", platMoved.vx, platMoved.vy, platMoved.vz);
		
			ADDVECTOR(pD->pPos, &platMoved, pD->pPos);
			ADDVECTOR(&pD->oldPos, &platMoved, &pD->oldPos);
		}
	}
*/

#ifdef TESTALL
	for(i=0; i<nMeshColl; i++)
	{
		collboxCheckOneBox(pMeshColl+i, pD, &nPolysHit);
	}
#else
	if(collptr) // Any other boxes to test?
	{
		if(((ULONG)collptr)<0x80000000)	// Check for one or >one
		{
			//*collptr&=0x7fffffff;
			collptr=(ULONG *)(reducedCollBox[collBoxPos]);
			pB=(COLLBOX*)collptr;

			collboxCheckOneBox(pB, pD, &nPolysHit);
		}
		else
		{	// must be >1 boxes to test
			loop=0;

			collptr = (ULONG *)(  ((ULONG)(collptr)) & 0x7fffffff);	// mask off collptrs 1st bit
			collptr1= (ULONG *)(*collptr);
			do	// the "none" case has already been dealt with
			{
				pB=(COLLBOX*)collptr1;

				collboxCheckOneBox(pB, pD, &nPolysHit);

				collptr++;
				collptr1=(ULONG *)(*collptr);
			}
			while (collptr1!=NULL);

		}
	}

#endif

	if (nPolysHit>16)
	{
		DB("too many collisions !\n");
		CRASH;
	}
#ifdef SHITLOADSOFDEBUG
	if (pD==&gloveColl) printf ("glove hit %d edges\n",pD->nEdgeHits);
#endif
	reboundcount=0;
	if(nPolysHit)
	{
		pD->lastHit=0;
		collPos.vx=pD->pPos->vx;
		collPos.vy=pD->pPos->vy;
		collPos.vz=pD->pPos->vz;

		SUBVECTOR(&v0v1, pD->pPos, &pD->oldPos);
		magv0v1=Magnitude(&v0v1);

// maybe sorting phitdata so it updates ramps first?
// Current sequence edge/corner,ramps,the rest and planes

		i=RemoveRedundantEdges(pD , &nPolysHit);
		hi=(nPolysHit-1)-i;
		low=0;

// Fred mod
// Leave nPolysHit alone till after we've weeded out the 128s...
// (which means we need to use "i" rather than "p" as the removal counter above)
// Let the 128-type act as the weeder rather than trying to auto-correct the first couple of hitplats.

		if (nPolysHit>1)
		{

// Any "128" redundant edges get thrown out by this code
// so we need to reduce "nPolyHit *afterwards*

			for (p=0;p<nPolysHit;p++)
			{
				if (pHitData[p].type==RAMP_H)
				{
					swap[low++]=&pHitData[p];
				}
			}
			for (p=0;p<nPolysHit;p++)
			{
				if (pHitData[p].type==EDGE || pHitData[p].type==CORNER)
				{
					swap[low++]=&pHitData[p];
				}
				else if (pHitData[p].type==PLANE)
				{
					swap[hi--]=&pHitData[p];
				}
			}
			for (p=0;p<nPolysHit;p++)
			{
				if (pHitData[p].type!=RAMP_H && pHitData[p].type!=PLANE && pHitData[p].type!=EDGE && pHitData[p].type!=CORNER && pHitData[p].type!=128) // 128=remove edge
				{
					swap[low++]=&pHitData[p];
				}
			}

// Fred mod
// Okay. The routines below use nPolysHit to index swap[], so it needs to be corrected
// for the removed edge count
			nPolysHit -= i;
		}
		else
		{
			swap[0] = &pHitData[0];
		}


		if (pD->nRampHits>=2)
		{
			//printf ("hit %d ramps\n",pD->nRampHits);
			//UpdateMultiRampCollision(pD , swap[p], &collPos , &planeRebound);
			UpdateMultiRampCollision(pD , &collPos , &planeRebound);
		}


		if (nPolysHit && pD==&ballColl)
		{
			BallCtrl.onTrampoline=FALSE;
		}

		reboundcount=0;
		flag=FALSE;

 		for(p=0; p<nPolysHit; p++)
		{
			if (pD->physics==NULL){{DB("ERROR no physics model exists\n");}CRASH;}
			Physics=&pD->physics[pD->physicsModel];
			pD->radius=Physics->radius;

			switch(swap[p]->type)
			{
			case RAMP_H:
				
				if (pD->nRampHits>=2) break;
				UpdateRampCollision(pD , swap[p], &collPos , &planeRebound);
				//swap[p]->normal.vy=-swap[p]->normal.vy;
				if (pD==&gloveColl && (pD->flags&SPECIALPART)!=P_STICKY)
				{
					if ( swap[p]->normal.vy >= -2899 && abs(swap[p]->normal.vy)>409 && swap[p]->normal.vy<0)
					{
						GloveCtrl.forceSlide=TRUE;
						GloveCtrl.slideData.vx=swap[p]->normal.vx;
						GloveCtrl.slideData.vz=swap[p]->normal.vz;
						if (GloveCtrl.onIce || GloveCtrl.onIceFlag)
						{
							GloveCtrl.onIce=FALSE;
							GloveCtrl.onIceFlag=FALSE;
						}
					}
					if (swap[p]->normal.vy>1000) GloveCtrl.onCeiling=TRUE;
					//printf ("y normal part %d \n",swap[p]->normal.vy);
					//else GloveCtrl.forceSlide=FALSE;
					//swap[p]->normal.vy=-swap[p]->normal.vy;
				}
					
				pD->normal.vx=swap[p]->normal.vx;
				pD->normal.vy=swap[p]->normal.vy;
				pD->normal.vz=swap[p]->normal.vz;
				break;

			case PLANE:
						flag=TRUE;
						UpdatePlaneCollision(pD , swap[p], &collPos , &planeRebound);
				break;

			case EDGE:
						UpdateEdgeCollision(pD , swap[p], &collPos , &planeRebound);
				break;

			case CORNER:
						UpdateCornerCollision(pD , swap[p],&collPos ,&planeRebound);
				break;

			case CYLINDER:
						UpdateCylinderCollision(pD , swap[p],&collPos,&planeRebound);
				break;

			case SPHERE_H:
						UpdateSphereCollision(pD , swap[p], &collPos , &planeRebound);
				break;
			}
		}
		// At This point the object will have been moved so its not intersecting anything (WITH LUCK!)
		// Now the bounce has to be done

		if ( nPolysHit>1 ) MergeBounceNormals(nPolysHit);


		COPYVECTOR(&vTempRebound, pD->pVel);

// NOTE if this collision code is to be use for other thing these case should be removed

		if (pD==&ballColl)
		{
			if (pD->flags==P_STICKY )
				BallCtrl.onSticky=TRUE;
	 		else
				BallCtrl.onSticky=FALSE;

			if (pD->flags==P_MEGASTICKY )
				BallCtrl.megaSticky=TRUE;
			else
				BallCtrl.megaSticky=FALSE;
		}
		if(pD==&gloveColl)
		{
			GloveCtrl.onTrampoline=FALSE;
			GloveCtrl.onWater=FALSE;
		}
		if(pD==&ballColl)
		{
			BallCtrl.onWater=FALSE;
		}
		if (pD==&gloveColl)	   //collision with THE GLOVE!!!
		{
			pD->flags &= ~(P_NOCAMCOLLISION);
			switch (pD->flags){
				case P_ICE:
				case P_SNOWANDICE:
					GloveCtrl.onIce=TRUE;
					//GloveCtrl.onIce=FALSE;
					if ( (pD->normal.vx || pD->normal.vz) && abs(pD->normal.vy)>512 )
					{
						//COPYVECTOR(&GloveCtrl.slideNormal,&pD->normal);
						if (GloveCtrl.forceSlide)
						{
							GloveCtrl.forceSlide=FALSE;
							GloveCtrl.slideData.vx=0;
							GloveCtrl.slideData.vy=0;
							GloveCtrl.slideData.vz=0;
						}
						else
						{
							GloveCtrl.slideData.vx=pD->normal.vx;
							GloveCtrl.slideData.vy=pD->normal.vy;
							GloveCtrl.slideData.vz=pD->normal.vz;
						}
						//printf ("normal for ice X %d Y %d Z %d\n",pD->normal.vx,pD->normal.vy,pD->normal.vz);

						//COPYVECTOR(&GloveCtrl.slideNormal,&slideNormal);
						//GloveCtrl.forceSlide=TRUE;
						//GloveCtrl.slideData.vx=swap[p]->normal.vx;
						//GloveCtrl.slideData.vz=swap[p]->normal.vz;
					}
					else
					{
						GloveCtrl.forceSlide=FALSE;
						GloveCtrl.slideData.vx=0;
						GloveCtrl.slideData.vy=0;
						GloveCtrl.slideData.vz=0;
					}
				break;
			/*	case P_SNOW:		// As snow has no effect on glove removed
								//BallCtrl.onConveyer=XPOS;
								//BallCtrl.conveyerTimer=6;
								//printf ("glove on snow\n");
								GloveCtrl.onSnow=TRUE;
			}
			*/
				case P_STICKY:
								GloveCtrl.forceSlide=FALSE;
				break;

/*				case P_CONVEYERXP:
								GloveCtrl.onConveyer=XPOS;
								GloveCtrl.conveyerTimer=6;
				break;
				case P_CONVEYERXN:
								GloveCtrl.onConveyer=XNEG;
								GloveCtrl.conveyerTimer=6;
				break;
				case P_CONVEYERZP:
								GloveCtrl.onConveyer=ZPOS;
								GloveCtrl.conveyerTimer=6;
				break;
				case P_CONVEYERZN:
								GloveCtrl.onConveyer=ZNEG;
								GloveCtrl.conveyerTimer=6;
				break;
*/
				case P_LAVA:
						if (!GloveCtrl.hurtFlag && !GloveCtrl.deathType && !GloveCtrl.handHurtTime)
						{
							GloveCtrl.hurtFlag=TRUE;
							GloveCtrl.deathType=DEADFROMPAIN;
						}
						GloveCtrl.onLava=TRUE;
				break;

				case P_TRAMPOLINE:
							//printf ("glove on trampoline\n");
							GloveCtrl.onTrampoline=TRUE;
				break;
				case P_WATERY:		//printf ("glove on water\n");
							if (GloveCtrl.action!=HAND_JOINED)
							{
							GloveCtrl.onWater=TRUE;
							collPos.vx=pGlovePSA->position.vx;
							collPos.vz=pGlovePSA->position.vz;
							collPos.vy=pGlovePSA->position.vy+(pD->radius/4096);
//							Start_Ripple(&collPos,4096/2,15);	// fred's moved this to a flag in "waterDoSplashiness"
							}
				break;

				case P_SPIKE:
							//if ((GloveCtrl.action!=HAND_CRAWL && GloveCtrl.walkType!=HANDWALK_TIPTOE && GloveCtrl.action!=HAND_IDLE) )
							//{
							//	printf ("Glove on spike\n");
						if (!GloveCtrl.hurtFlag && !GloveCtrl.deathType && !GloveCtrl.handHurtTime)
						{
							GloveCtrl.hurtFlag=TRUE;
							GloveCtrl.deathType=HURTFALL;
						}
						GloveCtrl.onLava=TRUE;
							//}
				break; 

				default:
							//DB("glove came through with no surface!\n");
				break;
			}


		}

		if (pD==&ballColl)	
		{
			pD->flags &= ~(P_NOCAMCOLLISION);
			switch(pD->flags){
			case	P_ICE:
				BallCtrl.onIce=TRUE;
				COPYVECTOR(&BallCtrl.slideNormal,&pD->normal);
				//if(level==PREHISTORICBOSS) 	
				//	BallCtrl.onSnow = TRUE;	// Messy, but this is the only slope in the game that's snowy AND icy, I think...
				break;

			case	P_SNOW:
				//BallCtrl.onConveyer=XPOS;
				//BallCtrl.conveyerTimer=6;
				//printf ("ball on snow\n");
				BallCtrl.onSnow=TRUE;
				break;

			case	P_SNOWANDICE:
				BallCtrl.onIce=TRUE;
				//COPYVECTOR(&BallCtrl.slideNormal,&slideNormal);
				COPYVECTOR(&BallCtrl.slideNormal,&pD->normal);
				BallCtrl.onSnow=TRUE;
				break;

/*			case P_CONVEYERXN:
							BallCtrl.onConveyer=XNEG;
							BallCtrl.conveyerTimer=6;
			break;
			case P_CONVEYERXP:
							BallCtrl.onConveyer=XPOS;
							BallCtrl.conveyerTimer=6;
			break;

			case P_CONVEYERZP:
							BallCtrl.onConveyer=ZPOS;
							BallCtrl.conveyerTimer=6;
			break;
			case P_CONVEYERZN:
							BallCtrl.onConveyer=ZNEG;
							BallCtrl.conveyerTimer=6;
			break;
*/			case P_LAVA:

				if (GloveCtrl.health==0) break;
				if (GloveCtrl.action!=SPECIALACTION && BallCtrl.health>1 && GloveCtrl.onGround && !GloveCtrl.deathTypeBall && level!=PREHISTORICBONUS)
				{
					GloveCtrl.actionTime=0;
					GloveCtrl.action=SPECIALACTION;
					GloveCtrl.preDelay=16;
					gloveVel.vx=0;
					gloveVel.vy=0;
					gloveVel.vz=0;
					AddToQueue(&Glover,HANDANIM_CLICKFINGER,NO,NO,4096);

					//removeSnow();
					BallChange.changeOn=0;
					BallCtrl.onSnow=0;
					BallCtrl.snowTexChange=0;
				}
				else if (GloveCtrl.deathTypeBall!=DEADFROMBALLBURST && GloveCtrl.action!=SPECIALACTION)
				{
					GloveCtrl.hurtFlagBall=TRUE;
					GloveCtrl.deathTypeBall=DEADFROMBALLBURST;
				}


//				else if (BallCtrl.health<=1)
//				{
//					GloveCtrl.hurtFlagBall=TRUE;
//					GloveCtrl.deathTypeBall=DEADFROMBALLBURST;
//				}

/*				if (GloveCtrl.actionTime==17)
				{
					VECTOR pos;
					GloveCtrl.action=HAND_IDLE;
					pos = glovePos;
					pos.vy -= 50<<12;
					BallCtrl.health--;
					BallCtrl.hurt=TRUE;
					if (BallCtrl.health==0)
					{
						GloveCtrl.hurtFlagBall=TRUE;
						GloveCtrl.deathTypeBall=DEADFROMBALLBURST;
					}
					//BallCtrl.type=BALL_MODE_NORMAL;
					ballPlaceAt(&pos);
				}
*/
//				if (GloveCtrl.deathTypeBall!=DEADFROMBALLBURST)
//				{
//					GloveCtrl.hurtFlagBall=TRUE;
//					GloveCtrl.deathTypeBall=DEADFROMBALLBURST;
//				}

				break;
			case P_TRAMPOLINE:
							BallCtrl.onTrampoline=TRUE;
							//printf ("ball on trampoline\n");
			break;

			case P_WATERY:
							//printf ("glove on water\n");
							BallCtrl.onWater=TRUE;
							collPos.vx=pBallPSA->position.vx;
							collPos.vz=pBallPSA->position.vz;
							collPos.vy=pBallPSA->position.vy+(pD->radius/4096);
							//	Start_Ripple(&collPos,4096/2,15);	// fred's moved this to a flag in "waterDoSplashiness"
			break;
			case P_SPIKE:
							DB("ball on spike\n");
							if (!GloveCtrl.hurtFlagBall && !GloveCtrl.deathTypeBall)
							{
							GloveCtrl.deathTypeBall=DEADFROMBALLBURST;
							GloveCtrl.hurtFlagBall=TRUE;
							}
			break;

			default:
							//DB("ball came through with no surface!\n");
			break;
			}
		}

		for(p=0; p<nPolysHit; p++)
		{
			switch(swap[p]->type)
			{
			case RAMP_H:
				magv0v1=Magnitude(&vTempRebound);
				if (pD==&ballColl)
				{
					if (BallCtrl.onSticky)
					{
						swap[p]->normal.vy-=4096;
						MakeUnit(&swap[p]->normal);
					}
					if (BallCtrl.megaSticky)
					{
						if (swap[p]->normal.vy<0)
							swap[p]->normal.vy-=8000;
						else
							swap[p]->normal.vy+=8000;
						MakeUnit(&swap[p]->normal);
					}
				}
/*				if (pD==&gloveColl)
				{
					if ( swap[p]->normal.vy >= -2899 && abs(swap[p]->normal.vy)>409)
					{
						GloveCtrl.forceSlide=TRUE;
						GloveCtrl.slideData.vx=swap[p]->normal.vx;
						GloveCtrl.slideData.vz=swap[p]->normal.vz;
					}
					else GloveCtrl.forceSlide=FALSE;
				}
*/
				CalcBounce(&vTempRebound, &swap[p]->normal);
				SCALEVECTOR(&vTempRebound, magv0v1);

				break;

			case PLANE:
				if (pD==&gloveColl) GloveCtrl.forceSlide=FALSE;
				switch(swap[p]->plane)
				{
			 		case D_XZPLANE:
									if (vTempRebound.vy>0) vTempRebound.vy=-vTempRebound.vy;
						break;
			 		case U_XZPLANE:
									if (vTempRebound.vy<0) vTempRebound.vy=-vTempRebound.vy;
						break;

//			 		case D_XZPLANE:
//			 		case U_XZPLANE:
//									vTempRebound.vy=-vTempRebound.vy;
//						break;


			 		case D_YZPLANE:
			 		case U_YZPLANE:
									vTempRebound.vx=-vTempRebound.vx;
						break;
			 		case D_XYPLANE:
			 		case U_XYPLANE:
									vTempRebound.vz=-vTempRebound.vz;
						break;
				}
				break;

			case EDGE:
				 if (pD==&ballColl)
				 {
						if (BallCtrl.megaSticky)
						{
							if (swap[p]->normal.vy<0)
								swap[p]->normal.vy-=8000;
							else
								swap[p]->normal.vy+=8000;
							MakeUnit(&swap[p]->normal);
						}
				 }
						magv0v1=Magnitude(&vTempRebound);
						CalcBounce(&vTempRebound, &swap[p]->normal);
						SCALEVECTOR(&vTempRebound, magv0v1);
				break;

			case CORNER:
						if (BallCtrl.megaSticky)
						{
							if (swap[p]->normal.vy<0) swap[p]->normal.vy-=8000;
							else					  swap[p]->normal.vy+=8000;
							MakeUnit(&swap[p]->normal);
						}
						magv0v1=Magnitude(&vTempRebound);
						CalcBounce(&vTempRebound, &swap[p]->normal);
						SCALEVECTOR(&vTempRebound, magv0v1);
				break;

			case CYLINDER:
						if (pD==&gloveColl) GloveCtrl.forceSlide=FALSE;
						magv0v1=Magnitude(&vTempRebound);
						CalcBounce(&vTempRebound, &swap[p]->normal);
						SCALEVECTOR(&vTempRebound, magv0v1);
						break;

			case SPHERE_H:
						if (pD==&gloveColl) GloveCtrl.forceSlide=FALSE;
						magv0v1=Magnitude(&vTempRebound);
						CalcBounce(&vTempRebound, &swap[p]->normal);
						SCALEVECTOR(&vTempRebound, magv0v1);
				break;
			}
		}
		if (pD==&ballColl)	doBounceOnVelBall(&vTempRebound,pD->pVel,Physics);
		else			  	doBounceOnVel(&vTempRebound,pD->pVel,Physics);
		
		COPYVECTOR(pD->pVel, &vTempRebound);
	}

	if (pD==&ballColl)
	{
		if (pD->flags==P_STICKY)
			BallCtrl.onSticky=TRUE; //printf ("on skicky surface\n");
		else
			BallCtrl.onSticky=FALSE;
	}


	//DB("REB=(%d,%d,%d)\n", vTempRebound.vx, vTempRebound.vy, vTempRebound.vz);

	//if (pD==&gloveColl && nPolysHit) gloveVel.vy=-gloveVel.vy;

	//GloveCtrl.forceSlide=FALSE;

	COPYVECTOR(&pD->oldPos, pD->pPos);
	return nPolysHit;
}

/*	--------------------------------------------------------------------------------
	Function 	: MergeBounceNormals
	Purpose 	: Merge normals (not planes)
	Parameters 	: hitdata / number of hit s
	Returns 	: Single normal
	Info 		: 
*/
//-------------------------------------------------------------------------------//
void	MergeBounceNormals(int nPolysHit)
{
	int		loop,count;
	VECTOR	normal;
	normal.vx=0;
	normal.vy=0;
	normal.vz=0;
	count=0;
	for (loop=0;loop<nPolysHit;loop++)
	{
		if ( swap[loop]->type!=PLANE )
		{
			ADDVECTOR(&normal,&normal,&swap[loop]->normal);
			//normal.vx+=swap[loop]->normal.vx;
			//normal.vy+=swap[loop]->normal.vy;
			//normal.vz+=swap[loop]->normal.vz;
			count++;
		}
	}

	if (count>1)
	{
		MakeUnit(&normal);
		COPYVECTOR(&swap[0]->normal,&normal);
		for (loop=1;loop<nPolysHit;loop++){
			if (swap[loop]->type!=PLANE)swap[loop]->type=99;
		}
	}
}

/*	--------------------------------------------------------------------------------
	Function 	: CheckCorners
	Purpose 	: Checks all the corners of a box to see if hit or not
	Parameters 	: Collision box to check
	Returns 	: If hit incs number of hits and stores corner pos
	Info 		: No bugs found yet
*/
//-------------------------------------------------------------------------------//

int pFaceOrder[]={D_XZPLANE, U_XZPLANE, D_YZPLANE, U_YZPLANE, D_XYPLANE, U_XYPLANE};

int pEdgeOrder[]={U_XYPLANE|U_XZPLANE, U_XZPLANE|D_XYPLANE, D_XYPLANE|D_XZPLANE, U_XYPLANE|D_XZPLANE,
				  U_XYPLANE|U_YZPLANE, U_YZPLANE|D_XYPLANE, D_XYPLANE|D_YZPLANE, U_XYPLANE|D_YZPLANE,
				  U_XZPLANE|U_YZPLANE, U_YZPLANE|D_XZPLANE, D_XZPLANE|D_YZPLANE, U_XZPLANE|D_YZPLANE};

int pCornerOrder[]={U_XYPLANE|U_XZPLANE|U_YZPLANE, U_XYPLANE|U_XZPLANE|D_YZPLANE,
					U_XYPLANE|D_XZPLANE|D_YZPLANE, U_XYPLANE|D_XZPLANE|U_YZPLANE,
					D_XYPLANE|U_XZPLANE|U_YZPLANE, D_XYPLANE|U_XZPLANE|D_YZPLANE,
					D_XYPLANE|D_XZPLANE|D_YZPLANE, D_XYPLANE|D_XZPLANE|U_YZPLANE};

/************************************************************************************/
ULONG	CheckCorners( COLLBOX *pB , COLLDATA *pD, HITDATA *pHitData )
{
	long x1,x2;
	long y1,y2;
	long z1,z2,c;
	ULONG	bHit=0;
	ULONG	hitFlag=0;
	x1=pB->pX;
	x2=x1+(pB->sX);
	y1=pB->pY;
	y2=y1+(pB->sY);
	z1=pB->pZ;
	z2=z1+(pB->sZ);
	for(c=0; c<8; c++)
	{ 
		switch(c)
		{
			// front of box
			case 0:
				bHit=collboxHasBallHitCorner(pD, x1,y1,z1);
				break;
			case 1:
				bHit=collboxHasBallHitCorner(pD, x2,y1,z1);
				break;
			case 2:
				bHit=collboxHasBallHitCorner(pD, x2,y2,z1);
				break;
			case 3:
				bHit=collboxHasBallHitCorner(pD, x1,y2,z1);
				break;
			// back of box
			case 4:
				bHit=collboxHasBallHitCorner(pD, x1,y1,z2);
				break;
			case 5:
				bHit=collboxHasBallHitCorner(pD, x2,y1,z2);
				break;
			case 6:
				bHit=collboxHasBallHitCorner(pD, x2,y2,z2);
				break;
			case 7:
				bHit=collboxHasBallHitCorner(pD, x1,y2,z2);
		}
		if(bHit)
		{
			//if (PRINTHITPOS) printf("Hit CORNER!\n");
			pHitData->type=CORNER;
			pHitData->plane=pCornerOrder[c];
			pHitData->pCollBox=pB;
			COPYVECTOR( &(pHitData->pos), &(pD->hitPos));
			hitFlag=TRUE;
			//nPolysHit++;
			//return (TRUE);
		}
		//else return (FALSE);
	}
	return (hitFlag);
}

/*	--------------------------------------------------------------------------------
	Function 	: collboxHasBallHitCorner
	Purpose 	: Checks if ball has hit corner
	Parameters 	: Corner position
	Returns 	: 0 if no hit !0 if hit
	Info 		: No bugs found yet
*/
//-------------------------------------------------------------------------------//
int collboxHasBallHitCorner(COLLDATA *pD, int x, int y, int z)
{
	VECTOR *hitP=&pD->hitPos;	
	VECTOR d;
	int bHit=0;
	d.vx=(pD->pPos->vx)-x;
	d.vy=(pD->pPos->vy)-y;
	d.vz=(pD->pPos->vz)-z;
	if(Magnitude(&d)<(pD->radius))
	{
		hitP->vx=x;
		hitP->vy=y;
		hitP->vz=z;
		bHit++;
	}
	return(bHit);
}

/*	--------------------------------------------------------------------------------
	Function 	: collboxHasBallHitEdge
	Purpose 	: Checks if ball has hit edge
	Parameters 	: Edge position
	Returns 	: 0 if no hit !0 if hit
	Info 		: No bugs found yet
*/
//-------------------------------------------------------------------------------//

COLLDATA *globalpD;
int coll_axis;

int collboxHasBallHitEdge(int l1, int l2, int x, int y)	///routine changed to 4 parameters, for speed  ANO
{
	VECTOR *hitP=&globalpD->hitPos;
	COLLDATA *pD=globalpD;
	long vx,vy,vz;
	int bHit=0;
	
//	ZEROVECTOR(&d);

	switch(coll_axis)
	{
	case XAXIS:	// I'm not going to record the old for all these if errors check in source safe
/*		d.v[1]=(pD->pPos->v[1])-x;
		d.v[2]=(pD->pPos->v[2])-y;
		if((Magnitude(&d)<(pD->radius)) && ((pD->pPos->v[0])>l1) && ((pD->pPos->v[0])<l2))
		{
			hitP->v[0]=pD->pPos->v[0];
			hitP->v[1]=x;
			hitP->v[2]=y;
			bHit++;
		}
		break;*/
		vy=(pD->pPos->vy)-x;
		vz=(pD->pPos->vz)-y;
		
		if((Magnitude2D(vy,vz)<(pD->radius)) && ((pD->pPos->vx)>l1) && ((pD->pPos->vx)<l2))
		{
			hitP->vx=pD->pPos->vx;
			hitP->vy=x;
			hitP->vz=y;
			bHit++;
		}
		break;

	case YAXIS:
		vx=(pD->pPos->vx)-x;
		vz=(pD->pPos->vz)-y;
		if((Magnitude2D(vx,vz)<(pD->radius)) && ((pD->pPos->vy)>l1) && ((pD->pPos->vy)<l2))
		{
			hitP->vx=x;
			hitP->vy=pD->pPos->vy;
			hitP->vz=y;
			bHit++;
		}
		break;
	case ZAXIS:
		vx=(pD->pPos->vx)-x;
		vy=(pD->pPos->vy)-y;
		if((Magnitude2D(vx,vy)<(pD->radius)) && ((pD->pPos->vz)>l1) && ((pD->pPos->vz)<l2))
		{
			hitP->vx=x;
			hitP->vy=y;
			hitP->vz=pD->pPos->vz;
			bHit++;
		}
		break;
	}
	return(bHit);
}

/*	--------------------------------------------------------------------------------
	Function 	: CheckEdges
	Purpose 	: Checks all the edges of a box to see if hit or not
	Parameters 	: Collision box to check
	Returns 	: If hit incs number of hits and stores corner pos
	Info 		: No bugs found yet
*/
//-------------------------------------------------------------------------------//
ULONG	CheckEdges(COLLBOX *pB , COLLDATA *pD , HITDATA *pHitData )
{

	long 	x1,x2;
	long 	y1,y2;
	long 	z1,z2;
	long 	e;
	ULONG	bHit=0;	
	ULONG	hitFlag=0;
	globalpD=pD;
	x1=pB->pX;
	x2=x1+(pB->sX);

	y1=pB->pY;
	y2=y1+(pB->sY);
	//y2=y1-(pB->sY);

	z1=pB->pZ;
	z2=z1+(pB->sZ);
	//if (pHitData[i].type!=FALSE) continue;
	// check edges of box (there's 4 X, 4 Y and 4 Z edges)
	for(e=0; e<12; e++)
	{ 
		switch(e)
		{
			// X edges
			case 0:
				coll_axis=XAXIS;
				bHit=collboxHasBallHitEdge(x1,x2, y1,z1);
				break;
			case 1:
				bHit=collboxHasBallHitEdge(x1,x2, y1,z2);
				break;
			case 2:
				bHit=collboxHasBallHitEdge(x1,x2, y2,z2);
				break;
			case 3:
				bHit=collboxHasBallHitEdge(x1,x2, y2,z1);
				break;
			// Y edges
			case 4:
				coll_axis=YAXIS;
				bHit=collboxHasBallHitEdge(y2,y1, x1,z1);
				break;
			case 5:
				bHit=collboxHasBallHitEdge(y2,y1, x1,z2);
				break;
			case 6:
				bHit=collboxHasBallHitEdge(y2,y1, x2,z2);
				break;
			case 7:
				bHit=collboxHasBallHitEdge(y2,y1, x2,z1);
				break;
				// Z edges first
			case 8:
				coll_axis=ZAXIS;
				bHit=collboxHasBallHitEdge(z1,z2, x1,y1);
				break;
			case 9:
				bHit=collboxHasBallHitEdge(z1,z2, x1,y2);
				break;
			case 10:
				bHit=collboxHasBallHitEdge(z1,z2, x2,y2);
				break;
			case 11:
				bHit=collboxHasBallHitEdge(z1,z2, x2,y1);
				break;
		}
		if(bHit)
		{
			if (PRINTHITPOS) printf ("hit edge!\n");
			pD->nEdgeHits++;
			pHitData->type=EDGE;
			pHitData->plane=pEdgeOrder[e];
			pHitData->pCollBox=pB;
			COPYVECTOR(&(pHitData->pos), &(pD->hitPos));
			//nPolysHit++;
			hitFlag=TRUE;
		}
	}
	return (hitFlag);
}



/*	--------------------------------------------------------------------------------
	Function 	: collboxHasVectorCrossedPoly
	Purpose 	: Checks if ball has crossed plane
	Parameters 	: plane position
	Returns 	: 0 if no hit !0 if hit
	Info 		: Does'nt work with moving boxes
*/
//-------------------------------------------------------------------------------//

int global_plane;
int global_planePos;
int global_r;
//int collboxHasVectorCrossedPoly(COLLDATA *pD, int plane, int planePos, int r, int x1, int y1, int x2, int y2)
int collboxHasVectorCrossedPoly(int x1, int y1, int x2, int y2)	//changed to 4 parameters for less stack messin'! ANO
{
	long xDist,yDist,zDist;
	long xInt,yInt,zInt;
	long xPos,xNeg,yPos,yNeg,zPos,zNeg, div;
	int bHit=FALSE;
	ULONG	testFlag=FALSE;
	COLLDATA *pD=globalpD;
	VECTOR *newP=pD->pPos;
	VECTOR *oldP=&pD->oldPos;
	VECTOR *hitP=&pD->hitPos;
	int plane=global_plane;
	int planePos=global_planePos;
	int r=global_r;


	int		r1=abs(r);
	switch(plane)
	{
	case D_XZPLANE:
	case U_XZPLANE:
		// work out distance from initial point to XZ plane
		//yPos=(oldP->vy)+(planePos+r);
		//yNeg=(newP->vy)+(planePos+r);
		yPos=-(oldP->vy)+(planePos+r);
		yNeg=-(newP->vy)+(planePos+r);

		//printf("yAbove=%d, yBelow=%d\n", yPos/4096, yNeg/4096);
		
		if ( ((newP->vy+r)<planePos) && ((oldP->vy-r)>planePos) )
		{
			testFlag=TRUE;
		}

		if((yPos^yNeg)&0x80000000) testFlag=TRUE;
		
		if (testFlag)
		{	// signs are different, crossing plane
			//printf("Different ...\n");
			
			
			xDist=(newP->vx)-(oldP->vx);
			yDist=(newP->vy)-(oldP->vy);
			zDist=(newP->vz)-(oldP->vz);
			if (!yDist)
			{
				xInt=oldP->vx;
				zInt=oldP->vz;
			}
			else
			{
				//div=(yPos*4096)/yDist;
				div=0;
				xInt=((xDist*div)/4096)+(oldP->vx);
				zInt=((zDist*div)/4096)+(oldP->vz);
			}

			// is it inside our bounds?
			if((xInt>=x1) && (xInt<x2) && (zInt>=y1) && (zInt<y2))
			{
				bHit=TRUE;
				hitP->vx=xInt;
				hitP->vy=planePos+(r);
				hitP->vz=zInt;
			}
			//printf("x=%d-%d (%d), y=%d-%d (%d)\n", x1,x2,xInt, y1,y2,zInt);
		}
		break;

	case D_YZPLANE:
	case U_YZPLANE:
		// work out distance from initial point to YZ plane
		xPos=-(oldP->vx)+(planePos+r);
		xNeg=-(newP->vx)+(planePos+r);
		//printf("yAbove=%d, yBelow=%d planePos=%d\n", xPos/4096, xNeg/4096, planePos/4096);

		if((xPos^xNeg)&0x80000000) testFlag=TRUE;

		if ( ((newP->vx-r1)<planePos) && ((newP->vx+r1)>planePos) )
		{
			testFlag=TRUE;
		}

		if (testFlag)
		{	// signs are different, crossing plane
			//printf("Different ...\n");
			xDist=(newP->vx)-(oldP->vx);
			yDist=(newP->vy)-(oldP->vy);
			zDist=(newP->vz)-(oldP->vz);

			if (xDist==0)
			{
				yInt=oldP->vy;
				zInt=oldP->vz;
			}
			else
			{
				//div=(xPos*4096)/xDist;
				div=0;
				yInt=((yDist*div)/4096)+(oldP->vy);
				zInt=((zDist*div)/4096)+(oldP->vz);
			}

			// is it inside our bounds?

			//if((yInt>=x1) && (yInt<x2) && (zInt>=y1) && (zInt<y2))
			if((yInt<=x1) && (yInt>x2) && (zInt>y1) && (zInt<y2))
			{
				bHit=TRUE;
				hitP->vx=planePos+r;
				hitP->vy=yInt;
				hitP->vz=zInt;
				if (plane==U_YZPLANE) hitP->vx--;
				else hitP->vx++;

			}
			//printf("x=%d-%d (%d), y=%d-%d (%d)\n", x1,x2,yInt, y1,y2,yInt);
		}
		break;

	case D_XYPLANE:
	case U_XYPLANE:
		// work out distance from initial point to YZ plane
		zPos=(oldP->vz)-(planePos+r);
		zNeg=(newP->vz)-(planePos+r);
		//printf("yAbove=%d, yBelow=%d planePos=%d\n", xPos/4096, xNeg/4096, planePos/4096);

		if((zPos^zNeg)&0x80000000) testFlag=TRUE;

		if ( ((newP->vz-r1)<planePos) && ((newP->vz+r1)>planePos) )
		{
			testFlag=TRUE;
		}

		if (testFlag)
		{	// signs are different, crossing plane
			//printf("Different ...\n");
			xDist=(newP->vx)-(oldP->vx);
			yDist=(newP->vy)-(oldP->vy);
			zDist=(newP->vz)-(oldP->vz);
			if (zDist==0)
			{
				yInt=oldP->vy;
				xInt=oldP->vx;
			}
			else
			{
				//div=(zPos*4096)/zDist;
				div=0;
				yInt=((yDist*div)/4096)+(oldP->vy);
				xInt=((xDist*div)/4096)+(oldP->vx);
			}

			// is it inside our bounds?
			//if((xInt>=x1) && (xInt<x2) && (yInt>=y1) && (yInt<y2))
			if((xInt>x1) && (xInt<=x2) && (yInt<=y1) && (yInt>y2))
			{
				bHit=TRUE;
				hitP->vx=xInt;
				hitP->vy=yInt;
				hitP->vz=planePos+r;
				if (plane==U_XYPLANE) hitP->vz--;
				else hitP->vz++;
			}
		}
	}
	return(bHit);
}

/*	--------------------------------------------------------------------------------
	Function 	: CheckPlanes
	Purpose 	: Checks all the planes on a box to see if hit or not
	Parameters 	: Collision box to check
	Returns 	: If hit incs number of hits and stores corner pos
	Info 		: No bugs found yet
*/
//-------------------------------------------------------------------------------//



ULONG	CheckPlanes(COLLBOX *pB , COLLDATA *pD , HITDATA *pHitData )
{
//BOXXPOLY boxXpoly;
	long 	x1,x2;
	long 	y1,y2;
	long 	z1,z2,f;
	ULONG	bHit=0;
	ULONG	hitFlag=0;
	//long r=pD->radius;
	long r=pD->physics[pD->physicsModel].radius;
 //	int ctr;
	globalpD=pD;

	x1=pB->pX;
	x2=x1+(pB->sX);
	y1=pB->pY;
	y2=y1+(pB->sY);
	z1=pB->pZ;
	z2=z1+(pB->sZ);

	//if (pHitData[i].type!=FALSE) continue;

	// checks added for -ve numbers

/*	STARTPOLY;
	ADDVERT(x1,y1,z1);
	ADDVERT(x2,y1,z1);
	ADDVERT(x2,y1,z2);
	ADDVERT(x1,y1,z2);
	DRAWPOLY(255, 0, 0);

	STARTPOLY;
	ADDVERT(x1,y2,z1);
	ADDVERT(x2,y2,z1);
	ADDVERT(x2,y2,z2);
	ADDVERT(x1,y2,z2);
	DRAWPOLY(255, 0, 0);
*/
	for(f=0; f<6; f++)
	{
		
		//if(DotProduct((pB->n)+f, pD->pVel)<0)
		//{
			global_plane=pFaceOrder[f];
			switch(f)
			{
			case 0://D_XZPLANE:
//				bHit=collboxHasVectorCrossedPoly(pD, pFaceOrder[f], y2, -r, x1,z1,x2,z2);
				global_r=-r;
				global_planePos=y2;
				bHit=collboxHasVectorCrossedPoly(x1,z1,x2,z2);
				break;
			case 1://U_XZPLANE:
//				bHit=collboxHasVectorCrossedPoly(pD, pFaceOrder[f], y1, r, x1,z1,x2,z2);
				global_r=r;
				global_planePos=y1;
				bHit=collboxHasVectorCrossedPoly(x1,z1,x2,z2);
				break;
			case 2://D_YZPLANE:
//				bHit=collboxHasVectorCrossedPoly(pD, pFaceOrder[f], x2, r, y1,z1,y2,z2);
				global_r=r;
				global_planePos=x2;
				bHit=collboxHasVectorCrossedPoly(y1,z1,y2,z2);
				break;
			case 3://U_YZPLANE:
//				bHit=collboxHasVectorCrossedPoly(pD, pFaceOrder[f], x1, -r, y1,z1,y2,z2);
				global_r=-r;
				global_planePos=x1;
				bHit=collboxHasVectorCrossedPoly(y1,z1,y2,z2);
				break;
			case 4://D_XYPLANE:
//				bHit=collboxHasVectorCrossedPoly(pD, pFaceOrder[f], z2, r, x1,y1,x2,y2);
				global_r=r;
				global_planePos=z2;
				bHit=collboxHasVectorCrossedPoly(x1,y1,x2,y2);
				break;
			case 5://U_XYPLANE:
//				bHit=collboxHasVectorCrossedPoly(pD, pFaceOrder[f], z1, -r, x1,y1,x2,y2);
				global_r=-r;
				global_planePos=z1;
				bHit=collboxHasVectorCrossedPoly(x1,y1,x2,y2);
				break;
			default:
				printf("ah nuts!\n");
				CRASH;
			}

			if(bHit)
			{
				//if ((pB->flags & SPECIALPART)==MOVE ) DB("hit plane on current position\n");
				pHitData->type=PLANE;
				pHitData->plane=pFaceOrder[f];
				COPYVECTOR(&(pHitData->pos), &(pD->hitPos));
				pHitData->pCollBox=pB;
				//nPolysHit++;
				//return (TRUE);
				hitFlag=TRUE;
			}
		//}
	}


	if((hitFlag!=TRUE) && ((pB->flags & SPECIALPART)==MOVE) && ((pB->oldpX-x1)||(pB->oldpY-y1)||(pB->oldpZ-z1))) // don't know about this CPW
	{
		x1=pB->oldpX;
		x2=x1+(pB->sX);
		y1=pB->oldpY;
		y2=y1+(pB->sY);
		z1=pB->oldpZ;
		z2=z1+(pB->sZ);

		for(f=0; f<6; f++)
		{
			//if(DotProduct((pB->n)+f, pD->pVel)<0)
			//{
				
				global_plane=pFaceOrder[f];

				switch(f)
				{
				case 0:
//					bHit=collboxHasVectorCrossedPoly(pD, pFaceOrder[f], y2, -r, x1,z1,x2,z2);
					global_r=-r;
					global_planePos=y2;
					bHit=collboxHasVectorCrossedPoly(x1,z1,x2,z2);
					break;
				case 1:
//					bHit=collboxHasVectorCrossedPoly(pD, pFaceOrder[f], y1, r, x1,z1,x2,z2);
					global_r=r;
					global_planePos=y1;
					bHit=collboxHasVectorCrossedPoly(x1,z1,x2,z2);
					break;
				case 2:
//					bHit=collboxHasVectorCrossedPoly(pD, pFaceOrder[f], x2, r, y1,z1,y2,z2);
					global_r=r;
					global_planePos=x2;
					bHit=collboxHasVectorCrossedPoly(y1,z1,y2,z2);
					break;
				case 3:
//					bHit=collboxHasVectorCrossedPoly(pD, pFaceOrder[f], x1, -r, y1,z1,y2,z2);
					global_r=-r;
					global_planePos=x1;
					bHit=collboxHasVectorCrossedPoly(y1,z1,y2,z2);
					break;
				case 4:
//					bHit=collboxHasVectorCrossedPoly(pD, pFaceOrder[f], z2, r, x1,y1,x2,y2);
					global_r=r;
					global_planePos=z2;
					bHit=collboxHasVectorCrossedPoly(x1,y1,x2,y2);
					break;
				case 5:
//					bHit=collboxHasVectorCrossedPoly(pD, pFaceOrder[f], z1, -r, x1,y1,x2,y2);
					global_r=-r;
					global_planePos=z1;
					bHit=collboxHasVectorCrossedPoly(x1,y1,x2,y2);
					break;
				default:
					printf("Ah nuts2!\n");
					CRASH;
				}
	
				if(bHit)
				{
					//DB("hit plane on old position\n");
					pHitData->type=PLANE;
					pHitData->plane=pFaceOrder[f];
					COPYVECTOR(&(pHitData->pos), &(pD->hitPos));
					pHitData->pCollBox=pB;
					//nPolysHit++;
					//return (TRUE);
					hitFlag=TRUE;
				}
			//}
		}
	}



	return (hitFlag);
}


/*	--------------------------------------------------------------------------------
	Function 	: CheckCylinders
	Purpose 	: Checks if ball has hit a cylinder and what type 
	Parameters 	: The usual
	Returns 	: 0 if no hit !0 if hit
	Info 		: bugs found
*/
ULONG	CheckCylinders(COLLBOX *pB , COLLDATA *pD , HITDATA *pHitData )
{
	// First find out what type it is
	long	dist;
//	long	xLen;
//	long	cRadius;
	long	tRadius;
	VECTOR	*pos=pD->pPos;
//	VECTOR	*hit=&pD->hitPos;
	VECTOR	*hit=&pHitData->pos;
	VECTOR	d;
	switch( pB->flags&TYPEPART )
	{
		case CYLINDER_X:	// X aligned cylinder
		{	
			tRadius=(pB->sZ/2)+pD->radius;	// get radius of cylinder + object

			if ( pos->vx > (pB->pX+pB->sX+tRadius) || pos->vx < (pB->pX-tRadius) )
			{
				return(FALSE);
			}
			d.vy=pos->vy-( pB->pY + (pB->sY/2) );
			d.vz=pos->vz-( pB->pZ + (pB->sZ/2) );

			if ( pos->vx > (pB->pX+pB->sX) || pos->vx < pB->pX ) // do we need to do top and bottom stuff ?
			{
				if (pos->vx < pB->pX )
				{
					d.vx=pos->vx - pB->pX;
				}
				else
				{
					d.vx=pos->vx - (pB->pX+pB->sX);
				}
				dist=MakeUnit(&d);
				if (dist>tRadius) // inside cylinder radius ?
					return (FALSE);

				SCALEVECTOR(&d, (pB->sZ/2) );

				d.vy+=pB->pY + (pB->sY/2) ;
				d.vz+=pB->pZ + (pB->sZ/2) ;					
				
				if (d.vx>0)
					d.vx+=(pB->pX+pB->sX);
				else
					d.vx+=pB->pX;
				
				hit->vx=d.vx;
				hit->vy=d.vy;
				hit->vz=d.vz;

				pHitData->type=CYLINDER;
				pHitData->pCollBox=pB;
				return (TRUE);
			}
			else
			{
				d.vx=0;
				//dist=Magnitude(&d);
				//dist=Magnitude2D(d.vy,d.vz);
				dist=MakeUnit(&d);
				
				if (dist>tRadius) // inside cylinder radius ?
					return (FALSE);

				SCALEVECTOR(&d, (pB->sZ/2) );

				d.vy+=pB->pY + (pB->sY/2) ;
				d.vz+=pB->pZ + (pB->sZ/2) ;					
				d.vx=pos->vx;
				hit->vx=d.vx;
				hit->vy=d.vy;
				hit->vz=d.vz;

				//printf ("hit point  X %d Y %d Z %d radius %d\n",d.vx,d.vy,d.vz,pD->radius);


				pHitData->type=CYLINDER;
				pHitData->pCollBox=pB;
				return (TRUE);
			}
			break;
		}
		case CYLINDER_Y:	// Y aligned cylinder
		{	
			// do bounds check first
			tRadius=(pB->sZ/2)+pD->radius;	// get radius of cylinder + object

			if ( (pos->vy > ( pB->pY+tRadius )) || (pos->vy < ((pB->pY-tRadius)+pB->sY )) )
			{
				return(FALSE);
			}

			d.vx=pos->vx-( pB->pX + (pB->sX/2) );
			d.vz=pos->vz-( pB->pZ + (pB->sZ/2) );

			if ( pos->vy > (pB->pY) || pos->vy < (pB->pY+pB->sY) )	// do we have to muck about with top and bottom ?
			{
// Top & Bottom of the Cylinder. Middle section's below
				if (pos->vy > pB->pY )
				{
					d.vy=pos->vy - pB->pY;
				}
				else
				{
					d.vy=pos->vy - (pB->pY+pB->sY);
				}
				dist=MakeUnit(&d);
				if (dist>tRadius) // inside cylinder radius ?
					return (FALSE);

// New from Fred - Store the normal NOW, rather than leaving to "UpdateCylinder"
				pHitData->normal.vx =  d.vx;
				pHitData->normal.vy =  -d.vy;
				pHitData->normal.vz =  d.vz;
//				DB("Cyl Normal calc at checking time = %d %d %d\n",pHitData->normal.vx,pHitData->normal.vy,pHitData->normal.vz);

				SCALEVECTOR(&d, (pB->sZ/2) );
				d.vx+=pB->pX + (pB->sX/2) ;
				d.vz+=pB->pZ + (pB->sZ/2) ;					
				
				if (d.vy<0)
					d.vy+=(pB->pY+pB->sY);
				else
					d.vy+=pB->pY;
				
				hit->vx=d.vx;
				hit->vy=d.vy;
				hit->vz=d.vz;

				pHitData->type=CYLINDER;
				pHitData->pCollBox=pB;
				return (TRUE);
			}
			else
			{
				d.vy=0;
				//dist=Magnitude(&d);
				//dist=Magnitude2D(d.vx,d.vz);
				dist=MakeUnit(&d);

// New from Fred - Store the normal NOW, rather than leaving to "UpdateCylinder"
				pHitData->normal.vx =  d.vx;
				pHitData->normal.vy = -d.vy;
				pHitData->normal.vz =  d.vz;

				if (dist>tRadius) // inside cylinder radius ?
					return (FALSE);

				SCALEVECTOR(&d, (pB->sZ/2) );
				d.vx+=pB->pX + (pB->sX/2) ;
				d.vz+=pB->pZ + (pB->sZ/2) ;					
				d.vy=pos->vy;

				hit->vx=d.vx;
				hit->vy=d.vy;
				hit->vz=d.vz;

				pHitData->type=CYLINDER;
				pHitData->pCollBox=pB;
				return (TRUE);
			}
			break;
		}
		case CYLINDER_Z:	// Z aligned cylinder
		{
			tRadius=(pB->sX/2)+pD->radius;	// get radius of cylinder + object

			if ( pos->vz > (pB->pZ+pB->sZ+tRadius) || pos->vz < (pB->pZ-tRadius) )
			{
				return(FALSE);
			}
			d.vx=pos->vx-( pB->pX + (pB->sX/2) );
			d.vy=pos->vy-( pB->pY + (pB->sY/2) );

			if ( pos->vz > (pB->pZ+pB->sZ) || pos->vz < pB->pZ ) // do we need to do top and bottom stuff ?
			{
				if (pos->vz < pB->pZ )
				{
					d.vz=pos->vz - pB->pZ;
				}
				else
				{
					d.vz=pos->vz - (pB->pZ+pB->sZ);
				}
				//dist=Magnitude(&d);
				dist=MakeUnit(&d);
				if (dist>tRadius) // inside cylinder radius ?
					return (FALSE);

				SCALEVECTOR(&d, (pB->sX/2) );

				d.vx+=pB->pX + (pB->sX/2) ;
				d.vy+=pB->pY + (pB->sY/2) ;

				
				if (d.vz>0)
					d.vz+=(pB->pZ+pB->sZ);
				else
					d.vz+=pB->pZ;
				
				hit->vx=d.vx;
				hit->vy=d.vy;
				hit->vz=d.vz;

				pHitData->type=CYLINDER;
				pHitData->pCollBox=pB;
				return (TRUE);
			}
			else
			{
				d.vz=0;
				//dist=Magnitude(&d);
				//dist=Magnitude2D(d.vx,d.vy);
				dist=MakeUnit(&d);
				if (dist>tRadius) // inside cylinder radius ?
					return (FALSE);

				SCALEVECTOR(&d, (pB->sX/2) );

				d.vx+=pB->pX + (pB->sX/2);
				d.vy+=pB->pY + (pB->sY/2);

				d.vz=pos->vz;
				hit->vx=d.vx;
				hit->vy=d.vy;
				hit->vz=d.vz;

				pHitData->type=CYLINDER;
				pHitData->pCollBox=pB;
				return (TRUE);
			}
			break;
		}
		default:
		{
			printf("Error in check Cylinders \n");
			CRASH;
		}

	}
}
/*	--------------------------------------------------------------------------------
	Function 	: CheckSpheres
	Purpose 	: Checks whether ball has hit a sphere
	Parameters 	: The usual
	Returns 	: 0 if no hit !0 if hit
	Info 		: 
*/

ULONG	CheckSpheres(COLLBOX *pB , COLLDATA *pD , HITDATA *pHitData )
{
	long	dist;
	long	tRadius;
	VECTOR	*pos=pD->pPos;
	VECTOR	*hit=&pHitData->pos;
	VECTOR	d,center;

	tRadius=pD->radius;
	//if ( (pos->vx+tRadius < pB->pX) || (pos->vx-tRadius > pB->pX-pB->sX ) ) return(FALSE); // no hit possable
	//if ( (pos->vy+tRadius < pB->pY) || (pos->vy-tRadius > pB->pY-pB->sY ) ) return(FALSE); // no hit possable
	//if ( (pos->vz+tRadius < pB->pZ) || (pos->vz-tRadius > pB->pZ-pB->sZ ) ) return(FALSE); // no hit possable

	//printf ("hit sphere\n");

	tRadius=pD->radius-(pB->sX/2);	// get total radius

	center.vx=(pB->pX-(pB->sX/2) );
	center.vy=(pB->pY+(pB->sY/2) );
	center.vz=(pB->pZ-(pB->sZ/2) );

	d.vx=pos->vx-center.vx;
	d.vy=pos->vy-center.vy;
	d.vz=pos->vz-center.vz;

//	dist=Magnitude(&d);
	dist=MakeUnit(&d);
	if (dist<tRadius)	// hit sphere
	{
//		DB("Hit Dude!\n");
//		effectsStartOverlay(5,0x00ff00);

		SCALEVECTOR( &d,-(pB->sX/2) );	// scale by sphere radius

		hit->vx=d.vx+center.vx;
		hit->vy=d.vy+center.vy;
		hit->vz=d.vz+center.vz;

		pHitData->type=SPHERE_H;
		pHitData->vel.vx=pB->sX;// using vel.vx to hold radius
		pHitData->pCollBox=pB;
		return(TRUE);
	}
	return(FALSE);
}

/*	--------------------------------------------------------------------------------
	Function 	: CheckRamps
	Purpose 	: Checks whether ball has hit a 'ramp' (see code)
	Parameters 	: The usual
	Returns 	: 0 if no hit !0 if hit
	Info 		: No bugs found yet
*/

char *pst[]={"--\0","XY\0","XZ\0","YZ\0"};


ULONG CheckRamps(COLLBOX *pB , COLLDATA *pD , HITDATA *pHitData)
{
	int vp;
	static VECTOR v1,v2;

	RAMPHEADER *pRampHeader;
	ULONG nVerts,nFaces;
	VECTOR *pVerts;
	ULONG *pFaces;
	ULONG f;
	int p;
	static VECTOR n,temp;
	static VECTOR iPos, iOldPos;
	static VECTOR vrt[3];

	long j,dist,dist2;
	long pX=pB->pX, pY=pB->pY, pZ=pB->pZ;
	long sX=pB->sX, sY=pB->sY, sZ=pB->sZ;
	int pt,k,touch;
	int tx,ty;
#ifndef PRECALC_COLLISION
	static VECTOR a;
	long dr, dr2;
#endif
	static Point2DType twoDpoints[4];
	Point2DType *p2D=twoDpoints;


	//if(((pD->pPos->vx)<=pX) || ((pD->pPos->vx)>=(pX+sX)) ||
	//	((pD->pPos->vy)>=pY) || ((pD->pPos->vy)<=(pY+sY)) ||
	//	((pD->pPos->vz)<=pZ) || ((pD->pPos->vz)>=(pZ+sZ)))
	//	return(0);

// Ramps are not really ramps as such. They're a mini mesh, which means we can collide with 
// arbitrary polygons within the bounding box. Slow, but we don't have to process very many.

	pRampHeader=pB->rampheader;
	nVerts=pRampHeader->nVerts;
	nFaces=pRampHeader->nFaces;
	pFaces=pRampHeader->pFaces;
	pVerts=pRampHeader->pVerts;

	iPos.vx=(pD->pPos->vx)/4096;
	iPos.vy=(pD->pPos->vy)/4096;
	iPos.vz=(pD->pPos->vz)/4096;

	iOldPos.vx=(pD->oldPos.vx)/4096;
	iOldPos.vy=(pD->oldPos.vy)/4096;
	iOldPos.vz=(pD->oldPos.vz)/4096;

//	hitCount=0;
					  
	vp=0; // This stops compiler warning

	for(p=0; p<nFaces; p++)
	{
		f=pFaces[p];

		// flags: bit 0:   0=tri, 1=quad
		// bit 1&2: 00=arbitrary poly, 01=XY plane, 10=XZ plane, 11=YZ plane

		pt=f&6;

//		nSides=3+(f&1);	// get number of sides	always 3!
		f=f>>8;

//		out=0;

 //		ASSERT((nSides==3)||(nSides==4));

		for(j=0; j<3; j++)
		{
			vp=f&(0x0f);
  //			v[c]=vp;
			f=f>>4;
			vrt[j].vx=pVerts[vp].vx/4096;
			vrt[j].vy=pVerts[vp].vy/4096;
			vrt[j].vz=pVerts[vp].vz/4096;
		}


//#ifndef PRECALC_COLLISION
 		SUBVECTOR(&v1, vrt, vrt+1);
		SUBVECTOR(&v2, vrt, vrt+2);
		n.vx=(v1.vy * v2.vz - v1.vz * v2.vy);
		n.vy=(v1.vz * v2.vx - v1.vx * v2.vz);
		n.vz=(v1.vx * v2.vy - v1.vy * v2.vx);
		MakeUnit(&n);
		a.vx = vrt->vx + pX/4096;
		a.vy = vrt->vy + pY/4096;
		a.vz = vrt->vz + pZ/4096;

//#endif
		// Find distance of new pos from plane




		switch(pt)
		{
		case 2:// XY
//			printf("XY slope found!\n");
			if (pD->pPos->vz>pD->oldPos.vz)
			{
				dist=pD->pPos->vz-(pVerts[vp].vz+pZ);
				dist2=pD->oldPos.vz-(pVerts[vp].vz+pZ);
//				n.vz=4095;
			}
			else
			{
				dist2=pD->pPos->vz-(pVerts[vp].vz+pZ);
				dist=pD->oldPos.vz-(pVerts[vp].vz+pZ);
//				n.vz=-4095;
			}

#ifdef PRECALC_COLLISION
			n.vx=0;
			n.vy=0;

//			n.vz = (v1.vx * v2.vy - v1.vy * v2.vx);
			n.vz= (vrt[0].vx - vrt[1].vx) * (vrt[0].vy - vrt[2].vy)
				- (vrt[0].vy - vrt[1].vy) * (vrt[0].vx - vrt[2].vx);
			if(n.vz > 0)
				n.vz = 4096;
			else
				n.vz = -4096;
#endif


			break;
		case 4:// XZ
//			printf("XZ slope found!\n");
			if (pD->pPos->vy>pD->oldPos.vy)
			{
				dist=pD->pPos->vy-(pVerts[vp].vy+pY);
				dist2=pD->oldPos.vy-(pVerts[vp].vy+pY);
//				n.vy=-4095;	// rats, this doesn't work.
			}
			else
			{
				dist2=pD->pPos->vy-(pVerts[vp].vy+pY);
				dist=pD->oldPos.vy-(pVerts[vp].vy+pY);
//				n.vy=4095;
			}

#ifdef PRECALC_COLLISION
			n.vx=0;
			n.vz=0;

//		n.vy=(v1.vz * v2.vx - v1.vx * v2.vz);


// ok, here's the flat-plane normal calculation
// (find a space for this in bff_coll?)
			n.vy= (vrt[0].vz - vrt[1].vz) * (vrt[0].vx - vrt[2].vx)
				- (vrt[0].vx - vrt[1].vx) * (vrt[0].vz - vrt[2].vz);

			if(n.vy > 0)
				n.vy = 4096;
			else
				n.vy = -4096;
#endif
			break;


		case 6:// YZ
			if (pD->pPos->vx>pD->oldPos.vx)
			{
				dist=pD->pPos->vx-(pVerts[vp].vx+pX);
				dist2=pD->oldPos.vx-(pVerts[vp].vx+pX);
//				n.vx=4095;
			}
			else
			{
				dist2=pD->pPos->vx-(pVerts[vp].vx+pX);
				dist=pD->oldPos.vx-(pVerts[vp].vx+pX);
//				n.vx=-4095;
			}

#ifdef PRECALC_COLLISION
			n.vy=0;
			n.vz=0;
//		n.vx=(v1.vy * v2.vz - v1.vz * v2.vy);
			n.vx= (vrt[0].vy - vrt[1].vy) * (vrt[0].vz - vrt[2].vz)
				- (vrt[0].vz - vrt[1].vz) * (vrt[0].vy - vrt[2].vy);
			if(n.vx > 0)
				n.vx = 4096;
			else
				n.vx = -4096;
#endif


			break;
		default:// a sloped ramp (not sure if these need to swap on direction)


#ifdef PRECALC_COLLISION
			n.vx=pRampHeader->normal_x;	  //would be good, not to have to copy this stuff!
			n.vy=pRampHeader->normal_y;
			n.vz=pRampHeader->normal_z;
			j=pRampHeader->plane;
			dist=(DotProduct(&n, &iPos)-j)*4096;
			dist2=(DotProduct(&n, &iOldPos)-j)*4096;
#else

			j=-DotProduct(&n, &a);
			dist=(DotProduct(&n, &iPos)+j)*4096;
			dist2=(DotProduct(&n, &iOldPos)+j)*4096;
#endif
		}


#ifdef PRECALC_COLLISION
		if(((dist+(pD->radius))>=0) && ((dist2-(pD->radius))<=0))  //has hit somewhere on the plane, of infinate size
#else
 		dr=dist+(pD->radius);
 		dr2=dist2-(pD->radius);
		if((dr>=0) && (dr2<=0))  //has hit somewhere on the plane, of infinate size
#endif
		{
			// Where on ramp have we hit?
			// normal may be needed later ...
			switch(pt)
			{
			case 2:
				COPYVECTOR(&(pD->hitPos), pD->pPos);
				pD->hitPos.vz=((pVerts[vp].vz)+pZ);// This causes a bug (fixed?)
				break;
			case 4:
				COPYVECTOR(&(pD->hitPos), pD->pPos);
				pD->hitPos.vy=((pVerts[vp].vy)+pY);//+(pD->radius);
				break;
			case 6:
				COPYVECTOR(&(pD->hitPos), pD->pPos);
				pD->hitPos.vx=((pVerts[vp].vx)+pX);// This causes a bug (fixed?)
				break;
			default:
				COPYVECTOR(&temp, &n);
				SCALEVECTOR(&temp, -dist);
				ADDVECTOR(&(pD->hitPos), pD->pPos, &temp);
			}

			// is it within the collision box?
			if(((pD->hitPos.vx)>=pX) && ((pD->hitPos.vx)<=(pX+sX)) &&
				((pD->hitPos.vy)<=pY) && ((pD->hitPos.vy)>=(pY+sY)) &&
				((pD->hitPos.vz)>=pZ) && ((pD->hitPos.vz)<=(pZ+sZ)))
			{
				//CDB("Point (%d,%d,%d) ", pD->hitPos.vx/4096, pD->hitPos.vy/4096, pD->hitPos.vz/4096);
				//CDB("in (%d,%d,%d)-", pX/4096,pY/4096,pZ/4096);
				//CDB("(%d,%d,%d) ", (pX+sX)/4096, (pY+sY)/4096, (pZ+sZ)/4096); 
				touch=TRUE;

				if(pt)
				{
					switch(pt)
					{
					case 2:	//CDB("XY\n");
						for(k=0; k<3; k++)
						{
							p2D[k].x=(vrt[k].vx)+(pX/4096);
							p2D[k].y=(vrt[k].vy)+(pY/4096);
						}
						tx=pD->hitPos.vx/4096;
						ty=pD->hitPos.vy/4096;

						//if(!pointInPoly(tx,ty, 4, p2D))
						//	touch=FALSE;
						break;

					case 4:	//CDB("XZ\n");
						for(k=0; k<3; k++)
						{
							p2D[k].x=(vrt[k].vx)+(pX/4096);
							p2D[k].y=(vrt[k].vz)+(pZ/4096);
						}
						tx=pD->hitPos.vx/4096;
						ty=pD->hitPos.vz/4096;

						//if(!pointInPoly(tx,ty, 4, p2D))
						//	touch=FALSE;

						break;
					case 6:		//CDB("YZ\n");
						for(k=0; k<3; k++)
						{
							p2D[k].x=(vrt[k].vy)+(pY/4096);
							p2D[k].y=(vrt[k].vz)+(pZ/4096);
							//CDB("v[%d].x=%d ", k, vrt[k].vx);
						}
						//CDB("\n");
						tx=pD->hitPos.vy/4096;
						ty=pD->hitPos.vz/4096;

						//if(!pointInPoly(tx,ty, 4, p2D))
						//	touch=FALSE;
						break;
					default:

						ASSERT(0); // This should never happen
						CRASH;
					}

					touch=pointInTri(tx,ty,p2D);  //is it inside triangle?
				}

				if(touch)
				{

					//if(PRINTRAMP) DB("Hello Radius=%d\n", pD->radius);
					// interpolate back up to allow for radius
					COPYVECTOR( &(pHitData->rampPos),&(pD->hitPos) );
					/*
					if (n.vy<0)
					{
						temp.vx=n.vy;
						n.vy=-n.vx;
						n.vx=temp.vx;
					}
					*/

					COPYVECTOR(&temp, &n);

					SCALEVECTOR(&temp, -(pD->radius+1));

					ADDTOVECTOR(&(pD->hitPos), &temp);

					COPYVECTOR(&pHitData->pos, &(pD->hitPos));

					COPYVECTOR(&pHitData->vel, pD->pVel);

					pHitData->type=RAMP_H;
					pHitData->pCollBox=pB;
					COPYVECTOR(&pHitData->normal, &n);

					pHitData->plane=NULL;
					/*
					if (pD==&gloveColl)
					{
						printf ("glove hit \n");
						printf ("hit pos x %d y %d z %d \n",pHitData->pos.vx,pHitData->pos.vy,pHitData->pos.vz);
					}
				  */	
					switch(pt)
					{
					case 2:
						if (pD->pVel->vz>0) pHitData->plane=D_XYPLANE;
						else pHitData->plane=U_XYPLANE;
						break;
					case 4:
						if (n.vy>0) pHitData->plane=D_XZPLANE;
						else pHitData->plane=U_XZPLANE;
						break;
					case 6:
						if (pD->pVel->vx>0) pHitData->plane=D_YZPLANE;
						else pHitData->plane=U_YZPLANE;
						break;
					}
					return(TRUE);
				}
			}
		}
	}
	return(0);
}

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

void UpdateRampCollision(COLLDATA *pD , HITDATA *pHitData , VECTOR *collPos , VECTOR *rebound)
{
  //	VECTOR v0v1, v0v2;
 //	long magv0v1, magv0v2;
	//long div;
//	long mag;

	/*SUBVECTOR(&v0v1, pD->pPos, &pD->oldPos);
	magv0v1=Magnitude(&v0v1);

 	if(magv0v1)
 	{
		PRINTNUMV(magv0v1);
 		SUBVECTOR(&v0v2, &pHitData->pos, &pD->oldPos);
 		magv0v2=Magnitude(&v0v2);
		PRINTNUMV(magv0v2);

 		div=(magv0v1*4096)/magv0v2;

		PRINTNUMV(div);
		PRINTNEWL;

 		SUBVECTOR(&velDiff, pD->pVel, &pD->oldVel);
 		SCALEVECTOR(&velDiff, div);
 		COPYVECTOR(&pHitData->vel, &pD->oldVel);
 	}
 	else
 		COPYVECTOR(&pHitData->vel, pD->pVel);
	*/

	//pHitData->normal.vx=-pHitData->normal.vx;
	//pHitData->normal.vz=-pHitData->normal.vz;

	pHitData->normal.vy=-pHitData->normal.vy;

	//if (PRINTRAMP) DB("VEL=(%d,%d,%d)\n", pHitData->vel.vx, pHitData->vel.vy, pHitData->vel.vz);

	//printf ("ramp normal X %d Y %d Z %d\n",pHitData->normal.vx,pHitData->normal.vy,pHitData->normal.vz);
	MakeUnit(&pHitData->normal);
	
	//mag=Magnitude(&pHitData->vel)+1;
	//COPYVECTOR(rebound, &pHitData->vel);
	//CalcBounce(rebound, &pHitData->normal);
	//SCALEVECTOR(rebound, mag);

	if (PRINTRAMP) DB("REB=(%d,%d,%d)\n", rebound->vx, rebound->vy, rebound->vz);

	// Note:- don't change this back
	if ( pHitData->normal.vx>0 && (pD->pPos->vx>pHitData->pos.vx) ) pD->pPos->vx=pHitData->pos.vx;
	if ( pHitData->normal.vx<0 && (pD->pPos->vx<pHitData->pos.vx) ) pD->pPos->vx=pHitData->pos.vx;

	if ( pHitData->normal.vy<0 && (pD->pPos->vy>pHitData->pos.vy) ) pD->pPos->vy=pHitData->pos.vy;
	if ( pHitData->normal.vy>0 && (pD->pPos->vy<pHitData->pos.vy) ) pD->pPos->vy=pHitData->pos.vy;

	if ( pHitData->normal.vz>0 && (pD->pPos->vz>pHitData->pos.vz) ) pD->pPos->vz=pHitData->pos.vz;
	if ( pHitData->normal.vz<0 && (pD->pPos->vz<pHitData->pos.vz) ) pD->pPos->vz=pHitData->pos.vz;

	//pHitData->normal.vy=-pHitData->normal.vy;

	//if (pD==&gloveColl) gloveVel.vy=-gloveVel.vy;

	//pD->pPos->vy=pHitData->pos.vy;
	//pD->pPos->vz=pHitData->pos.vz;
	
	
	//COPYVECTOR(pD->pPos, &pHitData->pos);
	//COPYVECTOR(&pD->oldPos, &pHitData->pos);
}


/*	--------------------------------------------------------------------------------
	Function 	: UpdateMultiRampCollision
	Purpose 	: Updates positions for more than one ramp collision
	Parameters 	: ramps
	Returns 	: null
	Info 		: No bugs found yet
*/


/*****************************************************************************************/
void	UpdateMultiRampCollision(COLLDATA *pD , VECTOR *collPos , VECTOR *rebound)
{
LONG	loop;
LONG	xChange=0,yChange=0,zChange=0;
HITDATA *pHitData;

	for (loop=0;loop<pD->nRampHits;loop++)
	{
		pHitData=swap[loop];

		pHitData->normal.vy=-pHitData->normal.vy;

		MakeUnit(&pHitData->normal);
	
		if (PRINTRAMP) DB("REB=(%d,%d,%d)\n", rebound->vx, rebound->vy, rebound->vz);

		// Note:- don't change this back
		if ( pHitData->normal.vx>0 && (pD->pPos->vx>pHitData->pos.vx) && xChange<=0 )
		{
			pD->pPos->vx=pHitData->pos.vx;
			xChange=pHitData->pos.vx-pD->pPos->vx;
		}
		if ( pHitData->normal.vx<0 && (pD->pPos->vx<pHitData->pos.vx) && xChange>=0 )
		{
			pD->pPos->vx=pHitData->pos.vx;
			xChange=pHitData->pos.vx-pD->pPos->vx;
		}

		if ( pHitData->normal.vy<0 && (pD->pPos->vy>pHitData->pos.vy) && yChange<=0 )
		{
			pD->pPos->vy=pHitData->pos.vy;
			yChange=pHitData->pos.vy-pD->pPos->vy;
		}
		if ( pHitData->normal.vy>0 && (pD->pPos->vy<pHitData->pos.vy) && yChange>=0 )
		{
			pD->pPos->vy=pHitData->pos.vy;
			yChange=pHitData->pos.vy-pD->pPos->vy;
		}

		if ( pHitData->normal.vz>0 && (pD->pPos->vz>pHitData->pos.vz) && zChange<=0 )
		{
			pD->pPos->vz=pHitData->pos.vz;
			zChange=pHitData->pos.vz-pD->pPos->vz;
		}
		if ( pHitData->normal.vz<0 && (pD->pPos->vz<pHitData->pos.vz) && zChange>=0 )
		{
			pD->pPos->vz=pHitData->pos.vz;
			zChange=pHitData->pos.vz-pD->pPos->vz;
		}


		//if ( pHitData->normal.vx<0 && (pD->pPos->vx<pHitData->pos.vx) ) pD->pPos->vx=pHitData->pos.vx;

		//if ( pHitData->normal.vy>0 && (pD->pPos->vy>pHitData->pos.vy) ) pD->pPos->vy=pHitData->pos.vy;
		//if ( pHitData->normal.vy<0 && (pD->pPos->vy<pHitData->pos.vy) ) pD->pPos->vy=pHitData->pos.vy;

		//if ( pHitData->normal.vz>0 && (pD->pPos->vz>pHitData->pos.vz) ) pD->pPos->vz=pHitData->pos.vz;
		//if ( pHitData->normal.vz<0 && (pD->pPos->vz<pHitData->pos.vz) ) pD->pPos->vz=pHitData->pos.vz;

		//COPYVECTOR(pD->pPos, &pHitData->pos);
		//COPYVECTOR(&pD->oldPos, &pHitData->pos);
	}
}




/*	--------------------------------------------------------------------------------
	Function 	: UpdateEdgeCollision
	Purpose 	: Checks if ball has crossed plane
	Parameters 	: plane position
	Returns 	: 0 if no hit !0 if hit
	Info 		: No bugs found yet
*/
//-------------------------------------------------------------------------------//


void	UpdateEdgeCollision(COLLDATA *pD , HITDATA *pHitData , VECTOR *collPos , VECTOR *rebound)
{

	VECTOR	objectmove,normal;	// changed from FVECTOR
	long	deltaX,deltaY,deltaZ;
  //	long	mag;

	if ( pHitData->plane & D_XZPLANE ) // top 
	{
		if ( pHitData->plane & U_YZPLANE ) // left
		{
			// Top Left
			deltaX=( pHitData->pos.vx - pD->pPos->vx );
			deltaY=( pHitData->pos.vy - pD->pPos->vy );
			deltaZ=0;

			if (deltaX<0) deltaX=0;
			if (deltaY<0) deltaY=0;
			if (deltaX==0 && deltaY==0) deltaY=4096;	// Can happen if ball moving fast enought

			objectmove.vx=-deltaX;
			objectmove.vy=-deltaY;
			objectmove.vz=deltaZ;
			MakeUnit(&objectmove);

			normal.vx=objectmove.vx;
			normal.vy=objectmove.vy;
			normal.vz=objectmove.vz;
			//MakeUnit(&normal);

#ifdef SHITLOADSOFDEBUG
			if (pD==&gloveColl)
			{
				printf ("\nglove hit top left edge\n");
				printf ("delta    X %d , Y %d , Z %d\n",deltaX,deltaY,deltaZ);
				printf ("glovevel X %d , Y %d , Z %d\n",gloveVel.vx/1024,gloveVel.vy/1024,gloveVel.vz/1024);
				printf ("normal   X %d , Y %d , Z %d\n",normal.vx,normal.vy,normal.vz);
				printf ("hit pos  X %d , Y %d , Z %d\n",pHitData->pos.vx,pHitData->pos.vy,pHitData->pos.vz);
			}

#endif


			SCALEVECTOR(&objectmove,(pD->radius+1) );
				
			if ( (pD->pPos->vx > pHitData->pos.vx+objectmove.vx) && (deltaX) )
				pD->pPos->vx=pD->oldPos.vx=pHitData->pos.vx+objectmove.vx;

			if ( (pD->pPos->vy > pHitData->pos.vy+objectmove.vy) && (deltaY) )
				pD->pPos->vy=pD->oldPos.vy=pHitData->pos.vy+objectmove.vy;

		}
		else if ( pHitData->plane & D_YZPLANE ) // right
		{
			// Top Right

			deltaX=( pHitData->pos.vx - pD->pPos->vx );
			deltaY=( pHitData->pos.vy - pD->pPos->vy );
			deltaZ=0;

			if (deltaX>0) deltaX=0;
			if (deltaY<0) deltaY=0;
			if (deltaX==0 && deltaY==0) deltaY=4096;	// Can happen if ball moving fast enought


			objectmove.vx=-deltaX;
			objectmove.vy=-deltaY;
			objectmove.vz=deltaZ;
			MakeUnit(&objectmove);

			normal.vx=objectmove.vx;
			normal.vy=objectmove.vy;
			normal.vz=objectmove.vz;
			//MakeUnit(&normal);

#ifdef SHITLOADSOFDEBUG
			if (pD==&gloveColl)
			{
				printf ("\nglove hit top right edge\n");
				printf ("delta    X %d , Y %d , Z %d\n",deltaX,deltaY,deltaZ);
				printf ("glovevel X %d , Y %d , Z %d\n",gloveVel.vx/1024,gloveVel.vy/1024,gloveVel.vz/1024);
				printf ("normal   X %d , Y %d , Z %d\n",normal.vx,normal.vy,normal.vz);
				printf ("hit pos  X %d , Y %d , Z %d\n",pHitData->pos.vx,pHitData->pos.vy,pHitData->pos.vz);
			}
#endif
			SCALEVECTOR(&objectmove,(pD->radius+1) );
				
			if ( (pD->pPos->vx < pHitData->pos.vx+objectmove.vx) && (deltaX) )
				pD->pPos->vx=pD->oldPos.vx=pHitData->pos.vx+objectmove.vx;

			if ( (pD->pPos->vy > pHitData->pos.vy+objectmove.vy) && (deltaY) )
				pD->pPos->vy=pD->oldPos.vy=pHitData->pos.vy+objectmove.vy;

		}
		else if ( pHitData->plane & U_XYPLANE ) // close
		{
			// Top Near

			deltaX=0;
			deltaY=( pHitData->pos.vy - pD->pPos->vy );
			deltaZ=( pHitData->pos.vz - pD->pPos->vz );

			if (deltaY<0) deltaY=0;
			if (deltaZ<0) deltaZ=0;
			if (deltaY==0 && deltaZ==0) deltaY=4096;	// Can happen if ball moving fast enought


			objectmove.vx=deltaX;
			objectmove.vy=-deltaY;
			objectmove.vz=-deltaZ;
			MakeUnit(&objectmove);

			normal.vx=objectmove.vx;
			normal.vy=objectmove.vy;
			normal.vz=objectmove.vz;
			//MakeUnit(&normal);

#ifdef SHITLOADSOFDEBUG
			if (pD==&gloveColl)
			{
				printf ("\nglove hit top near edge\n");
				printf ("delta    X %d , Y %d , Z %d\n",deltaX,deltaY,deltaZ);
				printf ("glovevel X %d , Y %d , Z %d\n",gloveVel.vx/1024,gloveVel.vy/1024,gloveVel.vz/1024);
				printf ("normal   X %d , Y %d , Z %d\n",normal.vx,normal.vy,normal.vz);
				printf ("hit pos  X %d , Y %d , Z %d\n",pHitData->pos.vx,pHitData->pos.vy,pHitData->pos.vz);
			}
#endif


			SCALEVECTOR(&objectmove,(pD->radius+1) );

			if ( (pD->pPos->vy > pHitData->pos.vy+objectmove.vy) && (deltaY) )
				pD->pPos->vy=pD->oldPos.vy=pHitData->pos.vy+objectmove.vy;

			if ( (pD->pPos->vz > pHitData->pos.vz+objectmove.vz) && (deltaZ) )
				pD->pPos->vz=pD->oldPos.vz=pHitData->pos.vz+objectmove.vz;
		}
		else if ( pHitData->plane & D_XYPLANE ) // far
		{
			// Top Far

			deltaX=0;
			deltaY=( pHitData->pos.vy - pD->pPos->vy );
			deltaZ=( pHitData->pos.vz - pD->pPos->vz );

			if (deltaY<0) deltaY=0;
			if (deltaZ>0) deltaZ=0;
			if (deltaY==0 && deltaZ==0) deltaY=4096;	// Can happen if ball moving fast enought

			objectmove.vx=deltaX;
			objectmove.vy=-deltaY;
			objectmove.vz=-deltaZ;
			MakeUnit(&objectmove);

			normal.vx=objectmove.vx;
			normal.vy=objectmove.vy;
			normal.vz=objectmove.vz;
			//MakeUnit(&normal);
#ifdef SHITLOADSOFDEBUG
			if (pD==&gloveColl)
			{
				printf ("\nglove hit top far edge\n");
				printf ("delta    X %d , Y %d , Z %d\n",deltaX,deltaY,deltaZ);
				printf ("glovevel X %d , Y %d , Z %d\n",gloveVel.vx/1024,gloveVel.vy/1024,gloveVel.vz/1024);
				printf ("normal   X %d , Y %d , Z %d\n",normal.vx,normal.vy,normal.vz);
				printf ("hit pos  X %d , Y %d , Z %d\n",pHitData->pos.vx,pHitData->pos.vy,pHitData->pos.vz);
			}
#endif


			SCALEVECTOR(&objectmove,(pD->radius+1) );

			if ( (pD->pPos->vy > pHitData->pos.vy+objectmove.vy) && (deltaY) )
				pD->pPos->vy=pD->oldPos.vy=pHitData->pos.vy+objectmove.vy;

			if ( (pD->pPos->vz < pHitData->pos.vz+objectmove.vz) && (deltaZ) )
				pD->pPos->vz=pD->oldPos.vz=pHitData->pos.vz+objectmove.vz;
		}
		else if (PRINTERROR) printf ("ERROR on top plane\n");
	}
	else if ( pHitData->plane & U_XZPLANE ) // bottom
	{
		if ( pHitData->plane & U_YZPLANE ) // left
		{
			// Bottom left

			deltaX=( pHitData->pos.vx - pD->pPos->vx );
			deltaY=( pHitData->pos.vy - pD->pPos->vy );
			deltaZ=0;

			if (deltaX<0) deltaX=0;
			if (deltaY>0) deltaY=0;
			//if (deltaX==0 && deltaY==0) deltaY=4096;	// Can happen if ball moving fast enought

			objectmove.vx=-deltaX;
			objectmove.vy=-deltaY;
			objectmove.vz=deltaZ;
			MakeUnit(&objectmove);

			normal.vx=objectmove.vx;
			normal.vy=objectmove.vy;
			normal.vz=objectmove.vz;
			//MakeUnit(&normal);
#ifdef SHITLOADSOFDEBUG
			if (pD==&gloveColl)
			{
				printf ("\nglove hit bottom left edge\n");
				printf ("delta    X %d , Y %d , Z %d\n",deltaX,deltaY,deltaZ);
				printf ("glovevel X %d , Y %d , Z %d\n",gloveVel.vx/1024,gloveVel.vy/1024,gloveVel.vz/1024);
				printf ("normal   X %d , Y %d , Z %d\n",normal.vx,normal.vy,normal.vz);
				printf ("hit pos  X %d , Y %d , Z %d\n",pHitData->pos.vx,pHitData->pos.vy,pHitData->pos.vz);
			}
#endif

			SCALEVECTOR(&objectmove,(pD->radius+1) );
				
			if ( (pD->pPos->vx > pHitData->pos.vx+objectmove.vx) && (deltaX) )
				pD->pPos->vx=pD->oldPos.vx=pHitData->pos.vx+objectmove.vx;

			if ( (pD->pPos->vy < pHitData->pos.vy+objectmove.vy) && (deltaY) )
				pD->pPos->vy=pD->oldPos.vy=pHitData->pos.vy+objectmove.vy;

		}
		else if ( pHitData->plane & D_YZPLANE ) // right
		{
			// Bottom Right

			deltaX=( pHitData->pos.vx - pD->pPos->vx );
			deltaY=( pHitData->pos.vy - pD->pPos->vy );
			deltaZ=0;

			if (deltaX>0) deltaX=0;
			if (deltaY>0) deltaY=0;
			//if (deltaX==0 && deltaY==0) deltaY=4096;	// Can happen if ball moving fast enought


			objectmove.vx=-deltaX;
			objectmove.vy=-deltaY;
			objectmove.vz=deltaZ;
			MakeUnit(&objectmove);

			normal.vx=objectmove.vx;
			normal.vy=objectmove.vy;
			normal.vz=objectmove.vz;
			//MakeUnit(&normal);

#ifdef SHITLOADSOFDEBUG
			if (pD==&gloveColl)
			{
				printf ("\nglove hit bottom right edge\n");
				printf ("delta    X %d , Y %d , Z %d\n",deltaX,deltaY,deltaZ);
				printf ("glovevel X %d , Y %d , Z %d\n",gloveVel.vx/1024,gloveVel.vy/1024,gloveVel.vz/1024);
				printf ("normal   X %d , Y %d , Z %d\n",normal.vx,normal.vy,normal.vz);
				printf ("hit pos  X %d , Y %d , Z %d\n",pHitData->pos.vx,pHitData->pos.vy,pHitData->pos.vz);
			}
#endif
			SCALEVECTOR(&objectmove,(pD->radius+1) );
				
			if ( (pD->pPos->vx < pHitData->pos.vx+objectmove.vx) && (deltaX) )
				pD->pPos->vx=pD->oldPos.vx=pHitData->pos.vx+objectmove.vx;

			if ( (pD->pPos->vy < pHitData->pos.vy+objectmove.vy) && (deltaY) )
				pD->pPos->vy=pD->oldPos.vy=pHitData->pos.vy+objectmove.vy;
		}
		else if ( pHitData->plane & U_XYPLANE ) // near
		{
			// Bottom Near

			deltaX=0;
			deltaY=( pHitData->pos.vy - pD->pPos->vy );
			deltaZ=( pHitData->pos.vz - pD->pPos->vz );

			if (deltaY>0) deltaY=0;
			if (deltaZ<0) deltaZ=0;
			//if (deltaY==0 && deltaY==0) deltaY=4096;	// Can happen if ball moving fast enought

			objectmove.vx=deltaX;
			objectmove.vy=-deltaY;
			objectmove.vz=-deltaZ;
			MakeUnit(&objectmove);

			normal.vx=objectmove.vx;
			normal.vy=objectmove.vy;
			normal.vz=objectmove.vz;
			//MakeUnit(&normal);
#ifdef SHITLOADSOFDEBUG
			if (pD==&gloveColl)
			{
				printf ("\nglove hit bottom near edge\n");
				printf ("delta    X %d , Y %d , Z %d\n",deltaX,deltaY,deltaZ);
				printf ("glovevel X %d , Y %d , Z %d\n",gloveVel.vx/1024,gloveVel.vy/1024,gloveVel.vz/1024);
				printf ("normal   X %d , Y %d , Z %d\n",normal.vx,normal.vy,normal.vz);
				printf ("hit pos  X %d , Y %d , Z %d\n",pHitData->pos.vx,pHitData->pos.vy,pHitData->pos.vz);
			}
#endif
			SCALEVECTOR( &objectmove , (pD->radius+1) );

			if ( (pD->pPos->vy < pHitData->pos.vy+objectmove.vy) && (deltaY) )
				pD->pPos->vy=pD->oldPos.vy=pHitData->pos.vy+objectmove.vy;

			if ( (pD->pPos->vz > pHitData->pos.vz+objectmove.vz) && (deltaZ) )
				pD->pPos->vz=pD->oldPos.vz=pHitData->pos.vz+objectmove.vz;

			/*if (pD==&gloveColl)
			{
				gloveVel.vy=0;
				pD->pPos->vy=pHitData->pos.vy+(2*4096);
				//if (!GloveCtrl.speed) GloveCtrl.speed=1;
				GloveCtrl.onLava=TRUE;	// on lava is a frig to stop the position hold kicking in
			}
			*/
		}

		else if ( pHitData->plane & D_XYPLANE ) // far
		{
			// Bottom Far

			deltaX=0;
			deltaY=( pHitData->pos.vy - pD->pPos->vy );
			deltaZ=( pHitData->pos.vz - pD->pPos->vz );

			if (deltaY>0) deltaY=0;
			if (deltaZ>0) deltaZ=0;
			//if (deltaY==0 && deltaY==0) deltaY=4096;	// Can happen if ball moving fast enought

			objectmove.vx=deltaX;
			objectmove.vy=-deltaY;
			objectmove.vz=-deltaZ;
			MakeUnit(&objectmove);

			normal.vx=objectmove.vx;
			normal.vy=objectmove.vy;
			normal.vz=objectmove.vz;
			//MakeUnit(&normal);

#ifdef SHITLOADSOFDEBUG
			if (pD==&gloveColl)
			{
				printf ("\nglove hit bottom far edge\n");
				printf ("delta    X %d , Y %d , Z %d\n",deltaX,deltaY,deltaZ);
				printf ("glovevel X %d , Y %d , Z %d\n",gloveVel.vx/1024,gloveVel.vy/1024,gloveVel.vz/1024);
				printf ("normal   X %d , Y %d , Z %d\n",normal.vx,normal.vy,normal.vz);
				printf ("hit pos  X %d , Y %d , Z %d\n",pHitData->pos.vx,pHitData->pos.vy,pHitData->pos.vz);
			}
#endif
			SCALEVECTOR(&objectmove,(pD->radius+1) );

			if ( (pD->pPos->vy < pHitData->pos.vy+objectmove.vy) && (deltaY) )
				pD->pPos->vy=pD->oldPos.vy=pHitData->pos.vy+objectmove.vy;

			if ( (pD->pPos->vz < pHitData->pos.vz+objectmove.vz) && (deltaZ) )
				pD->pPos->vz=pD->oldPos.vz=pHitData->pos.vz+objectmove.vz;
		}
		else if (PRINTERROR) printf ("ERROR on bottom plane\n");
	}
	else if ( pHitData->plane & D_YZPLANE ) // Right
	{
		if ( pHitData->plane & D_XYPLANE ) // far
		{
			// Right Far

			deltaX=( pHitData->pos.vx - pD->pPos->vx);
			deltaY=0;
			deltaZ=( pHitData->pos.vz - pD->pPos->vz);

			if (deltaX>0) deltaX=0;
			if (deltaZ>0) deltaZ=0;

			objectmove.vx=-deltaX;
			objectmove.vy=deltaY;
			objectmove.vz=-deltaZ;
			MakeUnit(&objectmove);

			normal.vx=objectmove.vx;
			normal.vy=objectmove.vy;
			normal.vz=objectmove.vz;
			//MakeUnit(&normal);

#ifdef SHITLOADSOFDEBUG
			if (pD==&gloveColl)
			{
				printf ("\nglove hit right far edge\n");
				printf ("delta    X %d , Y %d , Z %d\n",deltaX,deltaY,deltaZ);
				printf ("glovevel X %d , Y %d , Z %d\n",gloveVel.vx/1024,gloveVel.vy/1024,gloveVel.vz/1024);
				printf ("normal   X %d , Y %d , Z %d\n",normal.vx,normal.vy,normal.vz);
				printf ("hit pos  X %d , Y %d , Z %d\n",pHitData->pos.vx,pHitData->pos.vy,pHitData->pos.vz);
			}
#endif
			SCALEVECTOR(&objectmove,(pD->radius+1) );

			if ( (pD->pPos->vx < pHitData->pos.vx+objectmove.vx) && (deltaX) )
				pD->pPos->vx=pD->oldPos.vx=pHitData->pos.vx+objectmove.vx;

			if ( (pD->pPos->vz < pHitData->pos.vz+objectmove.vz) && (deltaZ) )
				pD->pPos->vz=pD->oldPos.vz=pHitData->pos.vz+objectmove.vz;

		}

		else if ( pHitData->plane & U_XYPLANE ) // near
		{
			// Right Near

			deltaX=( pHitData->pos.vx - pD->pPos->vx);
			deltaY=0;
			deltaZ=( pHitData->pos.vz - pD->pPos->vz);

			if (deltaX>0) deltaX=0;
			if (deltaZ<0) deltaZ=0;

			objectmove.vx=-deltaX;
			objectmove.vy=deltaY;
			objectmove.vz=-deltaZ;
			MakeUnit(&objectmove);

			normal.vx=objectmove.vx;
			normal.vy=objectmove.vy;
			normal.vz=objectmove.vz;
			//MakeUnit(&normal);
#ifdef SHITLOADSOFDEBUG
			if (pD==&gloveColl)
			{
				printf ("\nglove hit right near edge\n");
				printf ("delta    X %d , Y %d , Z %d\n",deltaX,deltaY,deltaZ);
				printf ("glovevel X %d , Y %d , Z %d\n",gloveVel.vx/1024,gloveVel.vy/1024,gloveVel.vz/1024);
				printf ("normal   X %d , Y %d , Z %d\n",normal.vx,normal.vy,normal.vz);
				printf ("hit pos  X %d , Y %d , Z %d\n",pHitData->pos.vx,pHitData->pos.vy,pHitData->pos.vz);
			}
#endif

			SCALEVECTOR(&objectmove,(pD->radius+1) );

			if ( (pD->pPos->vx < pHitData->pos.vx+objectmove.vx) && (deltaX) )
				pD->pPos->vx=pD->oldPos.vx=pHitData->pos.vx+objectmove.vx;

			if ( (pD->pPos->vz > pHitData->pos.vz+objectmove.vz) && (deltaZ) )
				pD->pPos->vz=pD->oldPos.vz=pHitData->pos.vz+objectmove.vz;
		}
		else if (PRINTERROR) printf ("error on right\n");
	}
	else if ( pHitData->plane & U_YZPLANE ) // left
	{
		if ( pHitData->plane & D_XYPLANE ) // far
		{
			// Left Far

			deltaX=( pHitData->pos.vx - pD->pPos->vx);
			deltaY=0;
			deltaZ=( pHitData->pos.vz - pD->pPos->vz);

			if (deltaX<0) deltaX=0;
			if (deltaZ>0) deltaZ=0;

			objectmove.vx=-deltaX;
			objectmove.vy=deltaY;
			objectmove.vz=-deltaZ;
			MakeUnit(&objectmove);

			normal.vx=objectmove.vx;
			normal.vy=objectmove.vy;
			normal.vz=objectmove.vz;
			//MakeUnit(&normal);

#ifdef SHITLOADSOFDEBUG
			if (pD==&gloveColl)
			{
				printf ("\nglove hit left far edge\n");
				printf ("delta    X %d , Y %d , Z %d\n",deltaX,deltaY,deltaZ);
				printf ("glovevel X %d , Y %d , Z %d\n",gloveVel.vx/1024,gloveVel.vy/1024,gloveVel.vz/1024);
				printf ("normal   X %d , Y %d , Z %d\n",normal.vx,normal.vy,normal.vz);
				printf ("hit pos  X %d , Y %d , Z %d\n",pHitData->pos.vx,pHitData->pos.vy,pHitData->pos.vz);
			}
#endif
			SCALEVECTOR(&objectmove,(pD->radius+1) );

			if ( (pD->pPos->vx > pHitData->pos.vx+objectmove.vx) && (deltaX) )
				pD->pPos->vx=pD->oldPos.vx=pHitData->pos.vx+objectmove.vx;

			if ( (pD->pPos->vz < pHitData->pos.vz+objectmove.vz) && (deltaZ) )
				pD->pPos->vz=pD->oldPos.vz=pHitData->pos.vz+objectmove.vz;
		}
		else if ( pHitData->plane & U_XYPLANE ) // near
		{
			// Left Near
			deltaX=( pHitData->pos.vx - pD->pPos->vx);
			deltaY=0;
			deltaZ=( pHitData->pos.vz - pD->pPos->vz);

			if (deltaX<0) deltaX=0;
			if (deltaZ<0) deltaZ=0;

			objectmove.vx=-deltaX;
			objectmove.vy=deltaY;
			objectmove.vz=-deltaZ;
			MakeUnit(&objectmove);

			normal.vx=objectmove.vx;
			normal.vy=objectmove.vy;
			normal.vz=objectmove.vz;
			//MakeUnit(&normal);

#ifdef SHITLOADSOFDEBUG
			if (pD==&gloveColl)
			{
				printf ("\nglove hit left near edge\n");
				printf ("delta    X %d , Y %d , Z %d\n",deltaX,deltaY,deltaZ);
				printf ("glovevel X %d , Y %d , Z %d\n",gloveVel.vx/1024,gloveVel.vy/1024,gloveVel.vz/1024);
				printf ("normal   X %d , Y %d , Z %d\n",normal.vx,normal.vy,normal.vz);
				printf ("hit pos  X %d , Y %d , Z %d\n",pHitData->pos.vx,pHitData->pos.vy,pHitData->pos.vz);
			}
#endif

			SCALEVECTOR(&objectmove,(pD->radius+1) );

			if ( (pD->pPos->vx > pHitData->pos.vx+objectmove.vx) && (deltaX) )
				pD->pPos->vx=pD->oldPos.vx=pHitData->pos.vx+objectmove.vx;

			if ( (pD->pPos->vz > pHitData->pos.vz+objectmove.vz) && (deltaZ) )
				pD->pPos->vz=pD->oldPos.vz=pHitData->pos.vz+objectmove.vz;
		}
		else if (PRINTERROR) printf ("error on right\n");
	}
	else if (PRINTERROR) printf ("ERROR with Edge\n");


	normal.vx=-normal.vx;
	normal.vz=-normal.vz;

	pHitData->normal.vx=normal.vx;
	pHitData->normal.vy=normal.vy;
	pHitData->normal.vz=normal.vz;
}
/*	--------------------------------------------------------------------------------
	Function 	: RemoveRedundantEdges
	Purpose 	: 
	Parameters 	: 
	Returns 	: 
	Info 		: 
*/
//-------------------------------------------------------------------------------//


long	RemoveRedundantEdges(COLLDATA *pD , int *nPolysHit)
{
	HITDATA *edge[16];
	LONG	loop,loop1;
	LONG	removedEdges=0;

// Fred mod (see below -
	if (pD->nEdgeHits!=2)
		return 0;

	//printf ("polys hit %d \n",nPolysHit);

	loop1=0;
	for (loop=0;loop<*nPolysHit;loop++)
	{
		if (pHitData[loop].type==EDGE)
		{
			edge[loop1++]=&pHitData[loop];
		}
	}

// The other Fred mod.
//	if ( (pD->nEdgeHits==2) && loop1==2)
	if (loop1==2)
	{
#ifdef SHITLOADSOFDEBUG
		printf ("check for remove\n");
#endif
		if ( (edge[0]->pos.vx==edge[1]->pos.vx) && (edge[0]->pos.vy==edge[1]->pos.vy) && (edge[0]->pos.vz==edge[1]->pos.vz) )
		{
#ifdef SHITLOADSOFDEBUG
			printf ("removal possable\n");
#endif
			if ( ((edge[0]->plane & D_XZPLANE) && (edge[1]->plane & D_XZPLANE)) ||	//  top to top
				((edge[0]->plane & U_XZPLANE) && (edge[1]->plane & U_XZPLANE)) )	// bottom to bottom
			{
				if ( (edge[0]->plane & D_YZPLANE) && (edge[1]->plane & U_YZPLANE) )// 0=right 1=left
				{
					if ( pD->pPos->vx > edge[0]->pos.vx ) // is edge 0 or 1 redundant?
					{	// 0 redundant
						removedEdges++;
						//(*nPolysHit)--;
						edge[0]->type=128;
#ifdef SHITLOADSOFDEBUG
						printf ("top right removed\n");
#endif
					}
					else
					{	// 1 redundant
						removedEdges++;
						//(*nPolysHit)--;
						edge[1]->type=128;
#ifdef SHITLOADSOFDEBUG
						printf ("top left removed\n");
#endif
					}
				}
				else if ( (edge[0]->plane & U_YZPLANE) && (edge[1]->plane & D_YZPLANE) )// 0=left 1=right
				{
					if ( pD->pPos->vx < edge[0]->pos.vx ) // is edge 0 or 1 redundant?
					{	// 0 redundant
						removedEdges++;
						//(*nPolysHit)--;
						edge[0]->type=128;
#ifdef SHITLOADSOFDEBUG
						printf ("top left removed\n");
#endif
					}
					else
					{	// 1 redundant
						removedEdges++;
						//(*nPolysHit)--;
						edge[1]->type=128;
#ifdef SHITLOADSOFDEBUG
						printf ("top right removed\n");
#endif
					}
				}
				else if ( (edge[0]->plane & U_XYPLANE) && (edge[1]->plane & D_XYPLANE) )// 0=near 1=far
				{
					if ( pD->pPos->vz < edge[0]->pos.vz )
					{	// 0 redundant
						removedEdges++;
						//(*nPolysHit)--;
						edge[0]->type=128;
#ifdef SHITLOADSOFDEBUG
						printf ("top near removed\n");
#endif
					}
					else
					{	// 1 redundant
						removedEdges++;
						//(*nPolysHit)--;
						edge[1]->type=128;
#ifdef SHITLOADSOFDEBUG
						printf ("top far removed\n");
#endif
					}
				}
				else if ( (edge[0]->plane & D_XYPLANE) && (edge[1]->plane & U_XYPLANE) )// 0=far 1=near
				{
					if ( pD->pPos->vz > edge[0]->pos.vz )
					{	// 0 redundant
						removedEdges++;
						//(*nPolysHit)--;
						edge[0]->type=128;
#ifdef SHITLOADSOFDEBUG
						printf ("top far removed\n");
#endif
					}
					else
					{	// 1 redundant
						removedEdges++;
						//(*nPolysHit)--;
						edge[1]->type=128;
#ifdef SHITLOADSOFDEBUG
						printf ("top near removed\n");
#endif
					}
				}
			}
			if ( (edge[0]->plane & D_XZPLANE) && (edge[1]->plane & U_XZPLANE) ) // 0=top 1=bottom
			{
				if (((edge[0]->plane&U_YZPLANE) && (edge[1]->plane&U_YZPLANE)) || //left
					((edge[0]->plane&D_YZPLANE) && (edge[1]->plane&D_YZPLANE)) || //right
					((edge[0]->plane&U_XYPLANE) && (edge[1]->plane&U_XYPLANE)) || //near
					((edge[0]->plane&D_XYPLANE) && (edge[1]->plane&D_XYPLANE)) )//far
				{
					if ( pD->pPos->vy < edge[0]->pos.vy )
					{	// 0 redundant
						removedEdges++;
						//(*nPolysHit)--;
						edge[0]->type=128;
#ifdef SHITLOADSOFDEBUG
						printf ("top match removed\n");
#endif
					}
					else
					{	// 1 redundant
						removedEdges++;
						//(*nPolysHit)--;
						edge[1]->type=128;
#ifdef SHITLOADSOFDEBUG
						printf ("bottom match removed\n");
#endif
					}
				}
			}
			if ( (edge[0]->plane & U_XZPLANE) && (edge[1]->plane & D_XZPLANE) ) // 0=bottom 1=top
			{
				if (((edge[0]->plane&U_YZPLANE) && (edge[1]->plane&U_YZPLANE)) || //left
					((edge[0]->plane&D_YZPLANE) && (edge[1]->plane&D_YZPLANE)) || //right
					((edge[0]->plane&U_XYPLANE) && (edge[1]->plane&U_XYPLANE)) || //near
					((edge[0]->plane&D_XYPLANE) && (edge[1]->plane&D_XYPLANE)) )//far
				{
					if ( pD->pPos->vy > edge[0]->pos.vy )
					{	// 0 redundant
						removedEdges++;
						//(*nPolysHit)--;
						edge[0]->type=128;
#ifdef SHITLOADSOFDEBUG
						printf ("top match removed\n");
#endif
					}
					else
					{	// 1 redundant
						removedEdges++;
						//(*nPolysHit)--;
						edge[1]->type=128;
#ifdef SHITLOADSOFDEBUG
						printf ("bottom match removed\n");
#endif
					}
				}
			}
			if ((((edge[0]->plane&U_XYPLANE) && (edge[1]->plane&U_XYPLANE))  || // near
				 ((edge[0]->plane&D_XYPLANE) && (edge[1]->plane&D_XYPLANE))) && // far
				(((edge[0]->plane&U_YZPLANE) && (edge[1]->plane&D_YZPLANE))  || // 0=left 1=right
				 ((edge[0]->plane&D_YZPLANE) && (edge[1]->plane&U_YZPLANE))) )	// 0=right1=left
			{
				if (edge[0]->plane&U_YZPLANE) // if on left side
				{
					if ( pD->pPos->vx > edge[0]->pos.vx )
					{	// 1 redundant
						removedEdges++;
						//(*nPolysHit)--;
						edge[1]->type=128;
#ifdef SHITLOADSOFDEBUG
						printf ("left match removed\n");
#endif
					}
					else
					{	// 0 redundant
						removedEdges++;
						//(*nPolysHit)--;
						edge[0]->type=128;
#ifdef SHITLOADSOFDEBUG
						printf ("right match removed\n");
#endif
					}
				}
				else if ( pD->pPos->vx < edge[0]->pos.vx )
				{	// 1 redundant
					removedEdges++;
					//(*nPolysHit)--;
					edge[1]->type=128;
#ifdef SHITLOADSOFDEBUG
					printf ("right match removed\n");
#endif
				}
				else
				{	// 0 redundant
					removedEdges++;
					//(*nPolysHit)--;
					edge[0]->type=128;
#ifdef SHITLOADSOFDEBUG
					printf ("left match removed\n");
#endif
				}
			}
			if ( (((edge[0]->plane&D_YZPLANE) && (edge[1]->plane&D_YZPLANE))	||	// right
				 ((edge[0]->plane&U_YZPLANE) && (edge[1]->plane&U_YZPLANE)))	&&	// left
				 (((edge[0]->plane&U_XYPLANE) && (edge[1]->plane&D_XYPLANE))	||	// 0=near 1=far
				 ((edge[0]->plane&D_XYPLANE) && (edge[1]->plane&U_XYPLANE))) )		// 0=far  1=near
			{
				if (edge[0]->plane&U_XYPLANE) // if on far side
				{
					if ( pD->pPos->vz > edge[0]->pos.vz )
					{	// 1 redundant
						removedEdges++;
						//(*nPolysHit)--;
						edge[1]->type=128;
#ifdef SHITLOADSOFDEBUG
						printf ("far match removed\n");
#endif
					}
					else
					{	// 0 redundant
						removedEdges++;
						//(*nPolysHit)--;
						edge[0]->type=128;
#ifdef SHITLOADSOFDEBUG
						printf ("near match removed\n");
#endif
					}
				}
				else if ( pD->pPos->vz < edge[0]->pos.vz )
				{	// 1 redundant
					removedEdges++;
					//(*nPolysHit)--;
					edge[1]->type=128;
#ifdef SHITLOADSOFDEBUG
					printf ("near match removed\n");
#endif
				}
				else
				{	// 0 redundant
					removedEdges++;
					//(*nPolysHit)--;
					edge[0]->type=128;
#ifdef SHITLOADSOFDEBUG
					printf ("far match removed\n");
#endif
				}
			}
		}
	}
	if(removedEdges)
	{
		static int c = 0;
		DB("Removed edges %d\n",c++);
	}
	return(removedEdges);
}


/*	--------------------------------------------------------------------------------
	Function 	: UpdateCornerCollision
	Purpose 	: 
	Parameters 	: 
	Returns 	: 0 if no hit !0 if hit
	Info 		: No bugs found yet (YOU MUST BE JOKING!!!)
*/
//-------------------------------------------------------------------------------//

void	UpdateCornerCollision(COLLDATA *pD , HITDATA *pHitData , VECTOR *collPos , VECTOR *rebound)
{

	VECTOR	objectmove,normal;	// changed from FVECTOR
	long	deltaX,deltaY,deltaZ;
//	long	mag;

	//printf  ("hit corner\n");
	if ( pHitData->plane & D_XZPLANE ) // Top
	{
		if ( pHitData->plane & U_YZPLANE ) // Left
		{
			if ( pHitData->plane & U_XYPLANE ) // Near
			{
				//printf ("top left near\n");
				deltaX=( (pD->pPos->vx) - (pHitData->pos.vx) );
				deltaY=( (pD->pPos->vy) - (pHitData->pos.vy) );
				deltaZ=( (pD->pPos->vz) - (pHitData->pos.vz) );
				// will need to put checks in
				if (deltaX>0) deltaX=0;
				if (deltaY>0) deltaY=0;
				if (deltaZ>0) deltaZ=0;

				objectmove.vx=deltaX;
				objectmove.vy=deltaY;
				objectmove.vz=deltaZ;
				MakeUnit(&objectmove);

				normal.vx=-deltaX;
				normal.vy=deltaY;
				normal.vz=-deltaZ;
				MakeUnit(&normal);

				SCALEVECTOR(&objectmove,(pD->radius+1) );
				
				if (pD->nCornerHits<2)
				{
					if ( (pD->pPos->vx > pHitData->pos.vx+objectmove.vx) && (deltaX) )
						pD->pPos->vx=pD->oldPos.vx=pHitData->pos.vx+objectmove.vx;

					if ( (pD->pPos->vz > pHitData->pos.vz+objectmove.vz) && (deltaZ) )
						pD->pPos->vz=pD->oldPos.vz=pHitData->pos.vz+objectmove.vz;
				}

				if ( (pD->pPos->vy > pHitData->pos.vy+objectmove.vy) && (deltaY) )
					pD->pPos->vy=pD->oldPos.vy=pHitData->pos.vy+objectmove.vy;
			}
			else if ( pHitData->plane & D_XYPLANE ) // Far
			{
				//printf ("top left far\n");
				deltaX=( (pD->pPos->vx) - (pHitData->pos.vx) );
				deltaY=( (pD->pPos->vy) - (pHitData->pos.vy) );
				deltaZ=( (pD->pPos->vz) - (pHitData->pos.vz) );
				// will need to put checks in
				if (deltaX>0) deltaX=0;
				if (deltaY>0) deltaY=0;
				if (deltaZ<0) deltaZ=0;

				objectmove.vx=deltaX;
				objectmove.vy=deltaY;
				objectmove.vz=deltaZ;
				MakeUnit(&objectmove);

				normal.vx=-deltaX;
				normal.vy=deltaY;
				normal.vz=-deltaZ;
				MakeUnit(&normal);

				SCALEVECTOR(&objectmove,(pD->radius+1) );
				
				if (pD->nCornerHits<2)
				{
					if ( (pD->pPos->vx > pHitData->pos.vx+objectmove.vx) && (deltaX) )
						pD->pPos->vx=pD->oldPos.vx=pHitData->pos.vx+objectmove.vx;

					if ( (pD->pPos->vz < pHitData->pos.vz+objectmove.vz) && (deltaZ) )
						pD->pPos->vz=pD->oldPos.vz=pHitData->pos.vz+objectmove.vz;
				}

				if ( (pD->pPos->vy > pHitData->pos.vy+objectmove.vy) && (deltaY) )
					pD->pPos->vy=pD->oldPos.vy=pHitData->pos.vy+objectmove.vy;
			}
			else printf ("ERROR on corner 1\n");
		}
		if ( pHitData->plane & D_YZPLANE ) // Right
		{
			if ( pHitData->plane & U_XYPLANE ) // Near
			{
				//printf ("top right near\n");
				deltaX=( (pD->pPos->vx) - (pHitData->pos.vx) );
				deltaY=( (pD->pPos->vy) - (pHitData->pos.vy) );
				deltaZ=( (pD->pPos->vz) - (pHitData->pos.vz) );
				// will need to put checks in
				if (deltaX<0) deltaX=0;
				if (deltaY>0) deltaY=0;
				if (deltaZ>0) deltaZ=0;

				objectmove.vx=deltaX;
				objectmove.vy=deltaY;
				objectmove.vz=deltaZ;
				MakeUnit(&objectmove);

				normal.vx=-deltaX;
				normal.vy=deltaY;
				normal.vz=-deltaZ;
				MakeUnit(&normal);

				SCALEVECTOR(&objectmove,(pD->radius+1) );
				
				if (pD->nCornerHits<2)
				{
					if ( (pD->pPos->vx < pHitData->pos.vx+objectmove.vx) && (deltaX) )
						pD->pPos->vx=pD->oldPos.vx=pHitData->pos.vx+objectmove.vx;

					if ( (pD->pPos->vz > pHitData->pos.vz+objectmove.vz) && (deltaZ) )
						pD->pPos->vz=pD->oldPos.vz=pHitData->pos.vz+objectmove.vz;
				}

				if ( (pD->pPos->vy > pHitData->pos.vy+objectmove.vy) && (deltaY) )
					pD->pPos->vy=pD->oldPos.vy=pHitData->pos.vy+objectmove.vy;
			}
			else if ( pHitData->plane & D_XYPLANE ) // Far
			{
				//printf ("top right far\n");
				deltaX=( (pD->pPos->vx) - (pHitData->pos.vx) );
				deltaY=( (pD->pPos->vy) - (pHitData->pos.vy) );
				deltaZ=( (pD->pPos->vz) - (pHitData->pos.vz) );
				// will need to put checks in
				if (deltaX<0) deltaX=0;
				if (deltaY>0) deltaY=0;
				if (deltaZ<0) deltaZ=0;

				objectmove.vx=deltaX;
				objectmove.vy=deltaY;
				objectmove.vz=deltaZ;
				MakeUnit(&objectmove);

				normal.vx=-deltaX;
				normal.vy=deltaY;
				normal.vz=-deltaZ;
				MakeUnit(&normal);

				SCALEVECTOR(&objectmove,(pD->radius+1) );
				
				if (pD->nCornerHits<2)
				{
					if ( (pD->pPos->vx < pHitData->pos.vx+objectmove.vx) && (deltaX) )
						pD->pPos->vx=pD->oldPos.vx=pHitData->pos.vx+objectmove.vx;

					if ( (pD->pPos->vz < pHitData->pos.vz+objectmove.vz) && (deltaZ) )
						pD->pPos->vz=pD->oldPos.vz=pHitData->pos.vz+objectmove.vz;
				}

				if ( (pD->pPos->vy > pHitData->pos.vy+objectmove.vy) && (deltaY) )
					pD->pPos->vy=pD->oldPos.vy=pHitData->pos.vy+objectmove.vy;
			}
			else printf ("ERROR on corner 2\n");
		}
	}

	else if ( pHitData->plane & U_XZPLANE ) // Bottom
	{
		if ( pHitData->plane & U_YZPLANE ) // Left
		{
			if ( pHitData->plane & U_XYPLANE ) // Near
			{
				//printf ("bottom left near\n");
				deltaX=( (pHitData->pos.vx) - (pD->pPos->vx) );
				deltaY=( (pD->pPos->vy) - (pHitData->pos.vy) );
				deltaZ=( (pHitData->pos.vz) - (pD->pPos->vz) );
				// will need to put checks in
				if (deltaX<0) deltaX=0;
				if (deltaY<0) deltaY=0;
				if (deltaZ<0) deltaZ=0;

				objectmove.vx=deltaX;
				objectmove.vy=deltaY;
				objectmove.vz=deltaZ;
				MakeUnit(&objectmove);
				SCALEVECTOR(&objectmove,(pD->radius+1) );

				if (pD->nCornerHits<2)
				{
					if ( (pD->pPos->vx > pHitData->pos.vx-objectmove.vx) && (deltaX) )
						pD->pPos->vx=pD->oldPos.vx=pHitData->pos.vx-objectmove.vx;

					if ( (pD->pPos->vz > pHitData->pos.vz-objectmove.vz) && (deltaZ) )
						pD->pPos->vz=pD->oldPos.vz=pHitData->pos.vz-objectmove.vz;
				}

				if ( (pD->pPos->vy < pHitData->pos.vy+objectmove.vy) && (deltaY) )
					pD->pPos->vy=pD->oldPos.vy=pHitData->pos.vy+objectmove.vy;

				deltaX=( (pHitData->pos.vx) - (collPos->vx) );
				deltaY=( (collPos->vy) - (pHitData->pos.vy) );
				deltaZ=( (pHitData->pos.vz) - (collPos->vz) );
				if (deltaX<0) deltaX=0;
				if (deltaY<0) deltaY=0;
				if (deltaZ<0) deltaZ=0;

				normal.vx=deltaX;
				normal.vy=deltaY;
				normal.vz=deltaZ;
				MakeUnit(&normal);
			}
			else if ( pHitData->plane & D_XYPLANE ) // Far
			{
				//printf ("bottom left far\n");
				deltaX=( (pHitData->pos.vx) - (pD->pPos->vx) );
				deltaY=( (pD->pPos->vy) - (pHitData->pos.vy) );
				deltaZ=( (pD->pPos->vz) - (pHitData->pos.vz) );
				// will need to put checks in
				if (deltaX<0) deltaX=0;
				if (deltaY<0) deltaY=0;
				if (deltaZ<0) deltaZ=0;

				objectmove.vx=deltaX;
				objectmove.vy=deltaY;
				objectmove.vz=deltaZ;
				MakeUnit(&objectmove);
				SCALEVECTOR(&objectmove,(pD->radius+1) );

				if (pD->nCornerHits<2)
				{
					if ( (pD->pPos->vx > pHitData->pos.vx-objectmove.vx) && (deltaX) )
						pD->pPos->vx=pD->oldPos.vx=pHitData->pos.vx-objectmove.vx;

					if ( (pD->pPos->vz < pHitData->pos.vz+objectmove.vz) && (deltaZ) )
						pD->pPos->vz=pD->oldPos.vz=pHitData->pos.vz+objectmove.vz;
				}

				if ( (pD->pPos->vy < pHitData->pos.vy+objectmove.vy) && (deltaY) )
					pD->pPos->vy=pD->oldPos.vy=pHitData->pos.vy+objectmove.vy;

				deltaX=( (pHitData->pos.vx) - (collPos->vx) );
				deltaY=( (collPos->vy) - (pHitData->pos.vy) );
				deltaZ=( (collPos->vz) - (pHitData->pos.vz) );
				if (deltaX<0) deltaX=0;
				if (deltaY<0) deltaY=0;
				if (deltaZ<0) deltaZ=0;

				normal.vx=deltaX;
				normal.vy=deltaY;
				normal.vz=-deltaZ;
				MakeUnit(&normal);
			}
			else printf ("ERROR on corner 3\n");
		}
		else if ( pHitData->plane & D_YZPLANE ) // Right
		{
			if ( pHitData->plane & U_XYPLANE ) // Near
			{
				//printf ("bottom right near\n");
				deltaX=( (pD->pPos->vx) - (pHitData->pos.vx) );
				deltaY=( (pD->pPos->vy) - (pHitData->pos.vy) );
				deltaZ=( (pHitData->pos.vz) - (pD->pPos->vz) );
				// will need to put checks in
				if (deltaX<0) deltaX=0;
				if (deltaY<0) deltaY=0;
				if (deltaZ<0) deltaZ=0;

				objectmove.vx=deltaX;
				objectmove.vy=deltaY;
				objectmove.vz=deltaZ;
				MakeUnit(&objectmove);
				SCALEVECTOR(&objectmove,(pD->radius+1) );

				if (pD->nCornerHits<2)
				{
					if ( (pD->pPos->vx < pHitData->pos.vx+objectmove.vx) && (deltaX) )
						pD->pPos->vx=pD->oldPos.vx=pHitData->pos.vx+objectmove.vx;

					if ( (pD->pPos->vz > pHitData->pos.vz-objectmove.vz) && (deltaZ) )
						pD->pPos->vz=pD->oldPos.vz=pHitData->pos.vz-objectmove.vz;
				}

				if ( (pD->pPos->vy < pHitData->pos.vy+objectmove.vy) && (deltaY) )
					pD->pPos->vy=pD->oldPos.vy=pHitData->pos.vy+objectmove.vy;

				deltaX=( (collPos->vx) - (pHitData->pos.vx) );
				//deltaY=( (pHitData->pos.vy) - (collPos->vy) );
				deltaY=( (collPos->vy) - (pHitData->pos.vy) );
				deltaZ=( (pHitData->pos.vz) - (collPos->vz) );
				if (deltaX<0) deltaX=0;
				if (deltaY<0) deltaY=0;
				if (deltaZ<0) deltaZ=0;

				normal.vx=-deltaX;
				normal.vy=deltaY;
				normal.vz=deltaZ;
				MakeUnit(&normal);
			}
			else if ( pHitData->plane & D_XYPLANE ) // Far
			{
				//printf ("bottom right far\n");
				deltaX=( (pD->pPos->vx) - (pHitData->pos.vx) );
				deltaY=( (pD->pPos->vy) - (pHitData->pos.vy) );
				deltaZ=( (pD->pPos->vz) - (pHitData->pos.vz) );
				// will need to put checks in
				if (deltaX<0) deltaX=0;
				if (deltaY<0) deltaY=0;
				if (deltaZ<0) deltaZ=0;

				objectmove.vx=deltaX;
				objectmove.vy=deltaY;
				objectmove.vz=deltaZ;
				MakeUnit(&objectmove);
				SCALEVECTOR(&objectmove,(pD->radius+1) );

				if (pD->nCornerHits<2)
				{
					if ( (pD->pPos->vx < pHitData->pos.vx+objectmove.vx) && (deltaX) )
						pD->pPos->vx=pD->oldPos.vx=pHitData->pos.vx+objectmove.vx;

					if ( (pD->pPos->vz < pHitData->pos.vz+objectmove.vz) && (deltaZ) )
						pD->pPos->vz=pD->oldPos.vz=pHitData->pos.vz+objectmove.vz;
				}
				if ( (pD->pPos->vy < pHitData->pos.vy+objectmove.vy) && (deltaY) )
					pD->pPos->vy=pD->oldPos.vy=pHitData->pos.vy+objectmove.vy;

				deltaX=( (collPos->vx) - (pHitData->pos.vx) );
				deltaY=( (collPos->vy) - (pHitData->pos.vy) );
				deltaZ=( (collPos->vz) - (pHitData->pos.vz) );
				if (deltaX<0) deltaX=0;
				if (deltaY<0) deltaY=0;
				if (deltaZ<0) deltaZ=0;

				normal.vx=-deltaX;
				normal.vy=deltaY;
				normal.vz=-deltaZ;
				MakeUnit(&normal);
			}
			else printf ("ERROR on corner 4\n");
		}
		else printf ("ERROR on corner 5\n");
	}

	pHitData->normal.vx=normal.vx;
	pHitData->normal.vy=normal.vy;
	pHitData->normal.vz=normal.vz;

	//mag=Magnitude(pD->pVel);
	//COPYVECTOR(rebound, pD->pVel);
	//CalcBounce(rebound, &normal);
	//SCALEVECTOR(rebound,mag);
	//printf ("corner normal X %d Y %d Z %d\n",normal.vx,normal.vy,normal.vz);

}

/*	--------------------------------------------------------------------------------
	Function 	: UpdatePlaneCollision
	Purpose 	: 
	Parameters 	: 
	Returns 	: 0 if no hit !0 if hit
	Info 		: No bugs found yet
*/
//-------------------------------------------------------------------------------//

void	UpdatePlaneCollision(COLLDATA *pD , HITDATA *pHitData , VECTOR *collPos , VECTOR *rebound)
{
	long div, magv0v1, magv0v2;//temp,temp1;
	VECTOR v0v2, v0v1, velDiff;	// changed from FVECTOR

	COPYVECTOR(rebound , pD->pVel);

	SUBVECTOR(&v0v1, pD->pPos, &pD->oldPos);
	magv0v1=Magnitude(&v0v1);

 	if(magv0v1)
 	{
 		SUBVECTOR(&v0v2, &pHitData->pos, &pD->oldPos);
 		magv0v2=Magnitude(&v0v2);
 		div=(magv0v2*4096)/magv0v1;
 		SUBVECTOR(&velDiff, pD->pVel, &pD->oldVel);
 		SCALEVECTOR(&velDiff, div);
 		COPYVECTOR(&pHitData->vel, &pD->oldVel);
 	}
 	else
 		COPYVECTOR(&pHitData->vel, pD->pVel);

 	switch(pHitData->plane)
 	{
 		case D_XZPLANE:
 		case U_XZPLANE:

			//if (pD==&gloveColl) gloveVel.vy=0;

 			if (pD->pPos->vy>pHitData->pos.vy && (pHitData->plane&D_XZPLANE) )
				pD->pPos->vy=pHitData->pos.vy;
 			
 			if (pD->pPos->vy<pHitData->pos.vy && (pHitData->plane&U_XZPLANE) )
				pD->pPos->vy=pHitData->pos.vy;

			//if ( (pHitData->plane==D_XZPLANE) && (rebound->vy>0) ) break;
			//else if ( (pHitData->plane==U_XZPLANE) && (rebound->vy<0) ) break;

			//if (pD==&gloveColl)
			//{
				if (pHitData->plane==U_XZPLANE)
				{
					if (pD==&gloveColl) gloveVel.vy=0;
					pD->pPos->vy=pHitData->pos.vy+(2*4096);
					if (!GloveCtrl.speed && pD==&gloveColl ) GloveCtrl.speed=1;
					if (pD==&ballColl) BallCtrl.noBounce=TRUE;
				}
			//}

			if ( (pHitData->plane==D_XZPLANE) && (pD->pVel->vy>0) ) break;
			else if ( (pHitData->plane==U_XZPLANE) && (pD->pVel->vy<0) ) break;

			//rebound->vy=-rebound->vy;
			//pD->pVel->vy=-pD->pVel->vy;
			/*if ( (pHitData->plane==D_XZPLANE) ) 
			{
				pD->bounce.vy-=4096;	// could be wrong
				printf ("plane normal X 0 Y -4096 Z 0\n");
			}
			else if ( (pHitData->plane==U_XZPLANE)  )
			{
				pD->bounce.vy+=4096;	// could be wrong
				printf ("plane normal X 0 Y 4096 Z 0\n");
			}
			*/
 			//pd->bounce.vy+=4096;	// could be wrong

 			break;
 		case D_YZPLANE:
 		case U_YZPLANE:


 			if (pD->pPos->vx<pHitData->pos.vx && (pHitData->plane&D_YZPLANE) )
 				pD->pPos->vx=pHitData->pos.vx;
 			
 			if (pD->pPos->vx>pHitData->pos.vx && (pHitData->plane&U_YZPLANE) )
 				pD->pPos->vx=pHitData->pos.vx;


			//if ( (pHitData->plane==D_YZPLANE) && (rebound->vx>0) ) break;
			//else if ( (pHitData->plane==U_YZPLANE) && (rebound->vx<0) ) break;

			if ( (pHitData->plane==D_YZPLANE) && (pD->pVel->vx>0) ) break;
			else if ( (pHitData->plane==U_YZPLANE) && (pD->pVel->vx<0) ) break;

			/*
			if ( (pHitData->plane==D_YZPLANE) )
			{
				pD->bounce.vx-=4096;	// could be wrong
				printf ("plane normal X -4096 Y 0 Z 0\n");
			}
			else if ( (pHitData->plane==U_YZPLANE) )
			{
				pD->bounce.vx+=4096;	// could be wrong
				printf ("plane normal X 4096 Y 0 Z 0\n");
			}
			*/
			
			//rebound->vx=-rebound->vx;
			//pD->pVel->vx=-pD->pVel->vx;
 			//if(pHitData->plane==U_YZPLANE)
 			//	pD->pPos->vx--;	
 			break;
 		case D_XYPLANE:
 		case U_XYPLANE:


 			if (pD->pPos->vz<pHitData->pos.vz && (pHitData->plane&D_XYPLANE) )
 				pD->pPos->vz=pHitData->pos.vz;
 			
 			if (pD->pPos->vz>pHitData->pos.vz && (pHitData->plane&U_XYPLANE) )
	 			pD->pPos->vz=pHitData->pos.vz;

			//if ( (pHitData->plane==D_XYPLANE) && (rebound->vz>0) ) break;
			//else if ( (pHitData->plane==U_XYPLANE) && (rebound->vz<0) ) break;

			if ( (pHitData->plane==D_XYPLANE) && (pD->pVel->vz>0) ) break;
			else if ( (pHitData->plane==U_XYPLANE) && (pD->pVel->vz<0) ) break;

			/*
			if ( (pHitData->plane==D_XYPLANE) )
			{
				pD->bounce.vz-=4096;	// could be wrong
				printf ("plane normal X 0 Y 0 Z -4096\n");
			}
			else if ( (pHitData->plane==U_XYPLANE) )
			{
				pD->bounce.vz+=4096;	// could be wrong
				printf ("plane normal X 0 Y 0 Z +4096\n");
			}
			*/

			rebound->vz=-rebound->vz;
			//pD->pVel->vz=-pD->pVel->vz;
 			//if(pHitData->plane==U_XYPLANE)
 			//	pD->pPos->vz--;	
 			break;
 		default:
 			DB("ERROR: Bad plane! Hit at (%ld,%ld,%ld)\n",
 					pHitData->pos.vx, pHitData->pos.vy, pHitData->pos.vz);
 	}
}

/*	--------------------------------------------------------------------------------
	Function 	: UpdateCylinderCollision
	Purpose 	:
	Parameters 	:
	Returns 	:
	Info 		: 
*/
//-------------------------------------------------------------------------------//


void	UpdateCylinderCollision(COLLDATA *pD , HITDATA *pHitData , VECTOR *collPos , VECTOR *rebound)
{
	long	deltaX,deltaY,deltaZ,mag;
	VECTOR	objectmove;
	VECTOR	normal;	// changed from FVECTOR
	COLLBOX *pB=pHitData->pCollBox;


// Normal / Objectmove calcs moved to be typepart-specific by Fred
// (Coz I'm calculating the normal for Y-Cylinders at CheckCylinder time, and I didn't want to touch the X/Z cylinder code)

	switch( pB->flags&TYPEPART )			// X aligned cylinder
	{
		case CYLINDER_X:			// X aligned cylinder
			deltaX=( (pHitData->pos.vx) - (collPos->vx) );
			deltaY=( (pHitData->pos.vy) - (collPos->vy) );
			deltaZ=( (pHitData->pos.vz) - (collPos->vz) );

			normal.vx=deltaX;
			normal.vy=deltaY;
			normal.vz=deltaZ;

			MakeUnit(&normal);

			pHitData->normal.vx=normal.vx;
			pHitData->normal.vy=normal.vy;
			pHitData->normal.vz=normal.vz;

			objectmove.vx=normal.vx;
			objectmove.vy=normal.vy;
			objectmove.vz=normal.vz;
// (end of code that used to be outside the switch)			

			mag=(pB->sZ/2)+pD->radius;	// get radius of cylinder + object
			SCALEVECTOR(&objectmove,mag);

			pD->pPos->vy=( pB->pY + (pB->sY/2) )-objectmove.vy;
			pD->pPos->vz=( pB->pZ + (pB->sZ/2) )-objectmove.vz;

			//printf ("move Y %d Z %d pos Y %d Z %d radius %d\n",objectmove.vy,objectmove.vz,pD->pPos->vy,pD->pPos->vz,pD->radius);

			if (objectmove.vx!=0)
			{
				if (objectmove.vx>0)
					pD->pPos->vx=-objectmove.vx+( pB->pX );
				else
					pD->pPos->vx=-objectmove.vx+( pB->pX+pB->sX );
			}

// (3 more lines that used to be outside the switch)
			pHitData->normal.vx=-normal.vx;
			pHitData->normal.vy=normal.vy;
			pHitData->normal.vz=-normal.vz;
			break;
	
		case CYLINDER_Y:	// Y aligned cylinder

			objectmove.vx = -pHitData->normal.vx;	// Transfer from normal calculated at "CheckCylinders" time
			objectmove.vy =  pHitData->normal.vy;
			objectmove.vz = -pHitData->normal.vz;

//			DB("Cylinder hitdata normal = %d %d %d\n",pHitData->normal.vx,pHitData->normal.vy,pHitData->normal.vz);
//			DB("objmove = %d %d %d\n",objectmove.vx,objectmove.vy,objectmove.vz);

			mag=(pB->sZ/2)+pD->radius;	// get radius of cylinder + object
			SCALEVECTOR(&objectmove,mag);

			pD->pPos->vx=-objectmove.vx+( pB->pX + (pB->sX/2) );
			pD->pPos->vz=-objectmove.vz+( pB->pZ + (pB->sZ/2) );
			if (objectmove.vy!=0)
			{
				if (objectmove.vy<0)
				{
					pD->pPos->vy=-objectmove.vy+( pB->pY );
//					DB("Cylinder hit vy bot, glovepos = %d, colpos = %d\n",(pHitData->pos.vy)>>12, (collPos->vy) >>12 );

				}
				else
				{
					pD->pPos->vy=-objectmove.vy+( pB->pY+pB->sY );
//					DB("Cylinder hit vy top, glovepos = %d, colpos = %d\n",(pHitData->pos.vy)>>12, (collPos->vy) >>12 );
				}
			}
			else
			{
//				DB("Cylinder centre doesn't update object's vy position\n");
			}
//			DB("Cyl Normal calc at *end* of updating time = %d %d %d. objmove = %d %d %d\n",
//				pHitData->normal.vx,pHitData->normal.vy,pHitData->normal.vz,
//				objectmove.vx,objectmove.vy,objectmove.vz);

			break;

		case CYLINDER_Z:	// Z aligned cylinder
			deltaX=( (pHitData->pos.vx) - (collPos->vx) );
			deltaY=( (pHitData->pos.vy) - (collPos->vy) );
			deltaZ=( (pHitData->pos.vz) - (collPos->vz) );

			normal.vx=deltaX;
			normal.vy=deltaY;
			normal.vz=deltaZ;

			MakeUnit(&normal);

			pHitData->normal.vx=normal.vx;
			pHitData->normal.vy=normal.vy;
			pHitData->normal.vz=normal.vz;

			objectmove.vx=normal.vx;
			objectmove.vy=normal.vy;
			objectmove.vz=normal.vz;


			mag=(pB->sX/2)+pD->radius;	// get radius of cylinder + object
			SCALEVECTOR(&objectmove,mag);

			pD->pPos->vx=-objectmove.vx+( pB->pX + (pB->sX/2) );
			pD->pPos->vy=-objectmove.vy+( pB->pY + (pB->sY/2) );


			if (objectmove.vz!=0)
			{
				if (objectmove.vz>0)
					pD->pPos->vz=-objectmove.vz+( pB->pZ );
				else
					pD->pPos->vz=-objectmove.vz+( pB->pZ+pB->sZ );
			}
			pHitData->normal.vx=-normal.vx;
			pHitData->normal.vy=normal.vy;
			pHitData->normal.vz=-normal.vz;
			break;
	}
}


/*	--------------------------------------------------------------------------------
	Function 	: UpdateCylinderCollision
	Purpose 	:
	Parameters 	:
	Returns 	:
	Info 		: 
*/
//-------------------------------------------------------------------------------//


void	UpdateSphereCollision(COLLDATA *pD , HITDATA *pHitData , VECTOR *collPos , VECTOR *rebound)
{
	long	deltaX,deltaY,deltaZ; //,mag;
	VECTOR	objectmove,normal,center;	// changed from FVECTOR
	COLLBOX *pB=pHitData->pCollBox;

	center.vx=(pB->pX-(pB->sX/2) );
	center.vy=(pB->pY+(pB->sY/2) );
	center.vz=(pB->pZ-(pB->sZ/2) );

	deltaX=pHitData->pos.vx-center.vx;
	deltaY=pHitData->pos.vy-center.vy;
	deltaZ=pHitData->pos.vz-center.vz;

	normal.vx=deltaX;
	normal.vy=deltaY;
	normal.vz=deltaZ;
	MakeUnit(&normal);

	objectmove.vx=normal.vx;
	objectmove.vy=normal.vy;
	objectmove.vz=normal.vz;

	SCALEVECTOR(&objectmove,pD->radius );

	objectmove.vx+=pHitData->pos.vx;
	objectmove.vy+=pHitData->pos.vy;
	objectmove.vz+=pHitData->pos.vz;

	pD->pPos->vx=pD->oldPos.vx=objectmove.vx;
	pD->pPos->vy=pD->oldPos.vy=objectmove.vy;
	pD->pPos->vz=pD->oldPos.vz=objectmove.vz;

	normal.vx=-normal.vx;
	normal.vz=-normal.vz;

	pHitData->normal.vx=normal.vx;
	pHitData->normal.vy=normal.vy;
	pHitData->normal.vz=normal.vz;
}

/**************************************************************************************/
void	doBounceOnVelBall(VECTOR *rebound,VECTOR *start,BEHAVIOUR_PHYSICS	*Physics)
{
VECTOR	tempVec1;
	SUBVECTOR(&tempVec1,start,rebound);


	tempVec1.vx=((tempVec1.vx* (4096-Physics->bounce) )/4096)/2;
	if (!BallCtrl.onTrampoline) tempVec1.vy=((tempVec1.vy* (4096-Physics->bounce) )/4096)/2;
	else tempVec1.vy=0;
	tempVec1.vz=((tempVec1.vz* (4096-Physics->bounce) )/4096)/2;
	ADDVECTOR(rebound,rebound,&tempVec1);
}

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

void	doBounceOnVel(VECTOR *rebound,VECTOR *start,BEHAVIOUR_PHYSICS	*Physics)
{
VECTOR	tempVec1;
	SUBVECTOR(&tempVec1,start,rebound);
	tempVec1.vx=((tempVec1.vx* (4096-Physics->bounce) )/4096)/2;
	tempVec1.vy=((tempVec1.vy* (4096-Physics->bounce) )/4096)/2;
	tempVec1.vz=((tempVec1.vz* (4096-Physics->bounce) )/4096)/2;
	ADDVECTOR(rebound,rebound,&tempVec1);
}
////////////////////////////////////////////////////////////////
LONG	doConveyerStuff(LONG	flags)
{

	switch (flags)
	{
		case P_CONVEYERXP:
			return(XPOS);
			//GloveCtrl.onConveyer=XPOS;
			//GloveCtrl.conveyerTimer=6;
			break;
		case P_CONVEYERXN:
			return(XNEG);
			//GloveCtrl.onConveyer=XNEG;
			//GloveCtrl.conveyerTimer=6;
			break;
		case P_CONVEYERZP:
			return(ZPOS);
			//GloveCtrl.onConveyer=ZPOS;
			//GloveCtrl.conveyerTimer=6;
			break;
		case P_CONVEYERZN:
			return(ZNEG);
			//GloveCtrl.onConveyer=ZNEG;
			//GloveCtrl.conveyerTimer=6;
			break;
	}
	return(FALSE);


}