// Players.java:  Defines Ship like classes for Stoneroids...

// Classes Defined:		stShip, stAlienShip

import java.awt.*;
import java.applet.*;
import Stoneroids;   import GameActor;
import stLaser;      import stAsteroid;   import stPowerup;


// The main Ship object (derived from GameActor).  This ship is YOU!
// Status=3 is the Laser Freeze Penalty
class stShip extends GameActor
{
	int LaserPower;		// Current Laser Power		(Max: Power 6)
	int lastShot;		// "lifetime" value at previous shot
	double CoolRate;	// Rate laser temperature cools (per frame)
	int WeaponList[];	// List of additional powerups.
	boolean SubZero;	// True while ship has "SubZero Lasers" Powerup

	// Initializes object to stShip defaults
	stShip()
	{
		super();
		status = 1;    shield = 100;
		LaserPower = 1;    lastShot = 0;    CoolRate = 0.20;
		active = onscreen = movable = true;
		SubZero = false;
		cx = px = Math.random()*(screenRect.width/2)  + screenRect.width/4;
		cy = px = Math.random()*(screenRect.height/2) + screenRect.height/4;
		MakePolyShape();
		color = new Color(0, 128, 0);    solidFill = true;
		WeaponList = new int[1];    WeaponList[0] = 1;

		// Initialize the Key List for this object...
		int kl[] = { Event.UP, Event.DOWN, Event.LEFT, Event.RIGHT, 32, ',', '.' };
		KeyList = kl;
		keys = new int[KeyList.length];
	}

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

	// Customize per frame actions for ship (invincible or not)
	void Move()
	{
		super.Move();

		energy -= CoolRate;		// Decrement Laser Heat...
		if (energy < 0)    energy = 0;

		if (status > 0  &&  shield < 0)		// Ensure player dies at zero shield
		{
			SFX[sfxPlrHit].play();    Explode();
		}

		if (status == 3  &&  energy < 85)	// Laser Freeze Penalty Ends at 85%
		{
			color = new Color(0, 128, 0);    status = 1;
			SFX[sfxSiren].stop();
		}
		
		// If invincible, decrement remaining amount until time runs out
		if (invincible  &&  --ticker <= 0)
		{
			invincible = false;
			color = new Color(0, 128, 0);    solidFill = true;
			SFX[sfxBuzz].stop();		// Stop playing invulnerability sound
		}
		if (invincible)    solidFill = false;

		// If SubZero is activated, decrement until time runs out
		if (SubZero  &&  --ticker2 <= 0)
		{
			SubZero = false;    CoolRate /= 2;
			color = new Color(0, 128, 0);
			SFX[sfxBuzz].stop();		// Stop playing invulnerability sound
		}
	}
	
