// C Source File
// Created 9/4/2004; 2:41:45 PM

#include "MainHeader.h"


//VARIABLES



//FUNCTIONS
void coll_DoCollision();
void coll_MarioCollision();
void coll_DoBump(short PosX, short PosY);
short coll_NoBump(short Tile);
short coll_NoRebound(short Tile);
void coll_BrickSmash(short PosX, short PosY);
void coll_ParticleCollision();
void coll_EnemyCollision();
char TestGround(short Type);
void coll_SpawnShroom(short PosX, short PosY);
void coll_SpawnFlower(short PosX, short PosY);
void coll_SpawnCoin(short PosX, short PosY);
void coll_SpawnStar(short PosX, short PosY);
void MarioTransform(short Type);
short coll_TestCollide(short X1, short Y1, short X2, short Y2, short W, short H);
short coll_CanCollide(short Type1, short Type2);
void coll_KnockEnemy(short E);
void coll_FireEnemy(short E, short Dir);
void coll_StompEnemy(short E, short Dir);
void coll_KillEnemy(short E, short Dir);
void coll_GrabVine(short PosX);
short coll_CanStomp(short Type);
void coll_MarioEnemyBump(short Type, short E);
void coll_GrabFlagPole(short PosX);

//MAIN SUB FOR COLLISION DETECTION
void coll_DoCollision()
{
	//check to see if mario has collided with the ground (or an object)
	coll_MarioCollision();
	
	//check to see if a particle has hit something important
	coll_ParticleCollision();
	
	//check enemies for collision
	coll_EnemyCollision();
}



