/*
* Friendly.cs
* Authors: August Zinsser
*
* Copyright Matthew Belmonte 2007
*/
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Pina3D.Particles;
using tAC_Engine;
namespace Astropolis
{
///
/// 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
{
private double mArcPosition; // Degrees of a circle corresponding to the player's ship's position
private double mArcVelocity; // Speed at which the ship can change its arcposition
private float mPowerupCooldown; // How long to wait before throwing the player a powerup
private PowerUpType mPowerUp; // The type of powerup to award
private float mMoveAway = 0f; // Holds the amount of "avoidance steering" from the main player
private float mMoveAwayTimer = 0f; // How long to wait before trying to steer away from the player
public enum PowerUpType { Weapon, Resource };
public double ArcPosition { set { mArcPosition = value; UpdatePosition(); } get { return mArcPosition; } }
public double ArcVelocity { set { mArcVelocity = value; } get { return mArcVelocity; } }
public PowerUpType PowerUp { get { return mPowerUp; } }
///
/// Constructor
///
/// Image of the ship
/// In Space3D units
/// In Space3D units
/// In Space3D units
/// 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
public Friendly(Texture2D texture, float width, float height, float depth, int hitPoints, PowerUpType powerUp, float turnMultiplier)
: base(texture, width, height, depth, hitPoints)
{
mArcVelocity = Math.PI / 720 * turnMultiplier * 2;
mPowerUp = powerUp;
mPowerupCooldown = 2.5f / turnMultiplier;
}
///
/// Deals the specified amount of damage to this ship, potentially killing it
///
///
public override void GetHit(int damage)
{
mHitPoints -= damage;
if (mHitPoints <= 0)
Destroy();
else
{
if (mPos.Z > -1)
{
// Shield particle effect
mShieldEmitter.RegularEmissionType.LifeExpectancy = .1f;
mShieldEmitter = Sparx.LoadParticleEffect(@"Content\Particle Effects\Shield.spx");
// Redden the shields to indicate that they are low
float percentLeft = (float)(mHitPoints / 100f);
Color newColor = new Color((byte)((255 * (1 - percentLeft))),
(byte)((150 * (percentLeft))),
(byte)((255 * (percentLeft))));
mShieldEmitter.RegularEmissionType.Modifiers[0].InitialTint = newColor;
mShieldEmitter.RegularEmissionType.Modifiers[0].InitialOpacity = percentLeft;
Sparx.AddEmitter(mShieldEmitter);
}
}
}
///
/// Spawns the appropriate particle effects and/or entities
///
public override void Destroy()
{
mAlive = false;
Emitter splosion = Sparx.LoadParticleEffect(@"Content\Particle Effects\MediumExplosion.spx");
Rectangle proj = Space3D.Project(this.X, this.Y, this.Z, this.Width, this.Height, -1f);
float scaling = proj.Width * .01f;
splosion.RenderScale = scaling;
splosion.Transform = Matrix.CreateScale(scaling) * Matrix.CreateTranslation(proj.X, proj.Y, MathHelper.Clamp(this.Z / 5f, 0f, 1f));
Sparx.AddEmitter(splosion);
splosion = Sparx.LoadParticleEffect(@"Content\Particle Effects\MediumExplosion.spx");
scaling *= .5f;
splosion.RenderScale = scaling;
splosion.Transform = Matrix.CreateScale(scaling) * Matrix.CreateTranslation(proj.X, proj.Y, MathHelper.Clamp(this.Z / 5f, 0f, 1f));
Sparx.AddEmitter(splosion);
}
///
/// Awards the appropriate resources or damages player
///
public override void CollideWithPlayer(Entity player)
{
((MeteorMadness)AstroBaseApplication.MiniGame).ShooterShieldHit(50);
Destroy();
}
///
/// Waits, throws a resource or power-up to the player, and then flies away
///
/// 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;
}
///
/// 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;
Random rand = new Random();
if (rand.NextDouble() < .5)
mMoveAway = (float)-mArcVelocity;
else
mMoveAway = (float)mArcVelocity;
}
///
/// Moves the ship clockwise
///
///
private void MoveLeft(float dt)
{
mArcPosition += mArcVelocity * dt;
UpdatePosition();
}
///
/// Moves the ship counterclockwise
///
///
private void MoveRight(float dt)
{
mArcPosition -= mArcVelocity * dt;
UpdatePosition();
}
///
/// Resets the cooldown of the powerup to a very long time, ensuring that only one is thrown
///
private void ThrowPowerup()
{
mPowerupCooldown = 1000f;
}
///
/// 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 %= Math.PI * 2;
mRot = mArcPosition - Math.PI / 2;
}
///
/// Updates logic and positional data for this ship
///
public override void Update()
{
float dt = AstroBaseApplication.GameManager.ElapsedSeconds;
mPowerupCooldown -= dt;
mMoveAwayTimer -= dt;
if (mMoveAwayTimer > 0)
{
// Start moving away from the original course
mArcPosition += mMoveAway;
UpdatePosition();
}
Rectangle proj = Space3D.Project(this.X, this.Y, this.Z, this.Width, this.Height, -1f);
float scaling = proj.Width * .015f;
mShieldEmitter.RenderScale = scaling;
mShieldEmitter.Transform = Matrix.CreateScale(scaling) * Matrix.CreateTranslation(proj.X, proj.Y, MathHelper.Clamp(this.Z / 5f, 0f, 1f));
base.Update();
}
}
}