	// Handles the keyDown event for particular for the Ship objects...
	// Game routines determine which ships allow keyboard input.
	boolean keyDown(Event ev, int key)
	{
		int idx;

		// Check for first time key presses...
		// Continue only if this key is part of Ship's KeyList
		for (idx=0;  idx<KeyList.length;  idx++)
		{
			if (key==KeyList[idx]  &&  keys[idx]==0)    break;
			if (key==0  &&  keys[idx]>0)    keys[idx]++;
		}
		if (key > 0  &&  idx >= KeyList.length)    return true;

		// Update the status for this key...
		if (key > 0)    keys[idx]++;

		// Choose the appropriate action for this keypress...
		if (keys[0] > 0)		// [0] UP: Forward Thrust
			Thrust(0.4, 8);

		if (keys[1] > 0)		// [1] DOWN: Reverse Thrust
			Thrust(-0.4, 8);

		if (keys[2] > 0)		// [2] LEFT: Rotate Left
		{
			pAngle = angle;    angle -= Math.PI / 24;
		}

		if (keys[3] > 0)		// [3] RIGHT: Rotate Right
		{
			pAngle = angle;    angle += Math.PI / 24;
		}

		if (keys[4] > 0  &&  status != 3)	// [4] SPACE: Fire!
		{
			// Shoot laser only if laser button has just been pressed
			if (keys[4] == 1  &&  status == 1)
			{
				// Fastest firing rate is once per 3 frames.
				if (lifetime-lastShot < 3)    return true;
				// You can't shoot if 20+ of your Lasers are active.
				if (NumChildren >= 20)    return true;
				lastShot = lifetime;

				// Shot could harm you if the laser gets too hot...
				if (energy >= 85)	// Laser Temp is in the Red Zone
				{
					double chance = (energy-85)/15;
					if (Math.random() < chance)		// Freeze the lasers
					{
						energy = 100;    status = 3;    SFX[sfxSiren].loop();
						return true;
					}
				}

				// Shoot Laser(s) from your ship, along with its angle & speed...
				// LaserPower determines location and number of Lasers...
				stLaser LaserShot;
				int LPower = Math.abs(LaserPower);
				if (LPower == 1  ||  LPower > 2)
				{	// Front Laser on Powers 1, 3+ -- TriShot on Power 3+
					AddObject(new stLaser(this, 0, 10, 15));
				}
				if ((LPower > 1  &&  LPower < 5)  ||  LPower > 5)
				{	// Front Angle Lasers at Power 2-4, 6+
					AddObject(new stLaser(this, Math.PI/30f, 10, 15));
					AddObject(new stLaser(this, Math.PI/-30f, 10, 15));
				}
				if (LPower > 3)
				{	// Back Laser on Power 4+
					AddObject(new stLaser(this, Math.PI, 10, 10));
				}
				if (LPower > 4)
				{	// Side Lasers on Power 5+
					AddObject(new stLaser(this, Math.PI/2f, 10, 10));
					AddObject(new stLaser(this, Math.PI/-2f, 10, 10));
				}
				SFX[sfxShot].play();

				// Lose 5 points + some energy per shot attempt...
				if (SubZero == false)
				{	energy += 3.5+LPower/2;    ScoreVal -= 5;   }
				if (ScoreVal < 0)   ScoreVal = 0;
				if (energy > 100)   energy = 100;
			}
		}

		if (keys[5] == 1)		// [5] ",": Rotate Weapons List Left
		{
			if (WeaponList.length > 1)    LaserPower = WeaponsStack(-101);
			if (WeaponList.length > 1)    SFX[sfxSwitch].play();
		}

		if (keys[6] == 1)		// [6] ".": Rotate Weapons List Right
		{
			if (WeaponList.length > 1)    LaserPower = WeaponsStack(-102);
			if (WeaponList.length > 1)    SFX[sfxSwitch].play();
		}
		return true;
	}

	// Called when a new weapon is added to the weapon's stack.
	// 1+ push/swap # on stack.    0 pops off stack.
	// -101 rotates stack left.   -102 rotates stack right.
	// Always returns the top item of the modified stack.
	int WeaponsStack(int item)
	{
		int i, head = 0;

		if (item > 0)				// Push/Swap number onto stack...
		{
			int idx = -1;
			for (i=0;  i<WeaponList.length;  i++)
				if (Math.abs(WeaponList[i]) == item)    idx = i;
			if (idx == -1)			// "item" Not found... push it onto stack
			{
				int temp[] = new int[WeaponList.length+1];
				for (i=0;  i<WeaponList.length;  i++)    temp[i+1] = WeaponList[i];
				head = temp[0] = item;    WeaponList = temp;
			}
			else					// "item" already exists, swap it with [0]...
			{
				WeaponList[idx] = WeaponList[0];    head = WeaponList[0] = item;
			}
		}
		else if (item == 0)			// Pop top number off stack...
		{
			if (WeaponList.length == 1)    {   WeaponList[0] = 1;    return 1;   }
			int temp[] = new int[WeaponList.length-1];
			for (i=1;  i<WeaponList.length;  i++)    temp[i-1] = WeaponList[i];
			WeaponList = temp;    head = WeaponList[0];
		}
		else if (item == -101)		// Rotate stack left (put top at end)...
		{
			int temp = WeaponList[0];
			for (i=0;  i<WeaponList.length-1;  i++)    WeaponList[i] = WeaponList[i+1];
			WeaponList[WeaponList.length-1] = temp;    head = WeaponList[0];
		}
		else if (item == -102)		// Rotate stack right (put end at top)...
		{
			int temp = WeaponList[WeaponList.length-1];
			for (i=WeaponList.length-1;  i>0;  i--)    WeaponList[i] = WeaponList[i-1];
			head = WeaponList[0] = temp;
		}
		return head;
	}

	// Handles the keyUp event for Ship objects...
	boolean keyUp(Event ev, int key)
	{
		int idx;

		// Continue only if this key is part of Ship's KeyList
		for (idx=0;  idx<KeyList.length;  idx++)
			if (key == KeyList[idx])    break;
		if (idx >= KeyList.length)    return true;

		// Change status of this key to "unpressed".
		keys[idx] = 0;
		return true;
	}