//THIS SUB CHECKS TO SEE IF MARIO HAS COLLIDED WITH SOMETHING
void coll_MarioCollision()
{
	int PosX, PosY; //the tile mario is on
	
	char Hit=false;
	short MYCmp=Mario.YCmp, MapTile, MY=Mario.y, MVine=Mario.OnVine;
		
	//if mario is greater than 1000, restart level
	if(MY>400)
	{
		//subtract a life \ power ups
		KillMario();
		
		//restart the current level
		DoSplash();
	}

	//if mario is dead, no colision
	if(Mario.State==m_Dead)
	{
		//no colision if time is up..
		if(Time<=0)
		{
			//no colision / vinage when time is up
			Mario.OnVine=false;
		}
	
		//if mario's y is off screen, restart level
		if(MY-20>240)
		{
			//restart the current level
			DoSplash();
		}
		//exit, no colision
		return;
	}
	

	
	//if mario has fallen off the map, exit
	if(MY>=235)
		return;
	
	//make sure mario hasnt gone off screen to the left
	if(Mario.x<0)
		Mario.x=0;
			
	
	//TESTS THE TOP OF MARIO, IF HE PUNCHED ANYTHING...
	if(MYCmp<0) //only if he's moving up...
	{
		//if mario is movibe up, then he must be airborn..
		Mario.Airborn=true;
		
		//uses integer division to find the tiles
		PosX=(int)((Mario.x+23)/16)-1;
		if(Mario.State==0)
			PosY=(int)((MY+0)/16);
		else
			PosY=(int)((MY-12)/16);
		
		//crash protect
		if(PosX<0) PosX=0;
		if(PosX>200*16) PosX=200*16;
		if(PosY<0) PosY=0;
		if(PosY>16) PosY=16;
		
		//the current map tile its over
		MapTile=Map[PosY][PosX];
		
		//checks to see if its a hit
		if(TestGround(MapTile)==true)
		{
			if(Mario.State==0)
				Mario.y=(PosY*16)+16;
			if(Mario.State==1 || Mario.State==2)
				Mario.y=(PosY*16)+32;

			Mario.YCmp=0;

			//if the tile doesnt support rebound, dont reflect mario, otherwise do
			if(!coll_NoRebound(MapTile) && !coll_NoBump(MapTile))
				coll_DoBump(PosX,PosY);
		}//end if hit roof
	}

	Mario.OnVine=false;
	MYCmp=Mario.YCmp;
	MY=Mario.y;
	//TESTS TO SEE IF MARIO HIT HIS LEFT SIDE
	if(MYCmp<0)
		PosY=(int)((MY+16)/16);
	else
		PosY=(int)((MY+0)/16);
		
	//TESTS BOTTON LEFT
	//uses integer division to find the tiles
	PosX=(int)((Mario.x+16)/16)-1;
	
	//crash protect
	if(PosX<0) PosX=0;
	if(PosX>200*16) PosX=200*16;
	if(PosY<0) PosY=0;
	if(PosY>16) PosY=16;
	
	//if mario hit a vine, set vine mode on, else test for rest of LEFT collision
	if(Map[PosY][PosX]==67 || Map[PosY][PosX]==68)
		coll_GrabVine(PosX);
	
	//if mario grabbed the flag pole
	if(Map[PosY][PosX]==14 || Map[PosY][PosX]==45)
		coll_GrabFlagPole(PosX);
		
	if(!Mario.OnVine)
	{
			//checks to see if its a hit
			if(TestGround(Map[PosY][PosX])==true)
					{Mario.x=(PosX*16)+16; Mario.Momentum=0;}
			
			//TESTS MIDDLE LEFT		
			PosY=(int)((Mario.y+6)/16);
		
			//crash protect
			if(PosY<0) PosY=0;
			if(PosY>16) PosY=16;
			
			//checks to see if its a hit
			if(TestGround(Map[PosY][PosX])==true)
					{Mario.x=(PosX*16)+16; Mario.Momentum=0;}
					
			
			//TESTS UPPER LEFT		
			PosY=(int)((Mario.y+0)/16);
		
			//crash protect
			if(PosY<0) PosY=0;
			if(PosY>16) PosY=16;
		
			//if mario hit a door, let stage 3 being
			if(LevelComplete)
			{
				if(Map[PosY][PosX]==9 || Map[PosY][PosX]==10)
				{
					//3rd stage of completeness
					LevelComplete=3;
					
				}
			}
				
			//checks to see if its a hit
			if(TestGround(Map[PosY][PosX])==true)
					{Mario.x=(PosX*16)+16; Mario.Momentum=0;}
					
			//Tests uper a second time if he's big..)
			if((Mario.State==1 || Mario.State==2) && !_keytest(RR_DOWN))
			{
					PosY=(int)((Mario.y-12)/16);
				
					//crash protect
					if(PosY<0) PosY=0;
					if(PosY>16) PosY=16;
					
					//checks to see if its a hit
					if(TestGround(Map[PosY][PosX])==true)
						{Mario.x=(PosX*16)+16; Mario.Momentum=0;}
			}	
	}//end if ! hit vine

	//TESTS TO SEE IF MARIO HIT HIS RIGHT SIDE
	//TESTS BOTTON RIGHT
	if(MYCmp<0)
		PosY=(int)((Mario.y+16)/16);
	else
		PosY=(int)((Mario.y+0)/16);
		
	//uses integer division to find the tiles
	PosX=(int)((Mario.x+32)/16)-1;
	
	//crash protect
	if(PosX<0) PosX=0;
	if(PosX>200*16) PosX=200*16;
	if(PosY<0) PosY=0;
	if(PosY>16) PosY=16;
	
	//if mario hit a vine, set vine mode on, else test other right side stuff
	if(Map[PosY][PosX]==67 || Map[PosY][PosX]==68)
		coll_GrabVine(PosX);

	//if mario grabbed the flag pole
	if(Map[PosY][PosX]==14 || Map[PosY][PosX]==45)
		coll_GrabFlagPole(PosX);

	if(!Mario.OnVine)
	{
			//checks to see if its a hit
			if(TestGround(Map[PosY][PosX])==true)
					{Mario.x=(PosX*16)-16; Mario.Momentum=0;}
			
			//TESTS MIDDLE RIGHT		
			PosY=(int)((Mario.y+6)/16);
		
			//crash protect
			if(PosY<0) PosY=0;
			if(PosY>16) PosY=16;

			//checks to see if its a hit
			if(TestGround(Map[PosY][PosX])==true)
					{Mario.x=(PosX*16)-16; Mario.Momentum=0;}
					
			//TESTS UPPER RIGHT		
			PosY=(int)((Mario.y+0)/16);
		
			//crash protect
			if(PosY<0) PosY=0;
			if(PosY>16) PosY=16;
			
			//checks to see if its a hit
			if(TestGround(Map[PosY][PosX])==true)
					{Mario.x=(PosX*16)-16; Mario.Momentum=0;}
					
			//Tests uper a second time if he's big..)
			if((Mario.State==1 || Mario.State==2) && !_keytest(RR_DOWN))
			{
					PosY=(int)((Mario.y-12)/16);
				
					//crash protect
					if(PosY<0) PosY=0;
					if(PosY>16) PosY=16;
					
					//checks to see if its a hit
					if(TestGround(Map[PosY][PosX])==true)
						{Mario.x=(PosX*16)-16; Mario.Momentum=0;}
			}	
	}//end if hit vine on right side
	
	Hit=false;
	//COLLISION DETECTION FOR THE BOTTOM (FEET) OF MARIO IF HE IS MOVING DOWN!
	//CHECKS BOTTOM LEFT
	if(MYCmp>0 || Mario.OnVine) //only if hes moving down...
	{
		//uses integer division to find the tiles
		PosX=(int)((Mario.x+18)/16)-1;
		PosY=(int)((Mario.y+16)/16);
		
		//if mario is on a vine, off set by 1
		if(MVine)
			PosX--;
			
		//crash protect
		if(PosX<0) PosX=0;
		if(PosX>200*16) PosX=200*16;
		if(PosY<0) PosY=0;
		if(PosY>16) PosY=16;
		
		//checks to see if its a hit
		if(TestGround(Map[PosY][PosX])==true)
			Hit=true;
		else if(PosY==16)
			return;
			
		//CHECKS BOTTOM RIGHT
		//uses integer division to find the tiles
		PosX=(int)((Mario.x+28)/16)-1;
		
		//if mario is on a vine, off set by 1
		if(MVine)
			PosX--;
			
		//crash protect
		if(PosX<0) PosX=0;
		if(PosX>200*16) PosX=200*16;
		
		//checks to see if its a hit
		if(TestGround(Map[PosY][PosX])==true)
				Hit=true;
			
		if(Hit==true)
		{
			//Moves mario back up
			//Mario.y-=Mario.YCmp;
			
			//if its the end of the level (Mario just slide down the pole, then move to part 2)
			if(LevelComplete==1)
			{
				LevelComplete=2;
				Mario.OnVine=false;
				Mario.OnFlagpole=false;
				
				if(Mario.State==m_Small)
					Mario.Animation=mss_GrabLeft;
				else
					Mario.Animation=msb_GrabLeft;
				
			}
				
			Mario.y=(PosY*16)-17;
			Mario.YCmp=0;
	
			Mario.IsJumping=false;
			Mario.Airborn=false;
			
			//if mario is on a vine, make sure he isnt animated anymore
			if(MVine)
			{
				if(Mario.State==m_Small)
				{
					if(Mario.Direction==LEFT)
						Mario.Animation=mss_GrabLeft;
					else
						Mario.Animation=mss_GrabRight;
				}else
				{
					if(Mario.Direction==LEFT)
						Mario.Animation=msb_GrabLeft;
					else
						Mario.Animation=msb_GrabRight;
				}

			}
				
			//Mario.Direction=Mario.JDir;
		}else
			Mario.Airborn=true;
	}
	
	
	
	//If Mario Hit A Shroom Or Fire Flower or Star, change his state
	short x; //looping var
	for(x=12;x<14;x++)
	{
		//the particle type
		short PType=Particle[x][p_Type], PX=Particle[x][p_X], PY=Particle[x][p_Y], MX=Mario.x, MY=Mario.y;
		
		if((PType==p_Shroom || PType==p_Flower || PType==p_Star) && Particle[12][p_Life]>16)
		{
			//test for collision
			if(
					(
						(MX+1>PX && MX+1<PX+16)
						||
						(MX+15>PX && MX+15<PX+16)
					)
					&& 
					(
						(
							(MY>PY && MY<PY+16)
							||
							(MY+16>PY && MY+16<PY+16)
							||
							(MY+25>PY && MY+25<PY+16)
						)
						/*||
						(
							(MY>PY && MY<PY+16)
							||
							(MY+25>PY && MY+25<PY+16)
						)*/
					)
				)//then
				{
					//transform mario
					MarioTransform(PType);
					
					//kill the flower / shroom / whatever
					Particle[12][p_Type]=-1;
					
					//spawn a score
					SpawnScore(Mario.x, Mario.y-16, 1000);	
				}
		}
	}//next x
	
	
	//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	
	//CHCEK TO SEE IF MARIO HAS STOMPED AN ENEMY, OR IF AN ENEMY HAS RUN INTO MARIO
	short EX, EY, Type, MX=Mario.x;
	//loop thru all enenmies to see if marios feet have colited with one
	for(x=0;x<Max_Enemies;x++)
	{
		//get enemy info
		Type=Enemy[x][e_Type];
		EX=Enemy[x][e_X];
		EY=Enemy[x][e_Y];
		
		//if its an enemy that can be stomped:
		if(coll_CanStomp(Type) && Enemy[x][e_Ani]!=es_Dead)
		{
			//test to see if marios feet are in colision with an enemy
			if(
					//is marios Y with in the range?
					(MY+16>=EY && MY+16<=EY+12)
					&&
					//test teh x positions
					(
						//bottom left?
						(MX+4>=EX && MX+4<=EX+16)
						||
						//bottom middle
						(MX+8>=EX && MX+8<=EX+16)
						||
						//bottom right
						(MX+12>=EX && MX+12<=EX+16)
					)
				)
			{
				//stop the enemy
				coll_StompEnemy(x, Mario.Direction);
				
				//give mario a bit of "bounce"
				if(Mario.YCmp>0)
					Mario.YCmp=-5;
				else
					Mario.YCmp-=3;
				
				//make sure mario can escape the bounce
				Mario.JDir2=0;
				
			}//end if collision with feet
		}//end if enemy can be stomped
		
		//only can collide with enemies that arent dead or non existant
		if(Enemy[x][e_Type]!=-1 && Enemy[x][e_Ani]!=es_Dead && Enemy[x][e_Type]!=eStompedGoomba)
		{
			//tests to see if marios right or left side have collided with an enemy, and if so
			//push mario to the side, / hurt him
			if(
					//is marios Y with in the range?
					//test y positions
					(
						//top of mario
						(MY+0>=EY && MY+0<=EY+12)
						||
						//middle of mario
						(MY+6>=EY && MY+6<=EY+12)
						||
						//bottom middle
						(MY+12>=EY && MY+12<=EY+12)
					)
					&&
					//test teh x positions
					(
						//left side?
						(MX+4>=EX && MX+4<=EX+16)
						||
						//right side?
						(MX+12>=EX && MX+12<=EX+16)
					)
				)
			{
				//find if mario is more to the left or righ of the enemy, and move him accordingly (if not invunerable)
				if(!Mario.Invincible)
				{
					if(MX<EX)
						Mario.x=EX-16;
					if(MX>=EX)
						Mario.x=EX+16;
						
					//now that mario has collided, kill is momentum
					Mario.Momentum=0;
				}

				//hurt mario, if nessicary
				//*will kick buzzy / koopa sheels*
				coll_MarioEnemyBump(Enemy[x][e_Type], x);
			}//end if mario collided with the side of it
		}//end if enemy is alice and well
	}//next x
}

