/* * Friendly.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 { /// /// This represents the friendly units that pop out of wormholes in Meteor Madness. /// The opposite of space pirate. /// It has a basic AI that tells Meteor Madness when to throw a powerup to the player /// class Friendly : UFO { #region Enums /// /// Defines the types of power ups that can be given to the player /// public enum PowerUpType { /// /// Defines a weapon upgrade power up /// Weapon, /// /// Defines a resource collectable power up /// Resource }; #endregion #region Fields // Degrees of a circle corresponding to the friendly ship's position private float mArcPosition; // Speed at which the ship can change its arcposition private float mArcVelocity; // How long to wait before throwing the player a powerup private float mPowerupCooldown; // The type of powerup to award private readonly PowerUpType mPowerUp; // Holds the amount of "avoidance steering" from the main player private float mMoveAway; // How long to wait before trying to steer away from the player private float mMoveAwayTimer; // Reference to the current Maritime Defender game screen private readonly MaritimeDefender m_Game; // Particle effect for visualizing the shield for when the friendly ship is hit private ParticleEngine mFriendlyHit; // Particle effect for visualizing the explosion for when the friendly ship dies private ParticleEngine mFriendlyDeath; #endregion #region Properties /// /// Gets the power up /// public PowerUpType PowerUp { get { return mPowerUp; } } /// /// Gets/Sets the degrees of a circle corresponding to the friendly 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 /// /// Path name of the texture representing the friendly ship /// The width of the friendly ship /// The height of the friendly ship /// The layer depth of the friendly ship /// How many hitpoints before the ship is destroyed /// The type of powerup to award the player /// Accelerates the time to turn and the rate of turn by this amount /// Reference to the current Maritime Defender game screen public Friendly(string texturePath, float width, float height, float depth, int hitPoints, PowerUpType powerUp, float turnMultiplier, MaritimeDefender p_Game) : base(texturePath, width, height, depth, hitPoints) { mArcVelocity = MathHelper.TwoPi / 720f * turnMultiplier; mPowerUp = powerUp; mPowerupCooldown = 2.5f / turnMultiplier; m_Game = p_Game; LoadContent(m_Game.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) { mFriendlyHit = m_Game.MMParticleManager.Load("ParticleEffects/Shield"); mFriendlyDeath = m_Game.MMParticleManager.Load("ParticleEffects/Explosion"); base.LoadContent(content); } /// /// Unloads and disposes of any unmanaged objects /// public override void UnloadContent() { mFriendlyHit.ToDestory = true; mFriendlyDeath.ToDestory = true; base.UnloadContent(); } #endregion #region Update /// /// Updates logic and positional data for this ship /// /// Time passed in game public override void Update(GameTime gameTime) { float dt = (float)gameTime.ElapsedGameTime.TotalSeconds; mPowerupCooldown -= dt; mMoveAwayTimer -= dt; if (mMoveAwayTimer > 0) { // Start moving away from the original course mArcPosition += mMoveAway; UpdatePosition(); } mFriendlyHit.SetEnginePosition(MaritimeDefender.ConvertPosition(mPos)); base.Update(gameTime); } /// /// Updates the inherited Position properties based on the arcposition /// private void UpdatePosition() { // Get cartesian coordinates from angular position Vector2 PositionFromOrigin = new Vector2((float)Math.Cos(mArcPosition), (float)Math.Sin(mArcPosition)); // Move the ship towards the center for aesthetics mPos.X = .8F * PositionFromOrigin.X; mPos.Y = .8F * PositionFromOrigin.Y; // Cleanup variables mArcPosition %= MathHelper.TwoPi; mRot = mArcPosition - MathHelper.PiOver2; } #endregion #region Movement /// /// Steer away from the original position so the player does not have to move out of this ship's way /// private void MoveAway() { mMoveAwayTimer = 3f; mMoveAway = Random.Bool() ? (float)-mArcVelocity : (float)mArcVelocity; } /// /// Moves the ship clockwise /// /// The time that has passed since the last update private void MoveLeft(float dt) { mArcPosition += mArcVelocity * dt; UpdatePosition(); } /// /// Moves the ship counterclockwise /// /// The time that has passed since the last update private void MoveRight(float dt) { mArcPosition -= mArcVelocity * dt; UpdatePosition(); } #endregion #region Reaction /// /// Waits, throws a resource or power-up to the player, and then flies away /// /// The player ship that the friendly ship will react to /// True if the AI should throw a powerup, false if it should not public override bool React(CheetahFighter playerShip) { // Wait and then throw a power up or resource to the player if (mPowerupCooldown < 0) { ThrowPowerup(); MoveAway(); return true; } return false; } /// /// Resets the cooldown of the powerup to a very long time, ensuring that only one is thrown /// private void ThrowPowerup() { mPowerupCooldown = 1000f; } #endregion #region Ship State Modifiers /// /// Awards the appropriate resources or damages player /// /// The player that the friendly ship has collided with public override void CollideWithPlayer(Entity player) { m_Game.ShooterShieldHit(50); Destroy(); } /// /// Deals the specified amount of damage to this ship, potentially killing it /// /// Damage to be dealt to the friendly ship public override void GetHit(int damage) { mHitPoints -= damage; if (mHitPoints <= 0) { Destroy(); } else { float percentLeft = (mHitPoints / 100f); SoundManager.SoundManager.PlayEffect("Zzt"); mFriendlyHit.SetEngineColor(new Vector4(1 - percentLeft, 0, percentLeft, 0.5f), false); mFriendlyHit.SetActive(true); } } /// /// Spawns the appropriate particle effects and/or entities /// public override void Destroy() { mAlive = false; mFriendlyHit.SetActive(false); mFriendlyDeath.SetEnginePosition(MaritimeDefender.ConvertPosition(mPos)); mFriendlyDeath.SetActive(true); mFriendlyDeath.ToDestory = true; mFriendlyHit.ToDestory = true; } #endregion } }