	// What object classes should collide with Ships?
	boolean CanCollide(GameActor objY)
	{
		// ...Anything but my own Lasers and other Ships
		if (objY instanceof stLaser  &&  objY.pOwner instanceof stShip)    return false;
		if (objY instanceof stShip)    return false;
		return true;
	}

	// What should a Ship do if it hits something?
	void OnHit(GameActor objY)
	{
		if (!invincible  &&  objY instanceof stAsteroid)
		{
			Damage(objY);
			if (shield < 0)    Explode();
			if (!objY.invincible)    objY.Explode();
		}
		if (!invincible  &&  objY instanceof stLaser  &&  objY.pOwner != this)
		{
			Damage(objY);
			if (shield < 0)    Explode();
			if (!objY.invincible)    objY.Death();
		}
		if (objY instanceof stAlienShip  &&  !invincible  &&  !objY.invincible)
		{	Damage(objY);    objY.Damage(this);   }
		if (objY instanceof stPowerup)
		{	objY.Damage(this);    objY.Death();   }
	}

	// Damage Taken to Ship when it gets hit...
	void Damage(GameActor objY)
	{
		if (objY instanceof stAsteroid)
		{	energy += 20;    shield -= ((stAsteroid)objY).AstSize*3;   }

		if (objY instanceof stLaser)
		{
			if (objY.pOwner instanceof stShip)		// Other Player shot you
				shield -= 15;
			if (objY.pOwner instanceof stAlienShip)		// Alien shot you
				shield -= 10;
			energy += 20;
		}
		if (objY instanceof stAlienShip)
		{	energy += 20;    shield -= 15;   }

		if (objY instanceof stAsteroid  ||  objY instanceof stLaser
			||  objY instanceof stAlienShip)
		{
			invincible = true;
			ticker += 20;    if (ticker < 20)   ticker = 20;
			if (LaserPower != 1)
			{
				if (LaserPower > 0)		// Damage weapon when hit
				{	LaserPower = WeaponList[0] *= -1;   }
				else					// Lose weapon if hit when damaged
				{	WeaponsStack(0);    LaserPower = WeaponList[0];   }
			}
			if (energy > 100)
			{	energy = 100;    status = 3;    SFX[sfxSiren].loop();   }
			SFX[sfxPlrHit].play();    SFX[sfxBuzz].loop();
		}
	}

	// Customize explosion for ship by dumping all powerups on death...
	void Explode()
	{
		double speed0=speed, angle0=angle;	// Remember current speed & angle...

		// Dump each of the remaining weapon powerups...
		for (int i=0;  i<WeaponList.length;  i++)
		{
			angle = Math.random()*2*Math.PI;
			speed = speed0 * (.4+Math.random()*.4);		// 40-80% of orig speed
			AddObject(new stPowerup(this, WeaponList[i], 150));
		}
		// Dump 1 Shield and 1 Energy powerups...
		for (int i=0;  i<2;  i++)
		{
			angle = Math.random()*2*Math.PI;
			speed = speed0 * (.4+Math.random()*.4);		// 40-80% of orig speed
			AddObject(new stPowerup(this, i+6, 150));
		}
		speed = speed0;    angle = angle0;		// Restore current speed & angle
		SFX[sfxBuzz].stop();    SFX[sfxSiren].stop();
		super.Explode();		// We now return you to our scheduled programming
	}

	// Special version to paint special abilities...
	void paint(Graphics g)
	{
		if (SubZero  &&  status != 3)
		{
			solidFill = true;
			color = new Color((200-((ticker2*6)%140)), 0, 50+((ticker2*6)%140));
			if (invincible)    super.paint(g);
		}
		if (invincible  &&  status == 3)
		{
			solidFill = true;    color = Color.red.darker();
			super.paint(g);
			solidFill = false;
		}
		if (status == 3)
			color = Color.red.darker();

		if (invincible)
		{
			solidFill = false;
			color = new Color(160, 60+((ticker*6)%180), 60);
		}
		super.paint(g);
	}
}



//////////////////////////////////////////////////////////////////////
// The AlienShip object.  Better watch out for these guys!
class stAlienShip extends GameActor
{
	int lastShot;			// "lifetime" value at previous shot
	int nextShot;			// Min time before next shot
	double angleSpeed;		// Angular Rotation
	double maxAngSpd;		// Max Angle Speed
	double angleErr;		// Amount of aiming error for next shot
	double TargetAngle;		// Angle to target...
	double delAngle;		// Delta Angle...
	double thrust;			// Ship's current thrust
	GameActor target;		// Target object this alien will shoot at
	AudioClip mySFX;		// Individually controlled SFX for each alien
	double tAngle;			// Angle to target
	int TargIdx, numFails;	// Array Index for target...
	String szItemList;		// List of Powerups picked up by this Alien