//TRANSFORMS MARIO'S STATE
void MarioTransform(short Type)
{
	//if mario is fire, just give him points..
	//To Be Programmed
	
	//if its a star, make mario invincible, exit
	if(Type==p_Star)
	{
		//make him invincible
		Mario.Invincible=200;

		//exit, nothing left to check for
		return;
	}
	
	short MState=Mario.State;
	//if mario is big, make him fire mario
	if(MState==m_Big)
	{
		Mario.State=m_Fire;
		Mario.Transition=22;
	}
	
	//if mario is small, make him big
	if(MState==m_Small)
	{
		Mario.State=m_Big;
		Mario.Transition=11;
	}
	
	//give mario score..
	Mario.Score+=1000;
}

//THIS SUB TESTS IF MARIO HIT A TILE HE CAN STAND ON
char TestGround(short Type)
{
	if(Type==66 && Mario.OnVine)
		return false;
		
	//peices you cannont stand on
	//0 14 16 17 18 19 20 21 22 23 38 41
	if(Type==00 ||
	   Type==14 ||
	   Type==16 ||
	   Type==17 ||
	   Type==18 ||
	   Type==19 ||
	   Type==20 ||
	   Type==21 ||
	   Type==22 ||
	   Type==23 ||
	   Type==38 ||
	   Type==41 ||
	   Type==43 ||
	   Type==47 ||
	   Type==48 ||
	   Type==49 ||
	   Type==50 ||
	   Type==51 ||
	   Type==52 ||
	   Type==53 ||
	   Type==59 ||
	   Type==60 ||
	   Type==61 ||
	   Type==62 ||
	   Type==63 ||
	   Type==64 ||
	   Type==7 ||
	   Type==8 ||
	   Type==9 ||
	   Type==10 ||
	   Type==11 ||
	   Type==12 ||
	   Type==13 ||
	   Type==67 ||
	   Type==68) 
		return false;
	else
		return true;
}

