// Asteroids.java:  Defines Target like classes for Stoneroids...

// Classes Defined:		stAsteroid

import java.awt.*;
import Stoneroids;    import GameActor;
import stAlienShip;   import stShip;      import stLaser;   import stPowerup;


// stAsteroid objects derived from GameActor.  This is your ENEMY!
class stAsteroid extends GameActor
{
	double  angleSpeed;			// Angular Rotation of Asteroid
	int     AstPoints;			// Approx num of points
	double  AstSize;			// Approx size (radius)
	int     PrizeType;			// Type of powerup when killed (0=none)

	// Initializes object to stAsteroid defaults
	stAsteroid()
	{
		super();
		cx = px = Math.random()*(screenRect.width-16)+8;
		cy = py = Math.random()*(screenRect.height-16)+8;
		// Make Asteroid emerge from T/B or L/R edge of screen...
		if (Math.random() > .5)   cy = py = -50;   else   cx = px = -50;

		speed = Math.random()*3 + thisApp.level/3;
		if (speed > 7)    speed = 7;					// Max initial speed is 7 ppf

		MakePolyShape(.25, (12+Math.random()*16));
		init();			// Initialize other Asteroid members
	}

	// Make an Asteroid with specific speed, size and x,y location
	stAsteroid(double x, double y, double variance, double size, double spd)
	{
		super();
		cx = px = x;    cy = py = y;
		if (spd >= 0)    speed = spd;
		if (size < 6)    AstSize = 6;	else    AstSize = size;

		MakePolyShape(variance, AstSize);
		init();			// Initialize other Asteroid members
	}

	// Shared code between different stAsteroid constructors...
	void init()
	{
		status = 1;    PrizeType = 0;
		active = onscreen = movable = true;
		solidFill = true;
		color = new Color((int)(Math.random()*80), (int)(Math.random()*80),
			(int)(Math.random()*95+80));
		angleSpeed = (Math.random()*8-4)*Math.PI/180;	// Rotates up to 4 deg per frame
		angle = Math.random()*2*Math.PI;
		dx = speed * Math.cos(angle);    dy = speed * Math.sin(angle);

		// Smaller and/or faster asteroids yield more score...
		ScoreVal = (int)(speed*20 - AstSize + 10)/5*5;
		if (ScoreVal < 10)    ScoreVal = 10;	// Prevent negative or tiny values
		RotatePoly();
	}


	// Initialize the initial shape and bounding box for Asteroid objects.
	void MakePolyShape()
	{
		poly = new Polygon();
		poly.addPoint(-7,15);   poly.addPoint(7,15);     poly.addPoint(15,0);
		poly.addPoint(7,-15);   poly.addPoint(-7,-15);   poly.addPoint(-15,0);
		bbox = poly.getBoundingBox();
		polyO = new Polygon(poly.xpoints, poly.ypoints, poly.npoints);
	}

	// Uses variance and size to compute random asteroid shapes...
	// Variance helps generate a random % change between points.
	void MakePolyShape(double variance, double size)
	{
		int points = (int)(size/2+4);
		double a = 0, r = size, x, y;
		double da = 2*Math.PI/points;

		poly = new Polygon();
		poly.addPoint((int)size, 0);	// First point
		r = size * (variance*(Math.random()*2 - 1) + 1);	// +- variance%
		a += da * (variance*(Math.random()*2 - 1) + 1);		// +- variance%
		do
		{
			x = r * Math.cos(a);    y = r * Math.sin(a);
			poly.addPoint((int)x, (int)y);					// Here's the point

			// Randomize radius & angle to set up next point...
			a += da * (variance*(Math.random()*2 - 1) + 1);
			r = size * (variance*(Math.random()*2 - 1) + 1);
		}
		while (a < 2*Math.PI);			// Finished when we turn full circle

		poly.addPoint((int)size, 0);			// Last point (same as First)
		bbox = poly.getBoundingBox();
		polyO = new Polygon(poly.xpoints, poly.ypoints, poly.npoints);
		points = poly.npoints;
		AstSize = size;    AstPoints = poly.npoints;
	}

	// Moves Asteriod (and angular velocity)...
	void Move()
	{
		angle += angleSpeed;			// Rotate Asteriod...
		super.Move();					// ...Then move it
	}


	// Handles how an Asteroid object dies.  Update Score...
	void Explode()
	{
		Split();
		super.Explode();
		SFX[sfxExplode].play();
		
		// There's a chance a dying Asteroid will drop a Powerup
		double chance = .18 - (thisApp.level*0.015);
		if (chance < 0.04)    chance = 0.04;
		if (Math.random() < chance)
		{
			int pType = stPowerup.RandType();
			AddObject(new stPowerup(this, pType, 125));
		}
	}


	// Add one to the "Target Hits" counter when an Asteroid dies...
	void Death()
	{
		thisApp.TargetsHit++;
//		thisApp.showStatus("Ast Hits: " + thisApp.TargetsHit
//			+"   Next: " + thisApp.NextAlien
//			+"   List: " + thisApp.szAlienList);
		super.Death();
	}

	
	// What object classes should collide with Asteroid objects?
	boolean CanCollide(GameActor objY)
	{
		// ...Any objects except for Asteroids and Powerups.
		if (objY instanceof stAsteroid)    return false;
		if (objY instanceof stPowerup)    return false;
		return true;
	}
	
	// What should an Asteroid do if it hits something?
	void OnHit(GameActor objY)
	{
		if (!invincible  &&  !objY.invincible)
		{
			if (objY instanceof stShip  ||  objY instanceof stLaser
				||  objY instanceof stAlienShip)
			{
				Explode();
				if (objY instanceof stLaser  &&  objY.pOwner != null)
				{
					if (objY.pOwner instanceof stShip)			// Ship gets full points
						objY.pOwner.ScoreVal += ScoreVal;
					if (objY.pOwner instanceof stAlienShip)		// Alien gets half points
						objY.pOwner.ScoreVal += ScoreVal/10*5;
					objY.Death();
				}

				if (objY instanceof stShip || objY instanceof stAlienShip)
						objY.Damage(this);
				else	objY.shield -= AstSize;
				if (objY.active  &&  objY.shield < 0)    objY.Explode();
			}
		}
	}

	// Splits an Asteroid into two smaller ones (if big enough to split)
	void Split()
	{
		// Forget it if too small to split...
		if ((int)AstSize < 10)    return;
		
		// Split into two new (smaller) asteroids
		double ratio=-1, spd=0, size=0;
		for (int i=0;  i<2;  i++)
		{
			if (ratio < 0)		// Split size 33-66%, speed +-33% from original
			{
				ratio = Math.random()*.33;
				size = AstSize * (.33+ratio);    spd = speed*(.66-ratio)*2;
			}
			else
			{
				size = AstSize * (.66-ratio);    spd = speed*(.33+ratio)*2;
			}
			AddObject(new stAsteroid(cx, cy, .25, size, spd));
		}
	}
}
