/* * 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 } }