//HANDLES IT WHEN MARIO PUNCHES SOMETHING
void coll_DoBump(short PosX, short PosY)
{
	//grabs the maps tile
	short Tile=Map[PosY][PosX];
	short MState=Mario.State;
	
	//if no bump is true, exit and dont bump the tile..
	if(coll_NoBump(Tile))
		return;
			
	//TESTS FOR BOTH SMALL AND BIG MARIO...
	if(Tile==2)	//if its a ? box
	{
		Map[PosY][PosX]=3;	//set it to an empty ? box
		
		//give mario a coin
		Mario.Coins++;
		
		//+200 points for a coin!
		Mario.Score+=200;
		
		//make the coin fly
		coll_SpawnCoin(PosX,PosY);
	}
		
	
	if(Tile==90) //if its a power up box
	{
		Map[PosY][PosX]=3;	//set it to an empty ? box
		
		//spawn the correct power up..
		//if mario is big already, make it a fire flower, else, shroom
		if(MState==m_Big || MState==m_Fire)
			coll_SpawnFlower(PosX, PosY);
		else
			coll_SpawnShroom(PosX, PosY);
	}
	
	if(Tile==91) //if its a hidden star box
	{
		Map[PosY][PosX]=3;	//set it to an empty ? box
		
		//spawn star..
		coll_SpawnStar(PosX, PosY);
	}
	
	if(Tile==92) //if its a star box
	{
		Map[PosY][PosX]=3;	//set it to an empty ? box
		
		//spawn star..
		coll_SpawnStar(PosX, PosY);
	}
	
	if(Tile==93) //if its a hidden power up box
	{
		Map[PosY][PosX]=3;	//set it to an empty ? box
		
		//spawn the correct power up..
		//if mario is big already, make it a fire flower, else, shroom
		if(MState==m_Big || MState==m_Fire)
			coll_SpawnFlower(PosX, PosY);
		else
			coll_SpawnShroom(PosX, PosY);
	}
	
	if(Tile==94) //if its a hidden coin brick
	{
		/*NOTE! FOR NOW THEY GIVE OUT INFINITE!!!!!!!!*/
		//give mario a coin
		Mario.Coins++;
		
		//+200 points for a coin!
		Mario.Score+=200;
		
		//make the coin fly
		coll_SpawnCoin(PosX,PosY);
	}
	
	if(Tile==95) //if its a invisible star box
	{
		Map[PosY][PosX]=3;	//set it to an empty ? box
		
		//spawn star..
		coll_SpawnStar(PosX, PosY);
	}
	
	if(Tile==96) //if its a invisible power up box
	{
		Map[PosY][PosX]=3;	//set it to an empty ? box
		
		//spawn the correct power up..
		//if mario is big already, make it a fire flower, else, shroom
		if(MState==m_Big || MState==m_Fire)
			coll_SpawnFlower(PosX, PosY);
		else
			coll_SpawnShroom(PosX, PosY);
	}
	
	//TESTS FOR BIG MARIO ONLY
	if(MState==m_Big || MState==m_Fire)
	{
		if(Tile==6 || Tile==44) //if its a brick,
		{
			Map[PosY][PosX]=0;	//kill it
			coll_BrickSmash(PosX,PosY); //make the mini bricks fly
			return; //no need to continue, plus saving the posx and y have negative side f-ect
		}
			
	}
	//saves which is bumped
	BumpX=PosX;
	BumpY=PosY;
}


//THIS SUB SETS UP THE MINI BRICKS TO GO FLYING
void coll_BrickSmash(short PosX, short PosY)
{
	short TheParticle;
	
	//which set of four should it used?
	if(Particle[0][p_Type]==-1) //if the first set is empty use them, 
		TheParticle=0;
	else //otherwise use the other set of four
		TheParticle=4;
		
	//set up the first paritcle
	Particle[TheParticle][p_X]=PosX*16;
	Particle[TheParticle][p_Y]=PosY*16;
	Particle[TheParticle][p_Type]=1;
	Particle[TheParticle][p_YCmp]=-6;
	Particle[TheParticle][p_Dir]=-2;
	//set up the second paritcle
	Particle[TheParticle+1][p_X]=PosX*16;
	Particle[TheParticle+1][p_Y]=PosY*16+8;
	Particle[TheParticle+1][p_Type]=1;
	Particle[TheParticle+1][p_YCmp]=-4;
	Particle[TheParticle+1][p_Dir]=-2;
	//set up the third paritcle
	Particle[TheParticle+2][p_X]=PosX*16+8;
	Particle[TheParticle+2][p_Y]=PosY*16;
	Particle[TheParticle+2][p_Type]=1;
	Particle[TheParticle+2][p_YCmp]=-6;
	Particle[TheParticle+2][p_Dir]=2;
	//set up the fourth paritcle
	Particle[TheParticle+3][p_X]=PosX*16+8;
	Particle[TheParticle+3][p_Y]=PosY*16+8;
	Particle[TheParticle+3][p_Type]=1;
	Particle[TheParticle+3][p_YCmp]=-4;
	Particle[TheParticle+3][p_Dir]=2;
	
	//give mario score..
	Mario.Score+=50;
	
	BumpX=PosX;
	BumpY=PosY;
}


