gt: 				float hitVecX = x - other.x;
context: package au.com.f1n.spaceinator.game;
  
  import au.com.f1n.spaceinator.GBSoundManager;
  import au.com.f1n.spaceinator.R;
  import au.com.f1n.spaceinator.Util;
  import au.com.f1n.spaceinator.game.enemy.PEnemy;
  import au.com.f1n.spaceinator.game.logic.GameState;
  
  /**
   * Spaceship object in the world.
   * 
   * This requires a lot more information than any spaceship to give to the user.
   * Enemy spaceships are a lot simpler.
   * 
   * @author luke
   */
  public class PSpaceShip extends PObject {
  	/**
  	 * 
  	 */
  	private static final long serialVersionUID = 1L;
  	public static final float SHIELD_SIZE = 230;
  	public static final int BASE_SHIELD = 100;
  	public static final int BASE_POWER = 200;
  	private static final int PLANET_SHIELD_DAMAGE = 20;
  	private static final float DRAG = 0.01f;
  	private static final float ANGLE_ROT_SPEED = 0.006f;
  	private static final float ANGLE_ERROR = 0.1f;
  	public static final float[][] LASER_OFFSETS = { { -97, -81, 5.6f }, { -97, 81, 5.6f }, { 8, 0, 5.5f }, { 75, 0, 4 } };
  	public static final float[][] TURRET_OFFSETS = { { -28, -83.5f, 0 }, { -28, 83.5f, 0 }, { -100, -110, 0 }, { -100, +110, 0 } };
  	public static final long POWER_TIME = 5000;
  	public static final int DRAW_ORDER = -1;
  
  	/**
  	 * Desired acceleration angle in radians
  	 */
  	private float accelAngle;
  	public float facingAngle;
  	public float accelX;
  	public float accelY;
  	private int lastHit = 0;
  	public boolean shooting;
  	public float shootAngle;
  	private WeaponShipLaser curWeapon;
  	private int maxShield;
  	public int curShield;
  
  	private long lastShieldStep;
  	private long shieldRate = 200;
  
  	public boolean accelerating;
  	private int rotatingProp;
  	PShipParticles shipParticles;
  	private PShipParticlesTop shipParticlesTop;
  	private World world;
  	public float dx;
  	public float dy;
  	public float rotX = 0;
  	/**
  	 * Set this to true for warp-like levels
  	 */
  	public boolean facingIn = false;
  	float accel = 0;
  	private int laserCount;
  	private int turretCount;
  	private WeaponShipTurret[] turrets;
  	private transient GBSoundManager soundManager;
  	private float shieldAlpha;
  	private boolean accelOn;
  	public float power;
  	public long lastPower;
  	public boolean powerDown;
  	private boolean worm;
  	private int planetHit;
  
  	public PSpaceShip(World world, float x, float y, float dx, float dy) {
  		super(x, y, SHIELD_SIZE);
  		this.world = world;
  		this.dx = dx;
  		this.dy = dy;
  		drawOrder = DRAW_ORDER;
  
  		GameState gameState = world.getGameState();
  
  		int[] upgrades = gameState.getShipUpgrades();
  
  		laserCount = upgrades[GameState.UPGRADE_LASER_COUNT] + 1;
  		turretCount = upgrades[GameState.UPGRADE_TURRET];
  		soundManager = world.gbRenderer.getSoundManager();
  
  		accel = 0.0002f + upgrades[GameState.UPGRADE_THRUSTER] * 0.0001f;
  		// Add thruster trail
  		shipParticles = new PShipParticles(this, upgrades[GameState.UPGRADE_THRUSTER]);
  		world.graphicEffect(shipParticles);
  
  		shipParticlesTop = new PShipParticlesTop(this, 100);
  
  		// Make all weapons
  		curWeapon = new WeaponShipLaser(world, laserCount, upgrades[GameState.UPGRADE_LASER_POWER], soundManager, shipParticlesTop, this);
  		turrets = new WeaponShipTurret[turretCount];
  		for (int i = 0; i < turretCount; i++)
  			turrets[i] = new WeaponShipTurret(world, i, soundManager, shipParticlesTop, upgrades[GameState.UPGRADE_TURRET_POWER],
  					upgrades[GameState.UPGRADE_TURRET_RATE], upgrades[GameState.UPGRADE_TURRET_SPREAD]);
  
  		// setup ship shield
  		maxShield = BASE_SHIELD + gameState.getShipUpgrades()[GameState.UPGRADE_SHIELD] * BASE_SHIELD / 2;
  		curShield = maxShield;
  	}
  
  	/**
  	 * Calculate how gravity of all solar bodies accelerates this space ship and
  	 * move it.
  	 */
  	@Override
  	public boolean timeStep(int dTime, long timeS) {
  		// top particle is a special type of particle
  		shipParticlesTop.timeStep(dTime, timeS);
  
  		if (world.zooming > 0) {
  			soundManager.setShip(false);
  			return false;
  		}
  
  		// Deal with power
  		if (timeS - lastPower > POWER_TIME && power > 0) {
  			power -= 1f;
  			powerDown = true;
  		} else if (timeS - lastPower > POWER_TIME && power == -1) {
  			power = 0;
  		}
  
  		float dxOld = dx;
  		float dyOld = dy;
  
  		// Recharge shield
  		shieldRate = 200;
  
  		if (curShield < maxShield && timeS - lastShieldStep >= shieldRate) {
  			curShield++;
  			lastShieldStep = timeS;
  		}
  
  		if (worm) {
  			accelerating = false;
  		} else {
  			// Calculate gravity force (change in dx and dy)
  			for (PPlanet planet : world.getPlanets()) {
  				float distX = planet.x - x;
  				float distY = planet.y - y;
  				float dist2 = distX * distX + distY * distY;
  
  				// F = ma, thus a = F / m (and below is std gravity divided by
  				// this.mass)
  				float accel = World.G * planet.mass / dist2;
  
  				// Normalise vector
  				dist2 = Util.invSqrt(dist2);
  				distX *= dist2 * accel;
  				distY *= dist2 * accel;
  
  				dx += distX;
  				dy += distY;
  			}
  
  			// Rotate ship
  			accelerating = accelOn;
  			if (accelerating && Math.abs(accelAngle - facingAngle) > ANGLE_ERROR) {
  				// How do we rotate? accelAngle is between -pi and pi (comes from
  				// atan2)
  				if (Math.abs(accelAngle - facingAngle) < Math.PI) {
  					// No brainer, simple rotation
  					boolean rotatingLeft = facingAngle < accelAngle;
  					facingAngle += (rotatingLeft ? ANGLE_ROT_SPEED : -ANGLE_ROT_SPEED) * (float) dTime;
  				} else {
  					// Greater than 180 degrees difference
  					boolean rotatingLeft = facingAngle > accelAngle;
  					facingAngle += (rotatingLeft ? ANGLE_ROT_SPEED : -ANGLE_ROT_SPEED) * (float) dTime;
  					if (facingAngle < -Math.PI)
  						facingAngle += Math.PI * 2;
  					if (facingAngle > Math.PI)
  						facingAngle -= Math.PI * 2;
  				}
  
  				accelerating = false;
  				// Also reset turrets
  				for (int i = 0; i < turretCount; i++)
  					turrets[i].resetAngle();
  			} else {
  				facingAngle = accelAngle;
  			}
  
  			if (facingIn) {
  				shootAngle = Util.PI / 2;
  				// Force turrets to be the same
  				for (int i = 0; i < turretCount; i++)
  					turrets[i].facingInAngle();
  			}
  
  			soundManager.setShip(accelerating);
  
  			// Check helio collision - special case of collision detection
  			if (world.zooming == 0) {
  				world.boundry.collideTest(this, soundManager);
  
  				if (curWeapon != null && shooting) {
  					// Fire weapon (let the weapon decide if it can fire this
  					// instant)
  					curWeapon.shooting(timeS, shootAngle, dx, dy);
  				}
  
  				for (int i = 0; i < turretCount; i++)
  					turrets[i].shooting(timeS, 0, dx, dy);
  
  				if (accelerating) {
  					dx += accelX * accel * dTime;
  					dy += accelY * accel * dTime;
  				}
  			}
  
  			if (curShield <= 0) {
  				soundManager.explode();
  				soundManager.stopShip();
  			}
  
  			// Dampner - velocity squared resistence!
  			dx -= Math.signum(dx) * DRAG * dx * dx;
  			dy -= Math.signum(dy) * DRAG * dy * dy;
  
  			x += (dx + dxOld) * dTime / 2f;
  			y += (dy + dyOld) * dTime / 2f;
  
  			if (lastHit > 0)
  				lastHit--;
  		}
  		top = y + radius;
  		bottom = y - radius;
  
  		return curShield <= 0;
  	}
  
  	public void setAccel(float x, float y, float angle) {
  		accelOn = true;
  		accelX = x;
  		accelY = y;
  		accelAngle = angle;
  	}
  
  	public float getFacingAngle() {
  		return facingAngle;
  	}
  
  	public boolean isAccelOn() {
  		return accelOn;
  	}
  
  	public void shootAt(float angle) {
  		if (curWeapon != null) {
  			shooting = true;
  			shootAngle = angle;
  		}
  	}
  
  	public float getAccelX() {
  		return accelX;
  	}
  
  	public float getAccelY() {
  		return accelY;
  	}
  
  	// The absolute highest this can return is 255 - 20 = 235
  	public int getCurShield() {
  		return curShield;
  	}
  
  	public float getShieldAlpha() {
  		return shieldAlpha;
  	}
  
  	public boolean isAccelerating() {
  		return accelerating && world.zooming <= 0;
  	}
  
  	public int getRotatingPropulsion() {
  		if (rotatingProp > 0) {
  			rotatingProp--;
  			return 1;
  		} else if (rotatingProp < 0) {
  			rotatingProp++;
  			return -1;
  		}
  		return 0;
  	}
  
  	public boolean isShooting() {
  		return shooting;
  	}
  
  	@Override
  	public void damage(int dmg, long timeS, float dx, float dy, boolean laser) {
  		if (dmg <= 0)
  			return;
  
  		// make it easier...
  		if (dmg > 1)
  			dmg /= 2;
  
  		world.hitShip(dmg, dx, dy);
  
  		if (curShield > 25 && curShield - dmg < 25)
  			soundManager.alarm();
  
  		curShield -= dmg;
  		if (laser)
  			soundManager.scratch();
  		else
  			soundManager.hit();
  	}
  
  	@Override
  	public void checkCollision(PObject other) {
  		if (world.zooming != 0 || z < -.001)
  			// When we are zooming, there is no collision with the spaceship...
  			return;
  
  		if (other instanceof PPlanet) {
  			if (lastHit == 0 && isIn(other)) {
  				// Accelerate violently away from the planet - destroying part of
  				// the shield
  