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