//THIS SUB CHEKS TO SEE IF A PARTCLE HIT SOMETHING IT SHOULD INTERACT WITH
void coll_ParticleCollision()
{
	short x, y, PType, PDir; //looping var
	int PosX=0, PosY; //the tile the particle is on

	for(x=0;x<Max_Particles;x++)
	{
		//the type of particle to test for
		PType=Particle[x][p_Type];
		
		//skip if its not an active particle..
		if(PType!=-1)
		{
		
			//uses integer division to find the tiles
			PosX=(int)(Particle[x][p_X]/16);
			PosY=(int)((Particle[x][p_Y]+8)/16);
			
			//if the particle is moving right, test one earlier
			//if(Particle[x][4]>0)
			//	PosX+=1;
				
			//crash protect (make sure its within the maps boundries)
			if(PosX<0) PosX=0;
			if(PosX>200*16) PosX=200*16;
			if(PosY<0) PosY=0;
			if(PosY>16) PosY=16;
			
			//if it hit a ground tile... (or a 'solid' tile)
			if(TestGround(Map[PosY][PosX])==true)
			{
					//if(PosY*16<Particle[x][p_Y])
						//{
					//if its a firebal
					if(PType==p_Fire)
					{
						//if the last x pos is one less or greater, then its a bonified collision
						if(Particle[x][p_LastX]==(PosX-1) || Particle[x][p_LastX]==(PosX+1))
						{
							//dont kill it, if the last tile was also solid
							if(!TestGround(Map[PosY][Particle[x][p_LastX]]))
							{
								//repalce the particle with an explosion particle...
								Particle[x][p_Type]=p_Explosion;
										
								//reset particle life..
								Particle[x][p_Life]=0;
										
								//center explosion
								Particle[x][p_X]-=8;
							}			
						}
						else
							Particle[x][p_YCmp]=-5;
					}
			}//end if on solid
			
			//does shizzle based on what type of particle it is
			if(PType==p_Fire)
			{
				//check to see if the particle crashed into an enemy
				for(y=0;y<Max_Enemies;y++)
				{
					//if the particle is an active enemy, check for collision
					if(Enemy[y][e_Type]!=-1 && Enemy[y][e_Ani]!=es_Dead && Particle[x][p_Type]==p_Fire)
					{
						short X1=Particle[x][p_X], Y1=Particle[x][p_Y], X2=Enemy[y][e_X], Y2=Enemy[y][e_Y], W=16, H=16, W2=6, H2=8, H3=10, H4=12;
						
						//collided? then call coll_FireEnemy(y)
						if (((X1>=X2 && X1<=X2+W)
						   ||
						   (X1+W2>=X2 && X1+W2<=X2+W))
						   &&
						   ((Y1>=Y2 && Y1<=Y2+H)
						   ||
						   (Y1+H2>=Y2 && Y1+H2<=Y2+H)
						   ||
						   (Y1+H3>=Y2 && Y1+H3<=Y2+H)
						   ||
						   (Y1+H4>=Y2 && Y1+H4<=Y2+H)))
						   //{

						{
							//hit the enemy with a fire ball
							coll_FireEnemy(y, Particle[x][p_Dir]);
							
							//add an explosion to the secen
							//repalce the particle with an explosion particle...
							Particle[x][p_Type]=p_Explosion;
									
							//reset particle life..
							Particle[x][p_Life]=0;
									
							//center explosion
							//Particle[x][p_X]-=8;
						}
					}//end if active enemy
				}//next y
			}	
					
			//TESTS FOR SPRITES 16 TALL
			//TESTS FOR SPRITES 16 TALL
			//TESTS FOR SPRITES 16 TALL
			PosY=(int)((Particle[x][p_Y]+16)/16);
			
			//crash protect (make sure its within the maps boundries)
			if(PosY<0) PosY=0;
			if(PosY>16) PosY=16;
			
			//the dir of the particle
			PDir=Particle[x][p_Dir];
			
			//if it hit a ground tile... (or a 'solid' tile) and its 16 tall...
			if(TestGround(Map[PosY][PosX])==true)
			{
				//if its a shroom, that isnt underage
				if(PType==p_Shroom && Particle[x][p_Life]>16)
				{	
					//kill its ycmp
					Particle[x][p_YCmp]=0;
					
					//make sure its above ground
					Particle[x][p_Y]=(PosY-1)*16+1;
					
					//tests to see if it hit anything on the right or left side,
					//dependant upon its direction
					if(PDir>0)
						{if(TestGround(Map[PosY-1][PosX+1])==true)
							Particle[x][p_Dir]*=-1;}
					else if(PDir<0)
						{if(TestGround(Map[PosY-1][PosX])==true)
							Particle[x][p_Dir]*=-1;}
				}
				if(PType==p_Star && Particle[x][p_Life]>16)
				{	
					//kill its ycmp
					Particle[x][p_YCmp]=-8;
					
					//make sure its above ground
					Particle[x][p_Y]=(PosY-1)*16+1;
					
					//tests to see if it hit anything on the right or left side,
					//dependant upon its direction
					if(PDir>0)
						{if(TestGround(Map[PosY-1][PosX+1])==true)
							Particle[x][p_Dir]*=-1;}
					else if(PDir<0)
						{if(TestGround(Map[PosY-1][PosX])==true)
							Particle[x][p_Dir]*=-1;}
				}
				//if its a star, that isnt under age
				
			}//end if on solid (16 tall)
				
				
			//save the tile its currently on
			Particle[x][p_LastX]=PosX;
		}//end if inactive
	}//next x
	
	
}
		