	// Initializes object to stAlienShip defaults
	stAlienShip()
	{
		super();
		status = 1;    shield = 100;    lastShot = 0;
		active = onscreen = movable = true;
		ScoreVal = 50 * thisApp.level;
		thrust = 0.5;
		szItemList = "";
		nextShot = (int)(20+Math.random()*30);		// min 20-50 frames b/t shots...
		angle = Math.random()*2*Math.PI;
		maxAngSpd = (5+Math.random()) * Math.PI/180;	// Rotates 5-6 deg/frame
		angleSpeed = maxAngSpd;
		angleErr = (10-Math.random()*20) * Math.PI/180;	// Error of +- 10 degrees
		cx = px = Math.random()*(screenRect.width/2)  + screenRect.width/4;
		cy = px = Math.random()*(screenRect.height/2) + screenRect.height/4;

		// Make Asteroid emerge from T/B or L/R edge of screen...
		double r = Math.random();
		if      (r < .25)  cy = py = -50;					// from Top
		else if (r < .50)  cy = py = screenRect.height+50;	// from Bottom
		else if (r < .75)  cx = px = -50;					// from Left
		else               cx = px = screenRect.width+50;	// from Right

		MakePolyShape();    solidFill = true;
		color = new Color((int)(70+Math.random()*120), 
			(int)(70+Math.random()*120), (int)(70+Math.random()*120));
		TargIdx = -1;
		target = NewTarget();    TargetAngle = delAngle = numFails = 0;

		invincible = true;   ticker = 40;	// Start with 40 invulnerability ticks

		// Energy for AlienShips relates to LaserPower
		// 50% Level 1  -  40% Level 2  -  10% Level 3
		energy = 1;
		if (thisApp.level > 1  &&  Math.random() > .5)    energy = 2;
		if (thisApp.level > 2  &&  Math.random() > .9)    energy = 3;
	}

	// Initialize the initial shape and bounding box for AlienShip objects.
	void MakePolyShape()
	{
		int p[][] = { {0,9}, {3,6}, {4,1}, {4,-4},   {6,-4}, {8,2}, {10,-4}, 
			{8,-7}, {4,-7}, {-4,-7}, {-8,-7},
			{-10,-4}, {-8,2}, {-6,-4},    {-4,-4}, {-4,1}, {-3,6}, {0,9} };

		poly = new Polygon();
		for (int i=0;  i<p.length;  i++)    poly.addPoint(p[i][0], p[i][1]);
		bbox = poly.getBoundingBox();
		polyO = new Polygon(poly.xpoints, poly.ypoints, poly.npoints);
	}

	// Tries to Find a new target for the alien to chase after...
	GameActor NewTarget()
	{
		GameActor targ = null;
		int idx=0;

		// Force to target first object if it can't find one randomly...
		if (numFails > 5)
		{
			numFails = 0;
			for (int i=0;  i<thisApp.NumObjects;  i++)
				if (objList[i].active
					&& (objList[i] instanceof stAsteroid || objList[i] instanceof stShip))
				{	targ = objList[i];    break;   }
		}
		else
		{
			if (Math.random() < .25)	// 25% chance it will target YOU...
			{
				for (int i=0;  i<thisApp.NumObjects;  i++)
					if (objList[i].active  &&  objList[i] instanceof stShip)
					{	targ = objList[i];    break;   }
			}
			else						// Else try to target a random object...
			{
				TargIdx = idx = (int)(Math.random() * thisApp.NumObjects);
				targ = objList[idx];
				if (targ != null  &&  targ.active
					&& (targ instanceof stAsteroid  ||  targ instanceof stShip))
					numFails = 0;
				else
				{	numFails++;    targ = null;   }
			}
		}
		return targ;
	}

