/*
* SpacePirate.cs
* Authors: August Zinsser, Adam Nabinger
* Copyright (c) 2007-2008 Cornell University
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
using System;
using Microsoft.Xna.Framework;
using TACParticleEngine.Particles;
using Random=Util.Random;
namespace MaritimeDefender
{
///
/// The enemy ships that spawn from wormholes in meteor madness Space Pirates can shoot at the player.
/// They also explode when the player shoots them enough times or they hit enough meteors.
/// Upon explosion, they drop coins that can be collected by the player.
///
class SpacePirate : UFO
{
public const int SHOT_DAMAGE = 5;
#region Fields
// Refence to the current Maritime Defender game screen
private readonly MaritimeDefender mGame;
// The effect used to visualize when the space pirate is hit
private ParticleEngine mPirateHit;
// The effect used to visualize the death of the space pirate
private ParticleEngine mPirateDeath;
// Degrees of a circle corresponding to the space pirate's ship's position
private float mArcPosition;
// Speed at which the ship can change its arcposition
private float mArcVelocity;
// The minimum base time between shots
private readonly float mCooldownTime;
// Counts down until the next shot
private float mCooldownTimer;
// The amount of time passed since last update, used for adjusting the space pirate's
// ship position for chasing after the player
private float dtx;
#endregion
#region Properties
///
/// Gets/Sets the degrees of a circle corresponding to the space pirate's ship's position
///
public float ArcPosition {
get { return mArcPosition; }
set {
mArcPosition = value;
UpdatePosition();
}
}
///
/// Gets/Sets the speed at which the ship can change its arcposition
///
public float ArcVelocity {
get { return mArcVelocity; }
set { mArcVelocity = value; }
}
#endregion
#region Creation
///
/// Constructor
///
/// The path name of the texture used to represent the space pirate
/// The width of the space pirate
/// The height of the space pirate
/// The depth of the space pirate
/// The amount of hit points the space pirate has
/// The duration of time between each shot by the space pirate
/// Reference to the current Maritime Defender game screen
public SpacePirate(string texturePath, float width, float height, float depth, int hitPoints,
float shotCooldown, MaritimeDefender game)
: base(texturePath, width, height, depth, hitPoints)
{
mGame = game;
mArcVelocity = MathHelper.PiOver4;
mCooldownTimer = 1f + shotCooldown;
mCooldownTime = shotCooldown;
LoadContent(mGame.Content);
}
#endregion
#region Management
///
/// Loads in any necessary information for all content dependent objects
///
/// Reference to the current content manager for loading in content
public override void LoadContent(Microsoft.Xna.Framework.Content.ContentManager content)
{
mPirateHit = mGame.MMParticleManager.Load("ParticleEffects/Shield");
mPirateDeath = mGame.MMParticleManager.Load("ParticleEffects/Explosion");
base.LoadContent(content);
}
///
/// Unloads and disposes of any content dependent objects
///
public override void UnloadContent()
{
mPirateDeath.ToDestory = true;
mPirateHit.ToDestory = true;
base.UnloadContent();
}
///
/// Spawns the appropriate particle effects and/or entities and destroys what needs to be
///
public override void Destroy()
{
mAlive = false;
mPirateHit.SetActive(false);
mPirateDeath.SetEnginePosition(MaritimeDefender.ConvertPosition(mPos));
mPirateDeath.SetActive(true);
mPirateDeath.ToDestory = true;
mPirateHit.ToDestory = true;
}
#endregion
#region Update
///
/// Updates the space pirate
///
/// Time that has passed in game
public override void Update(GameTime gameTime)
{
base.Update(gameTime);
dtx = (float)gameTime.ElapsedGameTime.TotalSeconds;
mCooldownTimer -= dtx;
mPirateHit.SetEnginePosition(MaritimeDefender.ConvertPosition(mPos));
}
///
/// Updates the inherited Position properties based on the arcposition
///
private void UpdatePosition()
{
Vector2 PositionFromOrigin = new Vector2((float)Math.Cos(mArcPosition), (float)Math.Sin(mArcPosition));
mArcPosition %= MathHelper.TwoPi;
mPos.X = .8F * PositionFromOrigin.X;
mPos.Y = .8F * PositionFromOrigin.Y;
mRot = mArcPosition - MathHelper.PiOver2;
}
#endregion
#region Movement
///
/// Moves the space pirate clockwise along the circumference of the Space3D cylinder
///
/// Seconds since last update
private void MoveLeft(float dt)
{
mArcPosition += mArcVelocity * dt;
UpdatePosition();
}
///
/// Moves the space pirate counterclockwise along the circumference of the Space3D cylinder
///
/// Seconds since last update
private void MoveRight(float dt)
{
mArcPosition -= mArcVelocity * dt;
UpdatePosition();
}
#endregion
#region Firing
///
/// Reset the firing cooldown
///
private void Fire()
{
mCooldownTimer = mCooldownTime;
}
#endregion
#region Collision Based Methods
///
/// Damages the player
///
/// The player entity in which the space pirate collided with
public override void CollideWithPlayer(Entity player)
{
Destroy();
mGame.ShooterShieldHit(50);
}
///
/// Deals the specified amount of damage to the space pirate, potentially killing it
///
/// The amount of damage to receive
public override void GetHit(int damage)
{
mHitPoints -= damage;
if (mHitPoints <= 0)
Destroy();
else
{
float percentLeft = (mHitPoints / 100f);
SoundManager.SoundManager.PlayEffect("Zzt");
mPirateHit.SetEngineColor(new Vector4(1 - percentLeft, 0, percentLeft, 0.5f), false);
mPirateHit.SetActive(true);
}
}
#endregion
#region React
///
/// Implements basic AI
///
/// True if the AI should fire, false if it should not
public override bool React(CheetahFighter playerShip)
{
// This should be done in Update
if (playerShip == null)
{
return false;
}
if (Math.Abs(mArcPosition - playerShip.ArcPosition) > .01)
{
if (mArcPosition < playerShip.ArcPosition)
MoveLeft(dtx);
else
MoveRight(dtx);
}
// Fire if the space pirate is lined up with the player
if (Collides2D(this, playerShip) && mCooldownTimer < 0)
{
Fire();
return true;
}
return false;
}
#endregion
}
}