//TESTS TO SEE IF AN ENEMY HIT SOMETHING...
void coll_EnemyCollision()
{
	short x, y, Type, Type2, EDir; //looping var
	int PosX, PosY; //the tile the particle is on

	//loop to test all enemies
	for(x=0;x<Max_Enemies;x++)
	{
		Type=Enemy[x][e_Type];
		
		//if the enemy has fallen off the screen, remove it from gameplay
		if(Enemy[x][e_Y]>256)
			Enemy[x][e_Type]=-1;
			
		//if enemy x is real, check to see if it hit another enemy
		if(Type!=-1 && Enemy[x][e_Ani]!=es_Dead)
		{
			//check to see if the enemy has colided with another enemy, and then do something about it
			for(y=0; y<Max_Enemies; y++)
			{
				Type2=Enemy[y][e_Type];
				
				//if its not itself, and its a vaild enemy, see if colided
				if(x!=y && Type2!=-1 && Type!=-1 && coll_CanCollide(Type, Type2) && Enemy[y][e_Ani]!=es_Dead)
				{
					//test for colision
					if(coll_TestCollide(Enemy[x][e_X], Enemy[x][e_Y], Enemy[y][e_X], Enemy[y][e_Y], 16, 16))
					{
						//if its a shell, KNOCK ENEMY
						if((Type==eShell || Type==eBuzzyShell) && Enemy[x][e_Dir]!=0)
						{
							coll_FireEnemy(y, Enemy[x][e_Dir]);
							continue;
						}
							
						
						//then they are going opposite direcetions, so collide both
						Enemy[x][e_Dir]*=-1;
						Enemy[y][e_Dir]*=-1;
						
						Enemy[x][e_X]+=Enemy[x][e_Dir]*2;
						Enemy[y][e_X]+=Enemy[y][e_Dir]*2;
						
						//if(Enemy[x][e_Type]==eKoopa)
						//	printf_xy(1,20,"K");
						
					}//end if collided
				}//end if valid enemy
			}//next y



			//TEST TO SEE IF THE ENEMY HAS HIT THE GROUND, OR A WALL
			//uses integer division to find the tiles
			PosX=(int)(Enemy[x][e_X]/16);
			PosY=(int)((Enemy[x][e_Y]+16)/16);
			
			//if the particle is moving right, test one earlier
			//if(Particle[x][4]>0)
			//	PosX+=1;
				
			//crash protect (make sure its within the maps boundries)
			if(PosX<0) PosX=0;
			if(PosX>200*16) PosX=200*16;
			if(PosY<0) PosY=0;
			if(PosY>16) PosY=16;

			
			//if it hit a ground tile... (or a 'solid' tile) and its 16 tall...
			if(TestGround(Map[PosY][PosX])==true)
			{
				//if its a spiny egg, turn it into a spiny
				if(Type==eSpinyEgg)
				{
					//convert the spiny egg to a spiny
					Enemy[x][e_Type]=eSpiny;
					Enemy[x][e_YCmp]=0;
				}
					
					
				//if its a goomba, buzzy, spiny, shell, that isnt underage. or if its a right side up buzz \ koopa shell
				if(Type==eGoomba || Type==eBuzzy || Type==eSpiny || Type==eShell || Type==eHammer || Type==eBuzzyShell || Type==eShell || Type==eKoopa)
				{
					//kill its ycmp
					Enemy[x][e_YCmp]=0;
					
					//make sure its above ground
					Enemy[x][e_Y]=(PosY-1)*16+1;
					
					EDir=Enemy[x][e_Dir];
					
					//tests to see if it hit anything on the right or left side,
					//dependant upon its direction
					if(EDir>0)
						{if(TestGround(Map[PosY-1][PosX+1])==true)
							Enemy[x][e_Dir]*=-1;}
					else if(EDir<0)
						{if(TestGround(Map[PosY-1][PosX])==true)
							Enemy[x][e_Dir]*=-1;}
				}
				
				
				//if its a koopa
				if(Type==eKoopa)
				{	
					//kill its ycmp
					Enemy[x][e_YCmp]=0;
					
					//make sure its above ground
					Enemy[x][e_Y]=(PosY-1)*16+1;		
				}	
			}//end if on solid
				
			//if it was a bumped tile
			if((Type==eGoomba || Type==eBuzzy || Type==eSpiny || Type==eKoopa || Type==eAirKoopa) && (BumpX==PosX || BumpX==PosX+1) && BumpY==PosY)
				coll_KnockEnemy(x);
					
			//if its koopa
			if(Type==eKoopa)
			{	
				EDir=Enemy[x][e_Dir];
				
				//tests to see if it hit anything on the right or left side,
				//dependant upon its direction
				if(EDir>0)
					{if(TestGround(Map[PosY][PosX+1])==false)
						Enemy[x][e_Dir]*=-1;}
				if(EDir<0)
					{if(TestGround(Map[PosY][PosX])==false)
					{
						Enemy[x][e_Dir]*=-1;
						Enemy[x][e_Y]=(PosY-1)*16+1;
					}}		
			}

			
			
		}//end if non active enemy
	}//next x
}



//MISCELENEOUS COLLISION STUFF (SPAWNING...)
//MISCELENEOUS COLLISION STUFF (SPAWNING...)
//MISCELENEOUS COLLISION STUFF (SPAWNING...)

//SPAN A SHOORM AS NESSICARY
void coll_SpawnShroom(short PosX, short PosY)
{
	short P;
	
	//finds a particle to store it in
	if(Particle[12][p_Type]==-1)
		P=12;
	else
		P=13;
	
	//sets up the particle
	Particle[P][p_Type]=p_Shroom;
	Particle[P][p_X]=PosX*16;
	Particle[P][p_Y]=PosY*16;
	Particle[P][p_Dir]=2;
	Particle[P][p_YCmp]=0;
	Particle[P][p_Life]=0;
}


//SPAWN A FIRE FLOWER AS NESSICARY
void coll_SpawnFlower(short PosX, short PosY)
{
	short P;
	
	//finds a particle to store it in
	if(Particle[12][p_Type]==-1)
		P=12;
	else
		P=13;
		
	//sets up the particle
	Particle[P][p_Type]=p_Flower;
	Particle[P][p_X]=PosX*16;
	Particle[P][p_Y]=PosY*16;
	Particle[P][p_Life]=0;	
}

//SPAWN A COIN PARTICLE
void coll_SpawnCoin(short PosX, short PosY)
{
	short P=0, x;
	
	//loop thru particles to find a free one
	for(x=0;x<Max_Particles;x++)
		if(Particle[x][p_Type]==-1)
		{
			P=x;
			x=Max_Particles+1;
		}
	
	//sets up the particle
	Particle[P][p_Type]=p_SpinCoin;
	Particle[P][p_X]=PosX*16+4;
	Particle[P][p_Y]=(PosY-1)*16;
	Particle[P][p_Life]=0;
	
}