	// Updates Alien stats to improve ship's aim at target...
	double TargetAim(GameActor targ)
	{
		// Simple Brain.  Rotate ship towards the target...
		double ang0 = angle;		// Ship's current angle
									// Angle of Ship-to-Target Vector
		TargetAngle = Math.atan2(cx-targ.cx, targ.cy-cy) - 3*Math.PI/2 + angleErr;
		double dAng = ang0 - TargetAngle;			// Diff b/t Angles

		if (dAng >  Math.PI)    dAng -= 2*Math.PI;		// Within -PI to +PI
		if (dAng < -Math.PI)    dAng += 2*Math.PI;

		// If "dAng" is negative, then move left, otherwise move right...
		if (dAng > 0)    angleSpeed = -Math.abs(maxAngSpd);
		else             angleSpeed = Math.abs(maxAngSpd);

		// If angleSpeed will pass target, then match angle to target angle
		if ((dAng >= 0  &&  dAng+angleSpeed < 0)  ||  (dAng < 0  &&  dAng+angleSpeed > 0))
			angleSpeed = -dAng;

		return dAng;
	}

	// Fires the ship's lasers...
	void Shoot()
	{
		lastShot = lifetime;
		nextShot = lifetime + (int)(20+Math.random()*30);
		if (status <= 0)    return;					// Can't shoot if dying or dead.
		angleErr = (10-Math.random()*20) * Math.PI/180;	// Error of +- 10 degrees
		double tempX=cx, tempY=cy;
		int PolyIdx[] = {5, 0, 12};				// Laser turrets at [5] [0] & [12]
		for (int i=0;  i<PolyIdx.length;  i++)
		{
			int x=0, y=0;
			if ( (i==1 && energy!=2)  ||  (i!=1 && energy>1) )
			{	x = PolyIdx[i];    y = PolyIdx[i];   }
			else    continue;

			stLaser newLaser = new stLaser(this, 0, 8, 12);
			newLaser.color = new Color(color.getRGB());
			newLaser.cx = poly.xpoints[x];   newLaser.cy = poly.ypoints[y];
			newLaser.MakePolyShape(3, 9);    newLaser.RotatePoly();
			AddObject(newLaser);
		}
		cx = tempX;    cy = tempY;
	}

	// Provides Alien's only defense...  Returns true if it should shoot...
	// Targets Powerups or your Ship if nearby...
	// Shoots at Asteroids or Ships if nearby and in front...
	boolean Defense()
	{
		// Fastest firing rate is 1 in 15 frames...
		if (lifetime < lastShot+15)    return false;

		// For each asteroid, make sure it's nearby and in front
		for (int i=0;  i<thisApp.NumObjects; i++)
		{
			if (objList[i].active == false)          continue;
			if (objList[i] instanceof stLaser)       continue;
			if (objList[i] instanceof stAlienShip)   continue;

			// "Nearby" means origins are within 60 pixels...
			double ddx = cx-objList[i].cx,  ddy = cy-objList[i].cy;
//			double dist = Math.sqrt(ddx*ddx + ddy*ddy);
//			if (dist < 50)
			if (Math.abs(ddx)<60  &&  Math.abs(ddy)<60)
			{
				if (objList[i] instanceof stPowerup)
				{   target = objList[i];    return false;   }
				if (objList[i] instanceof stShip)
					target = objList[i];

				// Shoot if object is in front within 15 degrees...
				double pTang=TargetAngle,  pAspd=angleSpeed;
				double dAng = TargetAim(objList[i]);
				TargetAngle = pTang;    angleSpeed = pAspd;
				if (Math.abs(dAng) < 15*Math.PI/180)    return true;
			}
		}
		return false;
	}

	// Moves AlienShip (and angular velocity)...
	void Move()
	{
		if (status > 0  &&  shield < 0)		// Ensure ship dies at zero shield
			Explode();

		if (active == true  &&  status > 0)
		{
			// Find a new target if the old one is gone...
			if (target == null  &&  (lifetime&3) == 2)    target = NewTarget();
			if (target != null  &&  target.active == false)    target = null;

			thrust = 0.3-(Math.random()*0.4);		// Thrust range -.1 to +.3
			if ((lifetime&3) == 0  &&  Defense() == true)    Shoot();
			if (target != null  &&  target.active)
			{
				/*if ((lifetime&1) == 1)*/    delAngle = TargetAim(target);

				// Shoot if ship is within 2 degrees of TargetAngle
				if (!invincible  &&  lifetime >= nextShot
					&&  Math.abs(delAngle) < 1.5*Math.PI/180
					&&  !(target instanceof stPowerup))
					Shoot();
			}

			// If invincible, decrement remaining amount until time runs out
			if (invincible  &&  --ticker <= 0)
			{
				invincible = false;    solidFill = true;
			}
			if (invincible)    solidFill = false;
		}

		Thrust(thrust, 2.5);
		angle += angleSpeed;			// Rotate Powerup...
		super.Move();					// ...Then move it
	}

