/* * 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(); } } }