//SPAWN A SUPER STAR
void coll_SpawnStar(short PosX, short PosY)
{
	short P;
	
	//finds a particle to store it in
	if(Particle[12][p_Type]==-1)
		P=12;
	else
		P=13;
	
	//sets up the particle
	Particle[P][p_Type]=p_Star;
	Particle[P][p_X]=PosX*16;
	Particle[P][p_Y]=PosY*16;
	Particle[P][p_Dir]=2;
	Particle[P][p_YCmp]=0;
	Particle[P][p_Life]=0;
}


//TESTS TO SEE IF A BUMP SHOULD NOT HAPPEN
short coll_NoBump(short Tile)
{
	short CheckList[25]={0,5,7,8,9,10,11,12,13,24,25,26,27,28,29,30,31,32,33,34,35,36,37}, x;
	
	//loop thru to make sure it isnt an unbumpable tile
	for(x=0;x<25;x++)
	{
		if(Tile==CheckList[x])
			return true;
	}//next x
	
	//otherwise, it is bumpable
	return false;
}

///TESTS TO SEE IF A TILE SHOULD REBOUND MARIO OR NOT
short coll_NoRebound(short Tile)
{
	short CheckList[1]={42}, x;
	
	//loop thru to make sure it isnt an rebound tile
	for(x=0;x<1;x++)
	{
		if(Tile==CheckList[x])
			return true;
	}//next x
	
	
	//otherwise you should rebound
	return false;
}

//TESTS TO SEE IF TWO WxH RECTANGLES HAVE COLLIDED
short coll_TestCollide(short X1, short Y1, short X2, short Y2, short W, short H)
{
	//big test
	if(((X1>=X2 && X1<=X2+W)
	   ||
	   (X1+W>=X2 && X1+W<=X2+W))
	   &&
	   ((Y1>=Y2 && Y1<=Y2+H)
	   ||
	   (Y1+H>=Y2 && Y1+H<=Y2+H)))
	   return 1;
	   else
	   return 0;
}

//RETURNS TRUE IF AN ENEMY PAIR CAN COLLID
short coll_CanCollide(short Type1, short Type2)
{
	/*The Following Enemies Cannot Collide:
	-Bullet Bill
	-Podoboo
	-Pirhana Plant
	-Cheep Cheep
	-Air Cheep Cheep
	-Hammer Bro
	-Blooper
	-Laukutu*/
	
	//if either is a shell, they can collide
	if(Type1==eShell || Type2==eShell || Type1==eBuzzyShell || Type2==eBuzzyShell)
		return 1;
		
	//test if either is one of those, if so, exit
	if(Type1==eBullet || Type2==eBullet)
		return 0;
	else if(Type1==ePodobo || Type2==ePodobo)
		return 0;
	else if(Type1==ePodobo || Type2==ePodobo)
		return 0;
	else if(Type1==ePlant || Type2==ePlant)
		return 0;
	else if(Type1==eCheep || Type2==eCheep)
		return 0;
	else if(Type1==eAirCheep || Type2==eAirCheep)
		return 0;
	else if(Type1==eHammer || Type2==eHammer)
		return 0;
	else if(Type1==eCannon || Type2==eCannon)
		return 0;
	else if(Type1==eLakutu || Type2==eLakutu)
		return 0;
	else if(Type1==ePodobo || Type2==ePodobo)
		return 0;
	else
		return 1;	
}

//MAKES MARIO GRAB ON TO A VINE
void coll_GrabVine(short PosX)
{
	//sets him on a vine
	Mario.OnVine=true;
	
	//give him the correct position
	Mario.x=PosX*16+6;
	
	//cant be jumping on a vine
	Mario.IsJumping=false;
	
	//no more y component for mario
	Mario.YCmp=0;
}

//MAKES MARIO GRAB ONTO THE FLAG POLE
void coll_GrabFlagPole(short PosX)
{
	if(LevelComplete==2) return;
	
	//sets him on a vine
	Mario.OnFlagpole=true;
	Mario.OnVine=true;
	
	//give him the correct position
	Mario.x=PosX*16+6;
	
	//cant be jumping on a vine
	Mario.IsJumping=false;
	
	//begining of the end
	LevelComplete=1;
	
	if(Mario.State==m_Small)
		Mario.Animation = mss_GrabRight;
	else
		Mario.Animation = msb_GrabRight;
}

//KNOCKES AN ENEMY
void coll_KnockEnemy(short E)
{
	//kill enemy
	Enemy[E][e_YCmp]=5;
	Enemy[E][e_Ani]=es_Dead;

	//special enemies
	short Type=Enemy[E][e_Type];
	
	//if its a koopa or kooopa paratroopa, turn it into a shell
	if(Type==eKoopa || Type==eAirKoopa)
		Enemy[E][e_Type]=eShell;
	
	//if its a buzzy, turn it into a buzzy shell
	if(Type==eBuzzy)
		Enemy[E][e_Type]=eBuzzyShell;
		
	//dont kill spinys.. 
	if(Type==eSpiny)
		{
			Enemy[E][e_Ani]=0;
			return;
		}
		
	//add score particle / update score
	SCORE(Type, Enemy[E][e_X], Enemy[E][e_Y], sc_Knock);
}


