/*
* CheetahFighter.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 System.Collections.Generic;
using Microsoft.Xna.Framework;
using TACParticleEngine.Particles;
namespace MaritimeDefender
{
///
/// This class represents the player's ship in the meteor madness game.
/// It can move according the rules of meteor madness, and also informs MM where to draw the ship and where to draw its projectiles
///
public class CheetahFighter : Entity
{
#region Constants
// Rate at which the firing delay decreases by.
private const float SHOT_DELAY_DECREASE = .95f;
// Amount of damage increase to fired torpedos every level
private const float DAMAGE_MODIFIER = 1f;
///
/// Rate at which the shield recharges. 1 = 100%
///
public const float SHIELD_RECHARGE_RATE = .02f;
///
/// Base damage of the fired torpedo
///
public const int SHOT_DAMAGE = 10;
///
/// How fast the shield recharges its recharge rate in seconds
///
public const float HEALTH_TIME = 5f;
#endregion
#region Fields
// Checks if engine has already been set after visibilty was changed
private bool mSetChecker;
// The number of weapon upgrades collected
private static int mCollectedUpgrades = 1;
// Degrees of a circle corresponding to the player's ship's position
private float mArcPosition;
// Speed at which the ship can change its arcposition
private float mArcVelocity;
// The current cooldown for the player's lasers in the shooter phase of meteor madness
private static float mWeaponCooldown = .25f;
// Distance from the center of the image to each firing point (in relation to width and height)
private readonly List mWeaponOffsets;
// An index of which of the 4 weapon locations to fire next
private int mFireNext;
// Visually roll the ship as it turns
private float mRoll;
// Speed at which the ship rolls
private readonly float mRollVelocity;
// Max amount to roll the ship
private readonly float mRollMax;
// Offset to draw the flare
private Vector2 mEngineOffset;
// Size of this entity in space3D coordinates
private Vector3 mSpace3DSize;
// Reference to the current Maritime Defender game screen
private readonly MaritimeDefender m_Game;
// Particle effect for the engine of the cheetah ship
private ParticleEngine mCheetahEngine;
// Particle effect for shield visualization for when the cheetah ship is hit
private ParticleEngine mCheetahHit;
// Particle effect for when the cheeth ship explodes at death
private ParticleEngine mCheetahDeath;
#endregion
#region Properties
///
/// Gets/Sets the number of weapon upgrades collected
///
public static int CollectedUpgrades
{
get { return mCollectedUpgrades; }
set { mCollectedUpgrades = value; }
}
///
/// Gets/Sets the degrees of a circle corresponding to the player's ship's position
///
public float ArcPosition {
get { return mArcPosition; }
set { mArcPosition = value; }
}
///
/// Gets/Sets the speed at which the ship can change its arcposition
///
public float ArcVelocity {
get { return mArcVelocity; }
set { mArcVelocity = value; }
}
///
/// Gets/Sets the current cooldown for the player's lasers in the shooter phase of meteor madness
///
public float WeaponCooldown
{
get { return mWeaponCooldown; }
set { mWeaponCooldown = value; }
}
///
/// Gets/Sets the width of the cheetah ship
///
public override float Width {
get { return mSpace3DSize.X; }
set { mSpace3DSize.X = value; }
}
///
/// Gets/Sets the height of the cheetah ship
///
public override float Height {
get { return mSpace3DSize.Y; }
set { mSpace3DSize.Y = value; }
}
///
/// Gets/Sets the depth of the cheetah ship
///
public override float Depth {
get { return mSpace3DSize.Z; }
set { mSpace3DSize.Z = value; }
}
///
/// Gets the 3-dimensional size of the cheetah ship
///
public override Vector3 Size { get { return mSpace3DSize; } }
#endregion
#region Creation
///
/// Constructor
///
/// The path name of the texture to use for the ship
/// The width of the ship
/// In height of the ship
/// In depth of the ship
/// Reference to the current Maritime Defender game screen
public CheetahFighter(string spriteName, float width, float height, float depth, MaritimeDefender game)
: base(spriteName)
{
mAlive = true;
m_Game = game;
mSpace3DSize = new Vector3(width, height, depth);
mArcPosition = MathHelper.PiOver2;
mArcVelocity = MathHelper.Pi * (5f/6f);
mSize.Z = depth;
mPos.Z = depth;
mRollMax = MathHelper.PiOver4;
mRollVelocity = mRollMax;
mWeaponOffsets = new List();
mWeaponOffsets.Add(new Vector2(.5f, -.8f));
mWeaponOffsets.Add(new Vector2(-.9f, .1f));
mWeaponOffsets.Add(new Vector2(.9f, .1f));
mWeaponOffsets.Add(new Vector2(-.5f, -.8f));
mEngineOffset = new Vector2(0f, 100f * mSpace3DSize.Y);
LoadContent(m_Game.Content);
UpdatePosition();
}
#endregion
#region Management
///
/// Loads in any necessary information for all content dependent objects
///
/// Reference to the current content manager for loading content
public override void LoadContent(Microsoft.Xna.Framework.Content.ContentManager content)
{
mCheetahHit = m_Game.MMParticleManager.Load("ParticleEffects/Shield");
mCheetahDeath = m_Game.MMParticleManager.Load("ParticleEffects/Explosion");
mCheetahEngine = m_Game.MMParticleManager.Load("ParticleEffects/Engine");
base.LoadContent(content);
}
///
/// Unloads and cleans up any objects left over
///
public override void UnloadContent()
{
mCheetahHit.ToDestory = true;
mCheetahDeath.ToDestory = true;
mCheetahEngine.ToDestory = true;
mCheetahEngine.SetActive(false);
base.UnloadContent();
}
#endregion
#region Update
///
/// Updates game logic
///
/// Time that has passed in game
public override void Update(GameTime gameTime)
{
float dT = (float)gameTime.ElapsedGameTime.TotalSeconds;
UpdatePosition();
if (mVisible != mSetChecker)
{
mCheetahEngine.SetActive(mVisible);
mSetChecker = mVisible;
}
base.Update(gameTime);
// Return roll to neutral
if (mRoll > 0)
mRoll *= 0.8f;
else if (mRoll < 0)
mRoll *= 0.8f;
if (Math.Abs(mRoll) < mRollMax * 0.1f)
mRoll = 0f;
}
///
/// Updates the inherited Position properties based on the arcposition
///
private void UpdatePosition()
{
if (!IsLerping)
{
// Get its position based its angle on the circle
Vector2 PositionFromOrigin = new Vector2((float)Math.Cos(mArcPosition), (float)Math.Sin(mArcPosition));
// Move the ship away from the edge of the screen for aesthetics
mPos.X = .8F * PositionFromOrigin.X;
mPos.Y = .8F * PositionFromOrigin.Y;
// Cleanup variables
mArcPosition %= MathHelper.TwoPi;
mRot = mArcPosition - MathHelper.PiOver2;
if (mRoll != 0f)
{
mRot += mRoll;
}
}
mCheetahEngine.SetEnginePosition(MaritimeDefender.ConvertPosition(mPos));
mCheetahHit.SetEnginePosition(MaritimeDefender.ConvertPosition(mPos));
}
///
/// Moves to the given arc position over the specified interval
///
/// The new position to set the ship to
/// The duration of time in which the ship will roll into place
public void Lerp(float newArcPosition, float duration)
{
mArcPosition = newArcPosition;
// Get the new position based its angle on the circle
Vector2 PositionFromOrigin = new Vector2((float)Math.Cos(mArcPosition), (float)Math.Sin(mArcPosition));
// Move the ship away from the edge of the screen for aesthetics
Vector3 newPos = new Vector3(
newPos.X = .8F * PositionFromOrigin.X,
newPos.Y = .8F * PositionFromOrigin.Y,
mPos.Z);
Lerp(newPos, mSize, (float)(mRot - mRoll), duration);
}
#endregion
#region Movement
///
/// Moves the ship clockwise on the circle that it is allowed to move on
///
/// Time that has passed since the last update
public void MoveRight(float dt)
{
mArcPosition -= mArcVelocity * dt;
mRoll = mRollMax;
}
///
/// Moves the ship counterclockwise on the circle
///
/// Time that has passed since the last update
public void MoveLeft(float dt)
{
mArcPosition += mArcVelocity * dt;
mRoll = -mRollMax;
}
#endregion
#region Getters
///
/// Returns the x and y screen location of the next spawn point for a projectile
///
/// The x and y screen location of the next spawn point for a projectile
public Vector2 GetNextFiringLocation()
{
// Get the offset based on width, and then rotate it with the ship
float offX = mWeaponOffsets[mFireNext].X * mSpace3DSize.X;
float offY = mWeaponOffsets[mFireNext].Y * mSpace3DSize.Y;
float retX = mPos.X + (float)Math.Cos(mRot) * offX - (float)Math.Sin(mRot) * offY;
float retY = mPos.Y + (float)Math.Sin(mRot) * offX + (float)Math.Cos(mRot) * offY;
if (++mFireNext >= mWeaponOffsets.Count)
{
mFireNext = 0;
}
return new Vector2(retX, retY);
}
#endregion
#region Effect Deactivation
///
/// Removes the engine flare from the particle engine
///
public void KillEngineFlare()
{
mCheetahEngine.SetActive(false);
}
///
/// Activates the engine flare from the particle engine
///
public void ActivateEngineFlare()
{
mCheetahEngine.SetActive(true);
}
#endregion
#region Player State Modifier
///
/// Fires a photon torpedo from one of the 4 lasers on the player's ship
///
/// Reference to the fired torpedo
public PhotonTorpedo FireTorpedo()
{
PhotonTorpedo retTorpedo = new PhotonTorpedo(
true, true, mCollectedUpgrades,
new Vector3(GetNextFiringLocation(), 0f),
Width * .5f, Width * .5f, Width * .5f,
5f, .01f, 15f, m_Game);
retTorpedo.Friendly = true;
retTorpedo.Damage = SHOT_DAMAGE + (int)(DAMAGE_MODIFIER * mCollectedUpgrades);
return retTorpedo;
}
///
/// Upgrades the player's weapon after collecting a weapon upgrade
///
public void UpgradeWeapon()
{
mCollectedUpgrades++;
mWeaponCooldown *= SHOT_DELAY_DECREASE;
}
///
/// Displays the appropriate particle effects
///
public void GetHit()
{
// Indicate the strength of the remaining shields through color and opacity of a particle effect
float percentLeft = m_Game.DotShields;
if (percentLeft >= 0)
{
SoundManager.SoundManager.PlayEffect("Zzt");
mCheetahHit.SetEngineColor(new Vector4(1 - percentLeft, 0, percentLeft, 0.5f), false);
mCheetahHit.SetActive(true);
}
}
///
/// Updates appropriate variables and spawns an explosion at the player's previous location
///
public void DestroyPlayer()
{
SoundManager.SoundManager.PlayEffect("Smash");
mCheetahHit.SetActive(false);
mCheetahEngine.SetActive(false);
mCheetahDeath.SetEnginePosition(MaritimeDefender.ConvertPosition(mPos));
mCheetahDeath.SetActive(true);
mCheetahDeath.ToDestory = true;
mCheetahEngine.ToDestory = true;
mCheetahHit.ToDestory = true;
mAlive = false;
}
#endregion
}
}