	// What object classes should collide with AlienShips?
	boolean CanCollide(GameActor objY)
	{
		// ...Everything but your own Lasers.
		if (objY instanceof stLaser  &&  objY.pOwner != this)    return true;
		if (objY instanceof stPowerup)    return true;
		if (objY instanceof stAsteroid)   return true;
		if (objY instanceof stAlienShip)  return true;
		if (objY instanceof stShip)       return true;
		return false;
	}

	// What should an AlienShip do if it hits something?
	void OnHit(GameActor objY)
	{
		if (!invincible  &&  objY instanceof stLaser)
		{
			Damage(objY);
			// Alien gets pissed off after it's shot at. Now it wants revenge!
			if (objY.pOwner.active)    target = objY.pOwner;
			// Two Aliens can't target each other... (Circle Jerks)
			if (target instanceof stAlienShip  &&  ((stAlienShip)target).target == this)
			{	((stAlienShip)target).target = null;    target = null;   }

			if (shield < 0)
			{	
				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;
				Explode();
			}
			objY.Death();
		}
		if (objY instanceof stPowerup)
		{	objY.Damage(this);    objY.Death();   }

		if (!invincible  &&  objY instanceof stAsteroid)
		{	Damage(objY);    objY.Explode();   }

		if (!invincible  &&  !objY.invincible
			&&  (objY instanceof stAlienShip  ||  objY instanceof stShip))
		{	Damage(objY);    objY.Damage(this);   }
	}

	// Damage Taken to AlienShip when it gets hit...
	void Damage(GameActor objY)
	{
		SFX[sfxAlHit].play();
		invincible=true;
		if (objY instanceof stLaser)
		{	ticker+=7;    if (ticker < 7)   ticker=7;   }
		else
		{	ticker+=15;    if (ticker < 15)   ticker=15;   }

//		thisApp.showStatus("Ast Hits: " + thisApp.TargetsHit
//			+"   Next: " + thisApp.NextAlien
//			+"   List: " + thisApp.szAlienList);

		if (objY instanceof stLaser  &&  objY.active)
		{
			if (objY.pOwner instanceof stAlienShip)		// Laser from Alien gets 5 pts
			{	shield -= 20.1;    objY.pOwner.ScoreVal += 5;   }
			if (objY.pOwner instanceof stShip)			// Laser from Ship gets 10 pts
			{	shield -= 33.4;    objY.pOwner.ScoreVal += 10;   }
		}
		if (objY instanceof stAsteroid)    shield -= ((stAsteroid)objY).AstSize * 1.5;
		if (objY instanceof stAlienShip)   shield -= 10;
		if (objY instanceof stShip)        shield -= 15;
	}

	// Customize explosion for AlienShip by dumping any powerups picked up...
	void Explode()
	{
		char cItemList[] = szItemList.toCharArray();
		double speed0=speed, angle0=angle;	// Remember current speed & angle...

		// Dump any picked up powerups...
		for (int i=0;  i<cItemList.length;  i++)
		{
			angle = Math.random()*2*Math.PI;
			speed = speed0 * (.4+Math.random()*.4);		// 40-80% of orig speed
			AddObject(new stPowerup(this, cItemList[i]-'0', 100));
		}
		speed = speed0;    angle = angle0;		// Restore current speed & angle
		super.Explode();		// We now return you to our scheduled programming
	}

	// Special version to paint AlienShip's cockpit window...
	void paint(Graphics g)
	{
		super.paint(g);
		if (status > 0)
		{
			// (Debug) Paint Target's bbox and a Ship-Target aim indicator...
//			if (target != null)
//			{
//				g.drawRect(target.bbox.x, target.bbox.y, target.bbox.width, target.bbox.height);
//				double x2 = 20*Math.cos(TargetAngle-Math.PI);
//				double y2 = 20*Math.sin(TargetAngle-Math.PI);
//				g.drawLine((int)cx, (int)cy, (int)(cx-x2), (int)(cy-y2));
//			}

			// Cockpit color relates to Alien's laser power...
			if (energy == 1)       g.setColor(Color.black);
			else if (energy == 2)  g.setColor(Color.green.darker());
			else                   g.setColor(Color.orange.darker());
			g.fillOval((int)(cx-2), (int)(cy-2), 4, 4);
		}
	}
}