//HITS AN ENEMY WITH A FIRE BALL
void coll_FireEnemy(short E, short Dir)
{
	//kill enemy
	Enemy[E][e_YCmp]=5;
	Enemy[E][e_Ani]=es_Dead;

	//special enemies
	short Type=Enemy[E][e_Type];
	
	//if its a plant, just remove it
	if(Type==ePlant)
		Enemy[E][e_Type]=-1;
	
	//if its a koopa or kooopa paratroopa, turn it into a shell
	if(Type==eKoopa || Type==eAirKoopa)
	{
		Enemy[E][e_Type]=eShell;
		Enemy[E][e_Ani]=es_Dead;
		
	}
		
		
	//cant kill buzzys / buzzy shells or bullet bill cannons
	if(Type==eBuzzy || Type==eBuzzyShell || Type==eCannon)
	{
		Enemy[E][e_Ani]=0;
		return;
	}
	
	//make sure the enemy flies the same direction as the ball was traveling
	Enemy[E][e_Dir]=(Dir/abs(Dir))*2;
	
	//add score particle / update score
	SCORE(Type, Enemy[E][e_X], Enemy[E][e_Y], sc_Fire);
}


//"STOMPS" AN ENEMY
void coll_StompEnemy(short E, short Dir)
{
	//kill enemy
	Enemy[E][e_YCmp]=0;

	//special enemies
	short Type=Enemy[E][e_Type];

	//if its a goomba, turn it into a stomped goomba
	if(Type==eGoomba)
	{
		Enemy[E][e_Type]=eStompedGoomba;
		Enemy[E][e_Life]=30;
		
		//score for the goomba
		SCORE(Type, Enemy[E][e_X], Enemy[E][e_Y], sc_Stomp);
		
		return;
	}
		
	//if its a koopa turn it into a shell
	if(Type==eKoopa)
	{
		Enemy[E][e_Type]=eShell;
		Enemy[E][e_Ani]=1;
		Enemy[E][e_Dir]=0;
		return;
	}

	//if its a koopa paratroopa, remove its wings
	if(Type==eAirKoopa)
	{
		Enemy[E][e_Type]=eKoopa;
		Mario.y-=3;
		return;
	}
	
	//if its buzzy, turn into a shell
	if(Type==eBuzzy)
	{
		Enemy[E][e_Type]=eBuzzyShell;
		Enemy[E][e_Ani]=-1;
		Enemy[E][e_Dir]=0;
		return;
	}
	
	//if its a koopa shell or a buzzy shell, just do nothing
	if(Type==eShell || Type==eBuzzyShell)
		return;
		
	//kill the enemy
	Enemy[E][e_Ani]=es_Dead;
	
	//make sure the enemy flies the same direction as the ball was traveling
	Enemy[E][e_Dir]=Dir;
	
	//add score particle / update score
	SCORE(Type, Enemy[E][e_X], Enemy[E][e_Y], sc_Stomp);
}


//HITS AN ENEMY WITH A FIRE BALL
void coll_KillEnemy(short E, short Dir)
{
	//kill enemy
	Enemy[E][e_YCmp]=5;
	Enemy[E][e_Ani]=es_Dead;

	//special enemies
	short Type=Enemy[E][e_Type];
	
	//if its a plant, just remove it
	if(Type==ePlant)
		Enemy[E][e_Type]=-1;
	
	//if its a koopa or kooopa paratroopa, turn it into a shell
	if(Type==eKoopa || Type==eAirKoopa)
	{
		Enemy[E][e_Type]=eShell;
		Enemy[E][e_Ani]=es_Dead;
		
	}
	
	//make sure the enemy flies the same direction as mario was traveling
	Enemy[E][e_Dir]=Dir*2;
	
	//add score particle / update score
	SCORE(Type, Enemy[E][e_X], Enemy[E][e_Y], sc_Invince);
}


//eGoomba, eKoopa, eAirKoopa, eBuzzy, eLakutu, eSpiny, eSpinyEgg, eHammer, eCheep, eAirCheep, eBullet,
//eSquid, ePlant, ePodobo, eShell, eFlameCW45, eFlameCW315, eFlameCW225, eFlameCW135, eFlameCCW45, 
//eFlameCCW315, eFlameCCW225, eFlameCCW135, eCannon, eBuzzyShell
//RETURNS TRUE IF AN ENEMY CAN BE STOMPS
short coll_CanStomp(short Type)
{
	//simply check if its true or not
	if(Type==eGoomba ||
		 Type==eKoopa ||
		 Type==eAirKoopa ||
		 Type==eBuzzy ||
		 Type==eLakutu ||
		 Type==eHammer ||
		 Type==eBullet ||
		 Type==eAirCheep ||
		 Type==eShell ||
		 Type==eBuzzyShell)
		return true;
	else
		return false;		 
}


//HURTS MARIO IF HE BUMPS AND ENEMY, OR KICKS A SHELL, OR KILLS AND ENEMY IF INVINCIBLE
void coll_MarioEnemyBump(short Type, short E)
{
	short MDir=Mario.Direction;
	
	//is mario invincible?
	if(Mario.Invincible)
	{
		//kill enemy / give score
		coll_KillEnemy(E, MDir);
		
		//exit, nothing left to do or kick...
		return;
	}//end if invincible
	
	//if the type is a koopa sheel or a buzzy shell THAT IS STATIONARY
	if((Type==eShell || Type==eBuzzyShell) && Enemy[E][e_Dir]==0)
	{
		//makes the shell go the same direction as mario, 3 times as fast
		if(MDir==RIGHT)
			Enemy[E][e_Dir]=3;
		else
			Enemy[E][e_Dir]=-3;
		
		//exit, nothing left to do
		return;
	}//end if mario kicked a shell
	
	//if the invunerability cheat is on, dont hurt mario!
	if(Cheats.Invincible)
		return;
		
	//if the type is a koopa shell or a buzzy shell, or any other type of enemy, then register a collision and "hurt" mario
	if(Mario.State>0)
	{
		//make mario small
		Mario.State=0;
		
		//mario will now transform to smaller mario
		Mario.Transition=11;
		
		//give mario invunerablity
		Mario.Invincible = 60;
	}
	else
		KillMario();
}