/*
* MaritimeDefender.cs
* Authors: Adam Nabinger, Mike Dapirin, Mike Demauro, Brian Murphy
* based on code by August Zinsser
* 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 Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using tAC_Engine.Graphics.Cameras;
using TACParticleEngine;
using TACParticleEngine.Particles;
using Util;
using Random = Util.Random;
using tAC_Engine.GUI;
namespace MaritimeDefender
{
///
/// The main class for the meteor madness minigame.
/// This class should be initialized after the colonygame is saved.
/// Once meteor madness is complete, the colonygame is reloaded and the scoresheet is displayed.
/// Meteor madness consists of 2 major phases. First is the shooter phase which is a retro-style
/// cylinder-based space shooter. The second is a field of dots that move randomly with a variable
/// percentage moving coherently. The game jumps between these phases based on the mTrialScript variable.
/// Between each major phase, a small transition phase also occurs.
///
public class MaritimeDefender : GameScreen
{
#region Enums
///
/// Defines the various game states that Maritime Defender can be in
///
private enum States {
///
/// Defines the default state that the game is in
///
Normal,
///
/// Defines when the game is in console mode
///
Console,
///
/// Defines when the game has been successfully beaten
///
Victory,
///
/// Defines when the game has been lost
///
Defeat,
///
/// Defines when the player has reached the boss
///
Boss,
///
/// Defines when the game has been paused
///
Pause,
///
/// Defines when the game is in the ship identity phase
///
ShipIdentDisplay
}
///
/// Defines the various game screens that Maritime Defender can be on
///
private enum GameState {
///
/// Defines when the game is currently in the main menu
///
Menu,
///
/// Defines when the game is in the tutorial mode
///
Tutorial,
///
/// Defines when the game is in the actual game mode
///
Game,
///
/// Defines when the game is currently paused
///
Paused
}
///
/// Defines the directions in which theplayer could be moving in
///
public enum Directions {
///
/// Defines when the player is moving left/clockwise
///
Left,
///
/// Defines when the player is moving right/counter-clockwise
///
Right,
///
/// Defines when the player is currently not moving
///
None
}
private enum DotTrialResults
{
///
/// Correctly identified motion
///
Correct,
///
/// Incorrectly identified motion
///
Incorrect,
///
/// Did not respond to dot trial
///
False,
}
#endregion
#region Constants
// How many resources the player receives for full energy from dot coherence phase
private const float RESOURCES_FROM_ENERGY = 1f;
// How much energy is gained for a correct response in the dot coherence phases
private const float ENERGY_GAINED = 0.0125f;
// How far the dot coherence particles are from the camera
private const float DISTANCE_FROM_CAMERA = 5f;
// How long a message is displayed for
private const float DISPLAY_WAIT_TIME = .25f;
// Chance of a meteor exploding into a jackpot of credits
private const float JACKPOT_CHANCE = .075f;
// Chance of a meteor exploding into a small reward of credits
private const float LUCKY_CHANCE = .2f;
// The degree of rotation of the arrow to the left
private const float ARROW_LEFT_ROT = -MathHelper.PiOver4;
// The degree of rotation of the arrow to the right
private const float ARROW_RIGHT_ROT = MathHelper.PiOver4;
// Minimum seconds that must elapse between firings of the wormhole connection beam
private const float WORMHOLE_CONNECTION_BEAM_COOLDOWN = .5f;
// The number of seconds that must elapse after opening a wormhole before the player can move again
private const float PLAYER_FREEZE_TIME = 3f;
// Starting health of the boss
private const int BOSS_HEALTH = 500;
// Starting shield of the boss
private const int BOSS_SHIELD = 250;
// Starting base health of the friendly and space pirate ships
private const int SHIP_HEALTH = 100;
// Starting base health of the friendly and space pirate ships
private const int SHIP_HEALTH_MODIFIER = 10;
// Delay time between successive shots by the space pirates
private const float ENEMY_FIRING_DELAY = 1f;
// The amount of decrease in the firing delay of pirate shots in each level
private const float ENEMY_DELAY_MODIFIER = .1f;
// Scrolling speed to start with in level 1
private const float INITIAL_SHOOTER_SPEED = .5f;
// How much the shooter phase speed increases each level
private const float SHOOTER_SPEED_MODIFIER = .1f;
// How long (in seconds) between triggering a successful connect and a ship appearing
private const float WARP_IN_TIME = 1.4f - (1 / 60f / 2); // 1400 milliseconds minus 1 half of a frame period
#endregion
#region Private Fields
#region Booleans
// Whether or not the player is moving clockwise
private bool mMovingToPort;
// Whether or not the player is moving counter clockwise
private bool mMovingToStarboard;
// Whether or not the player is firing
private bool mFiring;
// Whether or not the player is trying to open a wormhole
private bool TryingToOpenWormhole;
// True if a collectible is out
private bool mCollectibleThrown;
// Flag for reinitializing between phases
private bool mInitialized;
// True when the player has lost, signaling that the game can still update logic even though the player is dead.
// This is mostly aesthetic.
private bool mPlayerLossed;
// If a UFO is currently warping through a wormhole
private bool mUnitIsWarping;
// If a UFO has already warped through a wormhole (used for fading out of wormholes)
private bool mUnitHasWarped;
// Also used for wormhole fade in/out calculations
private bool mPlayerOpenedWormhole;
// If the player has finished reading the ending dialog
private bool mDoneWithEndingDialog;
// True for the first dot trial in a phase to prevent logging it or including it in PEST
private bool mFirstDotTrial;
// ''
private bool mPlayerHealthAboveLastTime;
// True indicates that a new dot trial should start as soon as the HUD is stable
private bool mWaitingForNextTrial;
// Boolean to let us know that the last trial has ended to smooth out dot transition
private bool mTrialEnded;
// Boolean to let us know that the a trial has just begun to smooth out dot transition
private bool mTrialBegan;
// ''
private bool mAllowTurns;
// ''
private bool mAllowFire;
// ''
private bool mAllowConnect;
// ''
private bool mForceFriendlySpawn;
// ''
private bool mForceBogieSpawn;
// Used by ShipIdentifier
private bool mReadyForID;
// ''
private bool mEnemyOnLeft;
// ''
private bool mCharSelection;
// If the mousepointer is visible or not, mostly set by games
private bool mShowMousePointer = true;
private bool isFrozen = false;
#endregion
#region Floats
// Max distance that the shooter game objects can go from the camera
private float mMaxShooterZ;
// The closest that shooter game objects can get to the camera
private float mMinShooterZ;
// A cutoff for rendering close to the camera
private float mNearPlane;
// The current coherence percentage of dots in the dot phase of meteor madness
private float mDotCoherencePercentage;
// Shield percentage of the ship in meteor madness
private float mDotShields = 1F;
// How much energy has been saved from correctly steering during the dot coherence phases
private float mEnergySaved;
// Minimum amount of seconds to elapse between the appearance of UFO wormholes
private float mUnitWormholeMinInterval;
// Maximum amount of seconds between UFO wormholes, although more time could elapse if the wormhole is
// waiting for meteors to get out of the way
private float mUnitWormholeMaxInterval;
// Counts the seconds between UFO wormhole appearances
private float mUnitWormholeCounter;
// Used for wormhole fade in/out calculations
private float mUnitWarpCounter;
// Tweak the size of all ships
private float mShipScale;
// Time (in arbitrary units) between coming out of warp and "moving forward"
// (should be at least double the amount of time it takes for a dot to go from -maxz to maxz)
private float mWarpDelay;
// Counts intervals used for warping of wormholes
private float mWarpCounter;
// Counts seconds between meteors spawning
private float mMeteorSpawnCounter;
// Used to prevent multiple boss rockets from hitting the player at once
private float mInvulnerableTimer;
// If one boss rocket hits the player, the time that must elapse before another rocket actually damages the player
private float mBossProjectileDamageCooldown;
// Affects scrolling of shooter entities, which is one of the ways in which the shooter phase's difficulty is increased
private float mShooterSpeed;
// Seconds that have elapsed since the last firing of the wormhole connection beam
private float mWormholeConnectionBeamCounter;
// Counts down until the player jumps into the wormhole for the shooter to dot transition phase
private float mPlayerJumpCountdown;
// How long to wait before starting the first trial
private float mDotTestBeginDelay;
// The time remaining in the current dot test
private float mDotTrialCountdown;
// Saves the previous coherence values for use in the late response
private float mOldCoherence;
// Wait at the beginning of a round before doing anything
private float mNewRoundWaitTimer;
// Let the player revel in victory for a couple seconds before ending the game
private float mVictoryTimer;
// Time before the ship flies off in the distance
private float mFlyAwayTimer;
// Used to prevent a flood of "+Credits" messages
private float mDisplayWaitTimer;
// Seconds between each player's shot
private float mWeaponCooldownCounter;
// Counts down the time the player's ship remains frozen after opening a wormhole
private float mFreezeTimer;
// How many seconds occur between the player dying and the score screen displaying
private float mLoseDelay;
// ''
private float mPlayerHealthTimer;
// Holds the coherence for extra time to allow better EEG readings
private float mHoldCoherenceTimer;
// Late response timer
private float mLateResponseTimer;
// Float used to provide a smooth dot transition after a dot coherence trial has ended
private float mFadeCoherence;
// ''
private float mArrowAngularVel;
// ''
private float mTimerID;
#endregion
#region Integers
// Number of dots that are being displayed in the dot phase of meteor madness
private int mNumDots;
// The number of dots during the last update cycle
private int mLastNumDots;
// The number of lives before the game ends
private int mPlayerLives;
// How much damage the shields take when the player hits a meteor
private int mMeteorDamage;
// Starting value of enemy shields
private int mEnemyShields;
// Remaining trials for each phase
private int mRemainingTrials;
// Tells the user what level they are on
private int mCurrentLevel;
// ''
private int mArrowSelected;
#endregion
#region Strings
// The current phase of the minigame
private string mCurrentPhase;
// Holds the image of the friendly ship
private string mFriendlyTexturePath;
// Holds the image of the enemy ship
private string mBogieTexturePath;
// '' (schematic)
private string mFriendlySchematicPath;
// '' (schematic)
private string mBogieSchematicPath;
#endregion
#region Objects
// The state of the minigame
private GameState mGameState;
// Camera used for drawing particles with
private Camera mActiveCamera;
// Defines a basic 3D coordinate system, although in this game most objects are constrained to a cylinder.
private Space3D mGameBoard;
// Defines the order in which phases occur as well as the trials per phase
private Queue mPhaseQueue;
// Direction of dot coherence (if any)
private Vector3 mDirection;
// The wormhole that spawns the cheetah fighter at the start of each shooter phase
private Wormhole mPlayerWormhole;
// Wormholes that spawn UFOs (there can only be one at a time)
private Wormhole mUnitWormhole;
// The powerup that UFOs leave behind either by "throwing" it to the player or dying.
private Flotsam mCollectible;
//
private InputHandler mInputHandler;
//
private States CurrentState = States.Normal;
// Manager for all particle effects in Meteor Madness, make sure to unload upon end
private ParticleManager mParticleManager;
// Holds all the meteors in the shooter phase
private List mMeteors;
// The reward spawned on a jackpot
private List mJackpotCollectibles;
// List of messages used for diplaying messages
private List mMessages;
// A list of sprites to draw
private List mSprites;
// '' widgets
private List mWidget2Ds;
// The units that come out of the wormholes
private UFO mUnit;
// The final boss
private Boss mBoss;
// Used to calculate the trial values in the dot phase
private BestPEST mPester;
// ''
private Vector3 mOldDirection;
// ''
private BossHealthBar2D mBossMeter;
// ''
private HealthBar2D mPlayerHealthBar;
// ''
private Entity mEnemyID;
// ''
private Entity mFriendlyID;
// ''
private Entity mArrowID;
// The image for the mouse pointer
private Texture2D mMousePointer;
//
private Rectangle mMouseLocation;
//
private SpriteBatch mSpriteBatch;
//
private SpriteFont font;
// Event code to log when finished drawing.
private EventCode logOnDraw;
#endregion
#endregion
#region Public Fields
#region Booleans
///
/// Used by the tutorial script
///
public bool mLPressed;
///
/// ''
///
public bool mRPressed;
///
/// ''
///
public bool mConnected;
///
/// ''
///
public bool DialogDone;
#endregion
#region Particle Effects
///
///
///
public ParticleEngine mPirateDeath;
///
///
///
public ParticleEngine mMeteorHit;
///
///
///
public ParticleEngine mStarField;
///
///
///
public ParticleEngine mWarping;
///
///
///
public ParticleEngine mFailBeam;
///
///
///
public ParticleEngine mSuccessBeam;
///
///
///
public ParticleEngine mWarpDrive;
///
///
///
public ParticleEngine mWarpPrepare;
///
///
///
public ParticleEngine mStationaryDots;
///
///
///
public ParticleEngine mCoherenceDots;
#endregion
#region Objects
///
///
///
public Logger logger;
///
/// Currently used only for 'ship identifier' display
///
public List mEntities = new List();
///
/// All projectiles fired from both enemy ships and the player
///
public List mProjectiles;
///
/// The cheetah fighter ship that the player controls
///
public CheetahFighter mPlayerShip;
///
/// HUD element
///
public Cockpit mCockpit;
#endregion
#endregion
#region Properties
///
/// Gets tje Space3D game board
///
internal Space3D GameBoard { get { return mGameBoard; } }
///
/// Gets/Sets the list of photon torpedoes
///
internal List Projectiles
{
get { return mProjectiles; }
set { mProjectiles = value; }
}
///
/// Gets the display wait timer
///
public float DisplayWaitTimer { get { return mDisplayWaitTimer; } }
///
/// Gets the particle manager for Maritime Defender
///
public ParticleManager MMParticleManager { get { return mParticleManager; } }
///
/// Gets the path name for the friendly ship's texture
///
public string FriendlyTexturePath { get { return mFriendlyTexturePath; } }
///
/// Gets the path name for the enemy ship's texture
///
public string BogieTexturePath { get { return mBogieTexturePath; } }
///
/// Gets the path name for the friendly ship's schematic
///
public string FriendlySchematicPath { get { return mFriendlySchematicPath; } }
///
/// Gets the path name for the enemy ship's schematic
///
public string BogieSchematicPath { get { return mBogieSchematicPath; } }
///
/// Gets how much energy has been saved from correctly steering during the dot coherence phases
///
public float EnergySaved { get { return mEnergySaved; } }
///
/// Gets/Sets the speed at which the player shoots
///
public float ShooterSpeed
{
get { return mShooterSpeed; }
set { mShooterSpeed = value; }
}
///
/// Gets/Sets the shield percentage of the ship in meteor madness
///
public float DotShields {
get { return mDotShields; }
set { mDotShields = value; }
}
///
/// Gets/Sets whether or not the mouse cursor should be visible
///
public bool ShowMouseCursor
{
get { return mShowMousePointer; }
set { mShowMousePointer = value; }
}
#endregion
internal void addWidget(Widget2D w)
{
mWidget2Ds.Add(w);
}
public void Log(EventCode EventCode, string text)
{
logger.Write((int)EventCode, text);
}
public string GetFriendlySchematic()
{
return mFriendlySchematicPath;
}
public string GetEnemySchematic()
{
return mBogieSchematicPath;
}
public void SetGamePhase(string phaseName)
{
mCurrentPhase = phaseName;
}
public void SetDrift(Directions direction)
{
switch (direction)
{
case Directions.Left:
mDotCoherencePercentage = .75f;
mDirection = Vector3.Left;
mStationaryDots.SetEngineParticles(Settings.GetNumberDots(GraphicsDevice) * .25f);
mCoherenceDots.SetEngineParticles(Settings.GetNumberDots(GraphicsDevice) * .75f);
mCoherenceDots.SetEngineDirection(Vector3.Left);
mCoherenceDots.SetActive(true);
break;
case Directions.Right:
mDotCoherencePercentage = .75f;
mDirection = Vector3.Right;
mStationaryDots.SetEngineParticles(Settings.GetNumberDots(GraphicsDevice) * .25f);
mCoherenceDots.SetEngineParticles(Settings.GetNumberDots(GraphicsDevice) * .75f);
mCoherenceDots.SetEngineDirection(Vector3.Right);
mCoherenceDots.SetActive(true);
break;
default:
mDotCoherencePercentage = 0f;
mStationaryDots.SetEngineParticles(Settings.GetNumberDots(GraphicsDevice));
mStationaryDots.SetActive(true);
mCoherenceDots.SetActive(false);
break;
}
}
// Only used for tutorial
public void ForceTurn(Directions direction)
{
switch (direction)
{
case Directions.Left:
mCockpit.TurnLeft();
break;
case Directions.Right:
mCockpit.TurnRight();
break;
}
}
public void ClearLRPressed()
{
mLPressed = false;
mRPressed = false;
}
public void DisallowFireAndConnect()
{
mAllowFire = false;
mAllowConnect = false;
}
public void AllowTurns()
{
mAllowTurns = true;
}
public void DisallowTurns()
{
mAllowTurns = false;
}
public void AllowFire()
{
mAllowFire = true;
}
public void AllowConnect()
{
mAllowConnect = true;
}
public void DisableControls()
{
mAllowFire = false;
mAllowConnect = false;
mAllowTurns = false;
}
public void SpawnMeteors(int amount)
{
for (int i = 0; i < amount; i++)
{
// Randomize the meteor's appearance
float newMeteorSize = (Meteor.MIN_SIZE + (Meteor.MAX_SIZE - Meteor.MIN_SIZE) * Random.NextFloat());
// Spawn a new meteor in an area that is not close to a unit wormhole
Meteor newMeteor = new Meteor(newMeteorSize, newMeteorSize, newMeteorSize, mShooterSpeed, mMaxShooterZ, -mMaxShooterZ, Content);
newMeteor.FadeIn(4);
newMeteor.Z -= (i * 0.25f);
mMeteors.Add(newMeteor);
}
}
///
/// Spawn a Wormhole that spawns a Unit.
///
/// The Rotation in pies.
public void SpawnUnitWormhole(float positionMultiplier)
{
// It's time for a new wormhole
float arcPosition = MathHelper.Pi * positionMultiplier;
mUnitWormhole = new Wormhole(
mShipScale * .9f,
mShipScale * .9f,
0f,
arcPosition,
false);
mUnitWormhole.LoadContent(Content);
Vector2 PositionFromOrigin = new Vector2((float)Math.Cos(arcPosition), (float)Math.Sin(arcPosition));
mUnitWormhole.X = .8F * PositionFromOrigin.X;
mUnitWormhole.Y = .8F * PositionFromOrigin.Y;
mUnitWormhole.Z = mMaxShooterZ - .1f;
mUnitWormhole.Visible = false;
mUnitIsWarping = false;
mUnitHasWarped = false;
mPlayerOpenedWormhole = false;
mUnitWormhole.FadeIn(WARP_IN_TIME);
}
public void SpawnFriendly()
{
mUnitIsWarping = true;
mForceFriendlySpawn = true;
mForceBogieSpawn = false;
mUnitWormholeCounter = 2f;
if (mUnit != null)
mGameBoard.RemoveEntity(mUnit);
}
public void SpawnBogie()
{
mUnitIsWarping = true;
mForceBogieSpawn = true;
mForceFriendlySpawn = false;
mUnitWormholeCounter = 2f;
if (mUnit != null)
mGameBoard.RemoveEntity(mUnit);
}
public void StartBoss()
{
mBoss.Start();
}
public void DoneWithEndingDialog()
{
mDoneWithEndingDialog = true;
}
public bool MeteorsExist()
{
return mMeteors.Count > 0;
}
public MaritimeDefender()
{
}
public override void Initialize()
{
logger = GetLogger();
mInputHandler = GetInputHandler();
logger.Initialize();
mInputHandler.Initialize();
// Setup logging parameters
mInputHandler.BindButton(Keys.OemTilde, Trigger.Activated, (int)EventCode.MD_OpenConsole);
mInputHandler.BindButton(Keys.Escape, Trigger.Activated, (int)EventCode.MD_Pause);
mInputHandler.BindButton(Keys.Left, Trigger.Activated, (int)EventCode.MD_ShooterActivateMovePort);
mInputHandler.BindButton(Keys.Left, Trigger.Deactivated, (int)EventCode.MD_ShooterCeaseMovePort);
mInputHandler.BindButton(Keys.Right, Trigger.Activated, (int)EventCode.MD_ShooterActivateMoveStarboard);
mInputHandler.BindButton(Keys.Right, Trigger.Deactivated, (int)EventCode.MD_ShooterCeaseMoveStarboard);
mInputHandler.BindButton(Keys.Up, Trigger.Activated, (int)EventCode.MD_ShooterActivateOpenWormholeBeam);
mInputHandler.BindButton(Keys.Up, Trigger.Deactivated, (int)EventCode.MD_ShooterCeaseOpenWormholeBeam);
mInputHandler.BindButton(Keys.Space, Trigger.Activated, (int)EventCode.MD_ShooterActivateFireWeapon);
mInputHandler.BindButton(Keys.Space, Trigger.Deactivated, (int)EventCode.MD_ShooterCeaseFireWeapon);
// Basic game initialization
logger.Write((int)EventCode.MD_MaritimeDefenderGameBegin, EventCode.MD_MaritimeDefenderGameBegin.ToString());
mActiveCamera = new Perspective3DCamera(new Vector3(0, 0, -5), Vector3.Zero, Vector3.Down, MathHelper.PiOver2, 1, 1, 100);
mInitialized = false;
mPlayerLossed = false;
mGameState = GameState.Menu;
//HUD
mSprites = new List();
mWidget2Ds = new List();
// Initialize game params
mCharSelection = Random.Bool();
mShipScale = .5F;
mNearPlane = -1.0F;
mDirection = Vector3.Zero;
mLastNumDots = -1;
mWarpDelay = 4F;
mMeteors = new List();
mMeteorSpawnCounter = 0F;
mMeteorDamage = 10;
mWeaponCooldownCounter = 0;
mMessages = new List();
mProjectiles = new List();
mUnitWormholeMinInterval = 2f;
mUnitWormholeMaxInterval = 5f;
mUnitWormholeCounter = mUnitWormholeMaxInterval;
mUnitIsWarping = false;
mUnitHasWarped = false;
mUnitWarpCounter = 0f;
mPlayerOpenedWormhole = false;
mUnit = null;
mBoss = null;
mFreezeTimer = 0;
mLoseDelay = 10f;
mDoneWithEndingDialog = false;
mDotTrialCountdown = 0f;
mPester = new BestPEST(@"PEST.dat");
mPester.Initialize();
mCurrentLevel = 1;
mWaitingForNextTrial = false;
mNewRoundWaitTimer = 0f;
mHoldCoherenceTimer = 0;
mAllowTurns = true;
mAllowFire = true;
mAllowConnect = true;
mForceFriendlySpawn = false;
mForceBogieSpawn = false;
mReadyForID = false;
CheetahFighter.CollectedUpgrades = 1;
mPlayerHealthTimer = 0f;
mPlayerLives = 3;
mBossProjectileDamageCooldown = .2f;
mJackpotCollectibles = new List();
mDisplayWaitTimer = 0f;
AutoClear(DrawOrder - 1);
base.Initialize();
#if DEBUG
ShowFPS();
#endif
}
protected override void LoadContent()
{
mSpriteBatch = new SpriteBatch(GraphicsDevice);
foreach (Message msg in mMessages)
{
msg.SpriteBatch = mSpriteBatch;
msg.LoadContent();
}
mParticleManager = new ParticleManager(Content, mActiveCamera, mSpriteBatch, GraphicsDevice.Viewport);
mParticleManager.DrawOrder = DrawOrder + 2;
AddComponent(mParticleManager);
font = Content.Load(@"Fonts\dialogfont");
mShowMousePointer = false;
mCockpit = new Cockpit(this, logger);
mCockpit.LoadContent(Content);
mCockpit.Visible = false;
mWidget2Ds.Add(mCockpit);
mGameBoard = new Space3D(this);
mGameBoard.mMeteors = mMeteors;
mGameBoard.mPhotonTorpedos = mProjectiles;
mGameBoard.mFlotsam = mJackpotCollectibles;
mMaxShooterZ = mGameBoard.MaxZ = 5.0F;
mMinShooterZ = mGameBoard.MinZ = -1.0F;
// HUD
mMousePointer = Content.Load(@"General\StandardCursor");
mMouseLocation = new Rectangle(0, 0, mMousePointer.Width, mMousePointer.Height);
int screenWidth = GraphicsDevice.Viewport.Width;
int screenHeight = GraphicsDevice.Viewport.Height;
mBossMeter = new BossHealthBar2D(
"BOSS",
@"Fonts\dialogfont",
new Rectangle(
(int)(screenWidth * .50f),
(int)(screenHeight * .05f),
(int)(screenWidth * .90f),
(int)(screenHeight * .05f)),
@"MiniGames\MMBossHealthbar",
new Color(0, 255, 255),
new Color(196, 196, 196),
new Color(246, 167, 0));
mBossMeter.LoadContent(Content);
mBossMeter.Visible = false;
mWidget2Ds.Add(mBossMeter);
mPlayerHealthBar = new HealthBar2D(0, 0, (int)(screenWidth * .10f), (int)(Math.Max(screenHeight * .01f, 4)));
mPlayerHealthBar.LoadContent(Content);
mPlayerHealthBar.BorderColor = Color.Gray;
mPlayerHealthBar.Visible = false;
mWidget2Ds.Add(mPlayerHealthBar);
// Load in Particle Effects
mPirateDeath = mParticleManager.Load("ParticleEffects/Explosion");
mMeteorHit = mParticleManager.Load("ParticleEffects/MeteorExplosion");
mStarField = mParticleManager.Load("ParticleEffects/ShooterStar");
mStarField.DrawOrder = DrawOrder;
mStarField.SetEngineDirection(Vector3.Forward);
mStarField.SetEnginePosition(new Vector3(0, 0, 150));
mWarping = mParticleManager.Load("ParticleEffects/Warping");
mWarping.DrawOrder = DrawOrder;
mFailBeam = mParticleManager.Load("ParticleEffects/FailBeam");
mSuccessBeam = mParticleManager.Load("ParticleEffects/SuccessBeam");
mWarpDrive = mParticleManager.Load("ParticleEffects/WarpDrive");
mWarpPrepare = mParticleManager.Load("ParticleEffects/WarpPrepare");
mWarpPrepare.DrawOrder = DrawOrder + 1;
mStationaryDots = mParticleManager.Load("ParticleEffects/DotCoherence");
mStationaryDots.SetRandomDirection(true);
mStationaryDots.SetEngineParticleLifetime((float)Settings.DotLifeSpan);
mStationaryDots.SetEngineSize(new Vector2((float)Settings.DotDiameter * GraphicsDevice.Viewport.Width,
(float)Settings.DotDiameter * GraphicsDevice.Viewport.Height));
mStationaryDots.SetEngineSpeed((float)Settings.DotSpeed * DISTANCE_FROM_CAMERA, true);
mStationaryDots.DrawOrder = DrawOrder;
mCoherenceDots = mParticleManager.Load("ParticleEffects/DotCoherence");
mCoherenceDots.SetEngineParticleLifetime((float)Settings.DotLifeSpan);
mCoherenceDots.SetEngineSize(new Vector2((float)Settings.DotDiameter * GraphicsDevice.Viewport.Width,
(float)Settings.DotDiameter * GraphicsDevice.Viewport.Height));
mCoherenceDots.SetEngineSpeed((float)Settings.DotSpeed * DISTANCE_FROM_CAMERA, true);
mCoherenceDots.DrawOrder = DrawOrder;
// Set Friendly and Enemy Textures, for the Ship Identifier Script
if (mCharSelection)
{
mFriendlyTexturePath = @"MiniGames\Drone";
mBogieTexturePath = @"MiniGames\Wasp";
mFriendlySchematicPath = @"MiniGames\MMDroneSchematic";
mBogieSchematicPath = @"MiniGames\MMWaspSchematic";
}
else
{
mFriendlyTexturePath = @"MiniGames\Wasp";
mBogieTexturePath = @"MiniGames\Drone";
mFriendlySchematicPath = @"MiniGames\MMWaspSchematic";
mBogieSchematicPath = @"MiniGames\MMDroneSchematic";
}
if (mUnitWormhole != null)
{
mUnitWormhole.LoadContent(Content);
}
if (mPlayerWormhole != null)
{
mPlayerWormhole.LoadContent(Content);
}
base.LoadContent();
}
///
/// Transitions the game into the next phase or ends the game and displays the score
///
public void CompletePhase()
{
if (mPhaseQueue.Count <= 0)
{
// We are out of trials, which means the player has beaten all of the levels so declare this a successful ending
logger.Write((int)EventCode.MD_GameSuccess, EventCode.MD_GameSuccess.ToString());
// TODO: SCORING TEST
MiniGameInfo.ScoreValue += mPlayerLives * 500;
MiniGameInfo.ScoreValue += 5000;
MiniGameInfo.ScoreValue += (int) (500 * mEnergySaved);
MiniGameInfo.HasPlayed = true;
mShowMousePointer = true;
// Lock the controls, relying on the score display to unlock them
mInputHandler.Disable();
// Record the range-adjusted coherence
double coherence = (mPester.NextValue() + 1) * 50f;
logger.Write((int)EventCode.MD_DotCoherenceEstimate, EventCode.MD_DotCoherenceEstimate + " Coherence=" + (coherence).ToString("F"));
// Display the end game screen
MiniGameScoreScreen screen = new MiniGameScoreScreen();
// Disable this screen
Disable();
// Raise the screen
Raise(screen);
// Create the list of scores
Dictionary scores = new Dictionary();
scores.Add("Lives Remaining: " + mPlayerLives, "" + (mPlayerLives * 500) + " points");
scores.Add("Energy Saved: " + (int)(mEnergySaved * 100), "" + (int)(mEnergySaved * 500) + " points");
scores.Add("Completion Bonus: ", "" + 5000 + " points");
scores.Add("Total Score: ", "" + MiniGameInfo.ScoreValue + " points");
// Set the title
screen.DisplayScores("Maritime Defender", scores);
}
else
{
// Update Trial script
string lastPhase = mCurrentPhase;
MaritimeDefenderTest curTest = mPhaseQueue.Dequeue();
mCurrentPhase = curTest.PhaseName;
mRemainingTrials = curTest.Trials;
// Signal the appropriate transition to take place in the next several update cycles
switch (mCurrentPhase)
{
case MaritimeDefenderPhases.DotTest:
logger.Write((int)EventCode.MD_DotPhaseBegin, EventCode.MD_DotPhaseBegin.ToString());
if (lastPhase == MaritimeDefenderPhases.Shooter)
mCurrentPhase = MaritimeDefenderPhases.Shooter2DotTestTransition;
break;
case MaritimeDefenderPhases.Shooter:
logger.Write((int)EventCode.MD_ShooterPhaseBegin, EventCode.MD_ShooterPhaseBegin.ToString());
if (lastPhase == MaritimeDefenderPhases.DotTest)
mCurrentPhase = MaritimeDefenderPhases.DotTest2ShooterTransition;
else
mCurrentPhase = MaritimeDefenderPhases.Shooter;
break;
case MaritimeDefenderPhases.Boss:
logger.Write((int)EventCode.MD_BossPhaseBegin, EventCode.MD_BossPhaseBegin.ToString());
mCurrentPhase = MaritimeDefenderPhases.Shooter2BossTransition;
break;
}
}
}
///
/// Resets the timer which must countdown before jackpot "+Credits" are displayed
///
public void ResetDisplayWaitTimer()
{
mDisplayWaitTimer = DISPLAY_WAIT_TIME;
}
///
/// Let the game continue to run in the background for a while before going back to the colony mode or respawn the ship
///
private void GotoAfterlife()
{
// Die only once per death
if (!mPlayerLossed)
{
if (mUnit != null)
{
mUnit.Destroy();
}
foreach (Meteor meteor in mMeteors)
{
meteor.FadeOut(1f);
}
mPlayerShip.DestroyPlayer();
mPlayerLives--;
}
// Respawn the player?
if (mPlayerLives > 0)
{
mDotShields = 1f;
mPlayerLossed = false;
mInitialized = false;
mNewRoundWaitTimer = 4f;
mPlayerHealthTimer = -2f;
mGameBoard.RemoveEntity(mPlayerShip);
mPlayerShip = null;
}
else if (!mPlayerLossed)
{
// Lose the game once
mPlayerLossed = true;
mPlayerHealthTimer = -2f;
mGameBoard.RemoveEntity(mPlayerShip);
mPlayerShip = null;
CurrentState = States.Defeat;
Raise((GameScreen)CSharpHelper.DoSimpleFile(RootDirectory + @"\Content\Scripts\Defeat.script", typeof(GameScreen)));
}
}
///
/// Let the game continue to run in the background for a while before going back to the colony mode
///
private void LoseGameFromDotTest()
{
// Lose only once
if (!mPlayerLossed)
{
CrashInSubspace();
mPlayerLives--;
}
// Respawn the player?
if (mPlayerLives > 0)
{
mDotShields = 1f;
mPlayerLossed = false;
mInitialized = false;
CompletePhase();
}
else if (!mPlayerLossed)
{
// Lose the game once
mPlayerLossed = true;
CurrentState = States.Defeat;
Raise((GameScreen)CSharpHelper.DoSimpleFile(RootDirectory + @"\Content\Scripts\Defeat.script", typeof(GameScreen)));
}
}
///
/// Perform necessary logic updates
///
public override void Update(GameTime gameTime)
{
foreach (Entity e in mEntities)
{
e.Update(gameTime);
}
foreach (Message msg in mMessages)
{
msg.Update(gameTime);
}
float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
SoundManager.SoundManager.Update();
foreach (Widget2D w in mWidget2Ds)
{
w.Update(gameTime);
}
if (mGameState == GameState.Menu)
{
mShowMousePointer = true;
}
if (mGameState == GameState.Game || mGameState == GameState.Tutorial)
{
if (DialogDone)
{
mReadyForID = true;
mEntities.Clear();
DialogDone = false;
}
#region common
mNewRoundWaitTimer -= dt;
mPlayerHealthTimer -= dt;
mInvulnerableTimer -= dt;
mDisplayWaitTimer -= dt;
if (mGameState == GameState.Game && mRemainingTrials <= 0 && mCurrentPhase != MaritimeDefenderPhases.Boss)
CompletePhase();
// Handle losing game transition
if (mPlayerLossed)
{
mLoseDelay -= dt;
if (mLoseDelay < 0 && mDoneWithEndingDialog)
{
logger.Write((int)EventCode.MD_GameFailure, EventCode.MD_GameFailure.ToString());
// TODO: Redo scoring system
//Score.Display(false, "SENDING REINFORCEMENTS");
//Score.CashOut(AstroBaseApplication.Game);
mShowMousePointer = true;
Done();
// Lock the controls, relying on the score display to unlock them
//InputState.Locked = true;
// Record the range-adjusted coherence
if (!logger.Disposed)
{
logger.Write((int)EventCode.MD_DotCoherenceEstimate, EventCode.MD_DotCoherenceEstimate +
" Coherence=" + ((mPester.NextValue() + 1) * 50f).ToString("F"));
}
Done();
}
}
// Mark dead things for removal
mEntities.RemoveAll(Entity.NotAlive);
mMeteors.RemoveAll(Meteor.NotAlive);
mProjectiles.RemoveAll(PhotonTorpedo.NotAlive);
mMessages.RemoveAll(Message.NotAlive);
//update shields
if (mDotShields < 1.0F)
mDotShields += CheetahFighter.SHIELD_RECHARGE_RATE * dt;
mPlayerHealthBar.Life = mDotShields;
if (mPlayerHealthTimer > 0f)
{
if (mPlayerWormhole != null && mPlayerWormhole.Visible)
mPlayerHealthBar.Opacity = 0f;
else
mPlayerHealthBar.Opacity = 1f;
mPlayerHealthBar.Visible = true;
}
else
{
// fade?
if (mPlayerHealthTimer > -1f)
mPlayerHealthBar.Opacity = 1 + mPlayerHealthTimer;
else
mPlayerHealthBar.Visible = false;
}
// Update scrolling meteors
foreach (Meteor meteor in mMeteors)
{
meteor.Update(gameTime);
}
// Update "the unit" (the UFO that may have come out of a wormhole)
if (mUnit != null)
{
if (!mUnit.Alive)
{
// See if the player has killed a friendly before it could give him/her a bonus
if (mUnit is Friendly && !mCollectibleThrown)
{
mRemainingTrials--;
}
// If it was an enemy, then leave some (very sturdy) money behind
if (mUnit is SpacePirate)
{
mGameBoard.RemoveEntity(mCollectible);
mCollectible = new Flotsam(Pickup.Credits, 100, @"General\Credits", .1F * mShipScale, .1F * mShipScale, mShipScale, this);
mCollectible.LoadContent(Content);
mCollectible.HitPoints = 100;
mCollectible.Position = mUnit.Position;
mCollectible.dZ = mUnit.dZ * 2f;
mGameBoard.AddEntity(mCollectible);
}
// Remove the unit from the game
mGameBoard.RemoveEntity(mUnit);
mUnit = null;
}
else
{
mUnit.Update(gameTime);
if (mUnit.React(mPlayerShip))
{
if (mUnit is SpacePirate && mUnit.Z > mPlayerShip.Z)
{
// Space pirates try to kill the player by shooting a photon torpedo
SoundManager.SoundManager.PlayEffect("Pew");
PhotonTorpedo newPhoton = new PhotonTorpedo(true, true, 0, mUnit.Position, mUnit.Width * .1f, mUnit.Width * .1f, mUnit.Width * .1f, mShooterSpeed * -10, mMaxShooterZ - .11f, mNearPlane, this);
newPhoton.Friendly = false;
newPhoton.Damage = SpacePirate.SHOT_DAMAGE;
newPhoton.Tint = new Color(255, 100, 100, 128);
mProjectiles.Add(newPhoton);
logger.Write((int)EventCode.MD_ShooterEnemyWeaponFired, EventCode.MD_ShooterEnemyWeaponFired.ToString());
}
else if (mUnit is Friendly)
{
// Friendlies shoot powerups at the player
mGameBoard.RemoveEntity(mCollectible);
if (CheetahFighter.CollectedUpgrades <= mCurrentLevel && Random.NextFloat() < .75f)
{
mCollectible = new Flotsam(Pickup.Weapon, 100, @"MiniGames\Crate", .3F * mShipScale, .3F * mShipScale, mShipScale, this);
mCollectible.LoadContent(Content);
}
else
{
mCollectible = new Flotsam(Pickup.Carbon, 100, @"MiniGames\Crate", .3F * mShipScale, .3F * mShipScale, mShipScale, this);
mCollectible.LoadContent(Content);
}
mCollectible.Position = mUnit.Position;
mCollectible.dZ = -6;
mGameBoard.AddEntity(mCollectible);
mCollectibleThrown = true;
logger.Write((int)EventCode.MD_ShooterCollectibleSpawned, EventCode.MD_ShooterCollectibleSpawned.ToString());
}
}
// Check for player-enemy collision (do not collide with friendlies)
if (mPlayerShip != null && mPlayerShip.Visible && mUnit is SpacePirate && Entity.Collides3D(mUnit, mPlayerShip))
{
mUnit.CollideWithPlayer(mPlayerShip);
}
// See if the ship has passed the player (ending the trial)
if (mUnit.Position.Z < mMinShooterZ)
{
// Friendly trials end when the powerup dies, but enemies may fly off the screen without getting killed
if (mUnit is SpacePirate)
mRemainingTrials--;
mGameBoard.RemoveEntity(mUnit);
mUnit = null;
}
}
}
// Update the player wormhole
if (mPlayerWormhole != null)
mPlayerWormhole.Update(gameTime);
if (mWarpCounter < 0 && mPlayerShip != null)
{
mWarpCounter = 0;
mPlayerShip.FadeIn(.5F);
if (mPlayerWormhole != null)
mPlayerWormhole.FadeOut(mWarpDelay / 4);
}
else if (mWarpCounter > 0)
{
mWarpCounter -= dt;
}
// Update any jackpot coins from exploded meteors
foreach (Flotsam coin in mJackpotCollectibles)
{
if (mPlayerShip == null)
{
coin.Alive = false;
}
else
{
if (coin.Z < mMinShooterZ)
{
coin.Alive = false;
continue;
}
// Update the collectible's position and test for collision
coin.Update(gameTime, mPlayerShip);
if (mPlayerShip.Visible && Entity.Collides3D(coin, mPlayerShip))
{
coin.CollideWithPlayer(mPlayerShip);
}
}
}
mJackpotCollectibles.RemoveAll(Flotsam.Destroyed);
#endregion
// Update the appropriate phase of the game
if (mCurrentPhase == MaritimeDefenderPhases.DotTest)
{
#region DotTest
// Adjust the dots' intervals if lifespan, screen dimensions or numdots was changed
if (mNumDots != mLastNumDots)
{
mInitialized = false;
mLastNumDots = Settings.GetNumberDots(GraphicsDevice);
mNumDots = mLastNumDots;
logger.Write("MD_DotCount NumDots=" + mNumDots);
}
// Reinitialize stuff
if (!mInitialized)
{
if (mGameState == GameState.Game)
{
// Setup logging parameters
mInputHandler.BindButton(Keys.OemTilde, Trigger.Activated, (int)EventCode.MD_OpenConsole);
mInputHandler.BindButton(Keys.Escape, Trigger.Activated, (int)EventCode.MD_Pause);
mInputHandler.BindButton(Keys.Left, Trigger.Activated, (int)EventCode.MD_DotTrialUserRespondLeft);
mInputHandler.BindButton(Keys.Right, Trigger.Activated, (int)EventCode.MD_DotTrialUserRespondRight);
}
mTrialBegan = false;
mTrialEnded = false;
mCoherenceDots.SetEngineParticles(1);
mCoherenceDots.SetActive(true);
mStationaryDots.SetEngineParticles(mNumDots);
mStationaryDots.SetActive(true);
// Refresh any old playerships or player wormholes
if (mPlayerShip != null)
mGameBoard.RemoveEntity(mPlayerShip);
mPlayerWormhole = null;
// Adjust the HUD
mCockpit.Visible = true;
mFirstDotTrial = true;
mInitialized = true;
}
// Test for death
if (mDotShields < 0f)
{
LoseGameFromDotTest();
mCockpit.Visible = false;
}
if (mTrialEnded)
{
if (mFadeCoherence < 0.1f)
{
mCoherenceDots.SetEngineParticles(1);
mStationaryDots.SetEngineParticles(mNumDots);
mTrialEnded = false;
}
else
{
mFadeCoherence -= 0.03f;
mCoherenceDots.SetEngineParticles(mNumDots * mFadeCoherence);
mStationaryDots.SetEngineParticles(mNumDots * (1f - mFadeCoherence));
}
}
else if (mTrialBegan)
{
if (mFadeCoherence >= mDotCoherencePercentage)
{
mCoherenceDots.SetEngineParticles(mNumDots * mDotCoherencePercentage);
mStationaryDots.SetEngineParticles(mNumDots * (1f - mDotCoherencePercentage));
mTrialBegan = false;
}
else
{
mFadeCoherence += 0.03f;
mCoherenceDots.SetEngineParticles(mNumDots * mFadeCoherence);
mStationaryDots.SetEngineParticles(mNumDots * (1f - mFadeCoherence));
}
}
// See if a trial should begin
if (mWaitingForNextTrial && mDotTestBeginDelay < 0f)
{
if (mLateResponseTimer < 0f)
{
if (mHoldCoherenceTimer < 0f)
{
if (mCockpit.IsStable())
{
// Begin the next trial
mWaitingForNextTrial = false;
if (mDotCoherencePercentage > 0f)
{
logger.Write((int)EventCode.MD_DotTrialBegin, EventCode.MD_DotTrialBegin + " Coherence=" + (mDotCoherencePercentage * 100f).ToString("F") + " Direction=" + (mDirection == Vector3.Right ? "Right" : "Left"));
mCoherenceDots.SetEngineDirection(mDirection);
mTrialBegan = true;
}
else
{
logger.Write((int)EventCode.MD_DotTrialBegin, EventCode.MD_DotTrialBegin + " Coherence=0");
}
}
}
else
{
mHoldCoherenceTimer -= dt;
}
}
else
{
mLateResponseTimer -= dt;
}
}
else
{
mDotTestBeginDelay -= dt;
}
if (mGameState == GameState.Game && !mWaitingForNextTrial)
{
// Trial is in progress
// Check to see if the trial has timed-out
mDotTrialCountdown -= dt;
if (mDotTrialCountdown < 0f)
{
// Ignore the coherence on the first trial
float lastCycleCoherence = mDotCoherencePercentage;
if (mFirstDotTrial)
{
lastCycleCoherence = 0f;
mRemainingTrials++;
}
else
{
// Display the damage animation
mCockpit.TakeDamage();
}
// Prep the next trial
if (--mRemainingTrials >= 0)
{
mFadeCoherence = mDotCoherencePercentage;
mTrialEnded = true;
// Did not react to the present motion
PESTAdjust(lastCycleCoherence, DotTrialResults.False);
mLateResponseTimer = (float)Settings.DotResponseWait;
}
// Don't count the first trial since it times out before the user can respond
// PestAdjust should have ignored the first trial since it thought coherence was 0
if (!mFirstDotTrial)
{
logger.Write((int)EventCode.MD_DotTrialExpire, EventCode.MD_DotTrialExpire.ToString());
}
mFirstDotTrial = false;
}
}
// Check to see if the user has responded (thus ending the trial)
if (!mPlayerLossed)
{
// For PEST responses:
// Correct direction when motion is present = +
// Incorrect direction when motion is present = -
// Any direction when no motion is present = +
// Correctly abstain when no motion is present = - (already handled at this point)
// TODO: Event based input
// NOTE: dot phase input
while (mInputHandler.HasEvent())
{
InputEvent e = mInputHandler.GetNextEvent();
switch ((EventCode)e.EventCode)
{
case EventCode.MD_DotTrialUserRespondLeft:
if (mGameState == GameState.Tutorial)
{
mLPressed = true;
}
// Log
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
if (mGameState != GameState.Tutorial)
{
if (mCockpit.IsStable())
{
if (mLateResponseTimer < 0f)
{
if (mHoldCoherenceTimer < 0f)
{
mFadeCoherence = mDotCoherencePercentage;
mTrialEnded = true;
// HUD
mCockpit.TurnLeft();
// Left arrow was pressed, so move onto the next trial
if (--mRemainingTrials > 0)
{
if (mDirection.X < 0f)
{
// Correct Identification
PESTAdjust(mDotCoherencePercentage, DotTrialResults.Correct);
mEnergySaved += ENERGY_GAINED;
}
else if (mDirection.X > 0f)
{
// Incorrect Identification
PESTAdjust(mDotCoherencePercentage, DotTrialResults.Incorrect);
mEnergySaved = Math.Max(0f, mEnergySaved - ENERGY_GAINED);
mCockpit.TakeDamage();
}
else
{
// Identified motion when there was none
PESTAdjust(mDotCoherencePercentage, DotTrialResults.False);
mEnergySaved = Math.Max(0f, mEnergySaved - ENERGY_GAINED);
mCockpit.TakeDamage();
}
}
}
}
else
{
// HUD
mCockpit.TurnLeft();
if (mOldDirection.X < 0f)
{
PESTAdjust(mOldCoherence, DotTrialResults.Correct);
mEnergySaved += ENERGY_GAINED;
}
else if (mOldDirection.X > 0f)
{
PESTAdjust(mOldCoherence, DotTrialResults.Incorrect);
mEnergySaved = Math.Max(0f, mEnergySaved - ENERGY_GAINED);
mCockpit.TakeDamage();
}
else
{
PESTAdjust(mOldCoherence, DotTrialResults.False);
mEnergySaved = Math.Max(0f, mEnergySaved - ENERGY_GAINED);
mCockpit.TakeDamage();
}
mLateResponseTimer = -1f;
}
}
}
break;
case EventCode.MD_DotTrialUserRespondRight:
// Log
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
if (mGameState != GameState.Tutorial)
{
if (mCockpit.IsStable())
{
if (mLateResponseTimer < 0f)
{
if (mHoldCoherenceTimer < 0f)
{
mFadeCoherence = mDotCoherencePercentage;
mTrialEnded = true;
// HUD
mCockpit.TurnRight();
// Right arrow was pressed, so move onto the next trial
if (--mRemainingTrials > 0)
{
if (mDirection.X > 0f)
{
PESTAdjust(mDotCoherencePercentage, DotTrialResults.Correct);
mEnergySaved += ENERGY_GAINED;
}
else if (mDirection.X < 0f)
{
PESTAdjust(mDotCoherencePercentage, DotTrialResults.Incorrect);
mEnergySaved = Math.Max(0f, mEnergySaved - ENERGY_GAINED);
mCockpit.TakeDamage();
}
else
{
PESTAdjust(mDotCoherencePercentage, DotTrialResults.False);
mEnergySaved = Math.Max(0f, mEnergySaved - ENERGY_GAINED);
mCockpit.TakeDamage();
}
}
}
}
else
{
// HUD
mCockpit.TurnRight();
if (mOldDirection.X > 0f)
{
PESTAdjust(mOldCoherence, DotTrialResults.Correct);
mEnergySaved += ENERGY_GAINED;
}
else if (mOldDirection.X < 0f)
{
PESTAdjust(mOldCoherence, DotTrialResults.Incorrect);
mEnergySaved = Math.Max(0f, mEnergySaved - ENERGY_GAINED);
mCockpit.TakeDamage();
}
else
{
PESTAdjust(mOldCoherence, DotTrialResults.False);
mEnergySaved = Math.Max(0f, mEnergySaved - ENERGY_GAINED);
mCockpit.TakeDamage();
}
mLateResponseTimer = -1f;
}
}
}
break;
case EventCode.MD_OpenConsole:
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
OpenConsole();
return;
case EventCode.MD_Pause:
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
OpenPauseMenu();
return;
default:
e.WriteToLog(logger, "IGNORE " + ((EventCode)e.EventCode).ToString());
return;
}
}
}
#endregion
} // dot test phase
else if (mCurrentPhase == MaritimeDefenderPhases.IdentityTest)
{
#region IdentityTest
if (!mInitialized && mReadyForID)
{
mTimerID = 0f;
mEnemyID = new Entity(mBogieTexturePath);
mEnemyID.LoadContent(Content);
mEnemyID.Size = new Vector3(
GraphicsDevice.Viewport.Width * .3f,
GraphicsDevice.Viewport.Height * .4f,
0f);
mFriendlyID = new Entity(mFriendlyTexturePath);
mFriendlyID.LoadContent(Content);
mFriendlyID.Size = new Vector3(
GraphicsDevice.Viewport.Width * .3f,
GraphicsDevice.Viewport.Height * .4f,
0f);
mArrowID = new Entity(@"General\UpArrow");
mArrowID.LoadContent(Content);
mArrowID.Position = new Vector3(GraphicsDevice.Viewport.Width * .50f, GraphicsDevice.Viewport.Height * .75f, 0f);
mArrowID.Size = new Vector3(
GraphicsDevice.Viewport.Width * .075f,
GraphicsDevice.Viewport.Width * .15f,
0f);
mArrowSelected = 0;
mArrowID.Rotation = 0;
mArrowAngularVel = 0;
// Randomly place the enemy on the left
mEnemyOnLeft = Random.Bool();
mEnemyID.Position = new Vector3(0f, GraphicsDevice.Viewport.Height * .50f, 0f);
mFriendlyID.Position = new Vector3(0f, GraphicsDevice.Viewport.Height * .50f, 0f);
if (mEnemyOnLeft)
{
mEnemyID.X = GraphicsDevice.Viewport.Width * .35f;
mFriendlyID.X = GraphicsDevice.Viewport.Width * .65f;
logger.Write((int)EventCode.MD_ShipIdentifierTestBegin, EventCode.MD_ShipIdentifierTestBegin + " Enemy=Left");
mPirateDeath.SetEnginePosition(new Vector3(GraphicsDevice.Viewport.Width * -.005f, 0, 10));
}
else
{
mFriendlyID.X = GraphicsDevice.Viewport.Width * .35f;
mEnemyID.X = GraphicsDevice.Viewport.Width * .65f;
logger.Write((int)EventCode.MD_ShipIdentifierTestBegin, EventCode.MD_ShipIdentifierTestBegin + " Enemy=Right");
mPirateDeath.SetEnginePosition(new Vector3(GraphicsDevice.Viewport.Width * .005f, 0, 10));
}
mInitialized = true;
mInputHandler.BindButton(Keys.OemTilde, Trigger.Activated, (int)EventCode.MD_OpenConsole);
mInputHandler.BindButton(Keys.Escape, Trigger.Activated, (int)EventCode.MD_Pause);
mInputHandler.BindButton(Keys.Left, Trigger.Activated, (int)EventCode.MD_ShipIdentifierSelectLeft);
mInputHandler.BindButton(Keys.Right, Trigger.Activated, (int)EventCode.MD_ShipIdentifierSelectRight);
mInputHandler.BindButton(Keys.Space, Trigger.Activated, (int)EventCode.MD_ShipIdentifierConfirmSelection);
mInputHandler.BindButton(Keys.Enter, Trigger.Activated, (int)EventCode.MD_ShipIdentifierConfirmSelection);
}
if (mInitialized)
{
while (mInputHandler.HasEvent())
{
InputEvent e = mInputHandler.GetNextEvent();
switch ((EventCode)e.EventCode)
{
case EventCode.MD_ShipIdentifierSelectLeft:
mArrowAngularVel = MathHelper.Pi * -3.5f;
mArrowSelected = -1;
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
break;
case EventCode.MD_ShipIdentifierSelectRight:
mArrowAngularVel = MathHelper.Pi * 3.5f;
mArrowSelected = 1;
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
break;
case EventCode.MD_ShipIdentifierConfirmSelection:
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
if ((mArrowSelected == -1 && mEnemyOnLeft) || (mArrowSelected == 1 && !mEnemyOnLeft))
{
// Correct ID
Message msg = new Message(
Content,
"Correct",
null, @"Fonts\dialogfont",
new Vector2(0f, GraphicsDevice.Viewport.Height * -0.30f),
new Vector2(0f, 120f),
Color.Blue,
1f,
3f,
true,
GraphicsDevice.Viewport);
msg.SpriteBatch = mSpriteBatch;
mMessages.Add(msg);
// Explode the bad guy
SoundManager.SoundManager.PlayEffect("Smash");
mPirateDeath.SetActive(true);
mStarField.SetActive(true);
logger.Write((int)EventCode.MD_ShipIdentifierTestEndSuccess, EventCode.MD_ShipIdentifierTestEndSuccess.ToString());
mInitialized = false;
mNewRoundWaitTimer = 4f;
CompletePhase();
}
else if (mArrowSelected != 0)
{
// Incorrect ID
logger.Write((int)EventCode.MD_ShipIdentifierTestEndFailure, EventCode.MD_ShipIdentifierTestEndFailure.ToString());
Message msg = new Message(
Content,
"Try Again",
null, @"Fonts\dialogfont",
new Vector2(0f, GraphicsDevice.Viewport.Height * -0.30f),
new Vector2(0f, 120f),
Color.Red,
1f,
3f,
true,
GraphicsDevice.Viewport);
msg.SpriteBatch = mSpriteBatch;
mMessages.Add(msg);
mInitialized = false;
}
break;
case EventCode.MD_OpenConsole:
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
OpenConsole();
return;
case EventCode.MD_Pause:
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
OpenPauseMenu();
return;
default:
e.WriteToLog(logger, "IGNORE " + ((EventCode)e.EventCode).ToString());
return;
}
}
// Move the arrow
mArrowID.Rotation += mArrowAngularVel * dt;
if (mArrowID.Rotation > ARROW_RIGHT_ROT)
{
mArrowID.Rotation = ARROW_RIGHT_ROT;
mArrowAngularVel = 0f;
}
if (mArrowID.Rotation < ARROW_LEFT_ROT)
{
mArrowID.Rotation = ARROW_LEFT_ROT;
mArrowAngularVel = 0f;
}
// Display a help message
if (mTimerID <= 0f)
{
mTimerID = 2f;
Message msg = new Message(
Content,
"Which one is the enemy?",
null, @"Fonts\dialogfont",
new Vector2(0, -GraphicsDevice.Viewport.Height * .25f),
Vector2.Zero,
Color.LimeGreen,
1f,
3f,
true,
GraphicsDevice.Viewport);
msg.SpriteBatch = mSpriteBatch;
mMessages.Add(msg);
msg = new Message(
Content,
"Press the left or right arrow key and then Enter",
null, @"Fonts\dialogfont",
new Vector2(0, GraphicsDevice.Viewport.Height * .375f),
new Vector2(0f, 0f),
Color.LimeGreen,
1f,
3f,
true,
GraphicsDevice.Viewport);
msg.SpriteBatch = mSpriteBatch;
mMessages.Add(msg);
}
}
mTimerID -= dt;
#endregion
} // Identity Test
else if (mCurrentPhase == MaritimeDefenderPhases.Shooter)
{
#region Shooter
// Reset necessary values to initial shooter position
if (!mInitialized && mNewRoundWaitTimer < 0f)
{
mWarping.SetActive(false);
if (mGameState == GameState.Game || mGameState == GameState.Tutorial)
{
// Setup logging parameters
mInputHandler.BindButton(Keys.OemTilde, Trigger.Activated, (int)EventCode.MD_OpenConsole);
mInputHandler.BindButton(Keys.Escape, Trigger.Activated, (int)EventCode.MD_Pause);
mInputHandler.BindButton(Keys.Left, Trigger.Activated, (int)EventCode.MD_ShooterActivateMovePort);
mInputHandler.BindButton(Keys.Left, Trigger.Deactivated, (int)EventCode.MD_ShooterCeaseMovePort);
mInputHandler.BindButton(Keys.Right, Trigger.Activated, (int)EventCode.MD_ShooterActivateMoveStarboard);
mInputHandler.BindButton(Keys.Right, Trigger.Deactivated, (int)EventCode.MD_ShooterCeaseMoveStarboard);
mInputHandler.BindButton(Keys.Up, Trigger.Activated, (int)EventCode.MD_ShooterActivateOpenWormholeBeam);
mInputHandler.BindButton(Keys.Up, Trigger.Deactivated, (int)EventCode.MD_ShooterCeaseOpenWormholeBeam);
mInputHandler.BindButton(Keys.Space, Trigger.Activated, (int)EventCode.MD_ShooterActivateFireWeapon);
mInputHandler.BindButton(Keys.Space, Trigger.Deactivated, (int)EventCode.MD_ShooterCeaseFireWeapon);
}
mMovingToPort = false;
mMovingToStarboard = false;
mFiring = false;
TryingToOpenWormhole = false;
// Set the gameboard's near and farplanes to that of the shooter phase
mGameBoard.MinZ = mMinShooterZ;
mGameBoard.MaxZ = mMaxShooterZ;
// Make the game go faster according to increased difficulty
mShooterSpeed = INITIAL_SHOOTER_SPEED + SHOOTER_SPEED_MODIFIER * mCurrentLevel;
// Setup initial ship and player wormhole values
SoundManager.SoundManager.PlayEffect("WarpIn");
if (mPlayerShip != null)
mPlayerShip.KillEngineFlare();
mPlayerShip = new CheetahFighter(@"MiniGames\Cheetah", .3F * mShipScale, .24F * mShipScale, .2F * mShipScale, this);
mPlayerShip.LoadContent(Content);
mPlayerShip.Visible = false;
mGameBoard.AddEntity(mPlayerShip);
mPlayerWormhole = new Wormhole(
mShipScale,
mShipScale,
mShipScale,
mPlayerShip.ArcPosition,
true);
mPlayerWormhole.LoadContent(Content);
mPlayerWormhole.X = mPlayerShip.X;
mPlayerWormhole.Y = mPlayerShip.Y;
mPlayerWormhole.Z = mPlayerShip.Z;
mPlayerWormhole.FadeIn(mWarpDelay * 0.125f);
mWarpCounter = mWarpDelay * 0.5f;
mUnitWormhole = null;
// Destroy any meteors in the way
foreach (Meteor meteor in mMeteors)
{
if (Entity.Collides2D(meteor, mPlayerWormhole))
DestroyMeteor(meteor, null);
}
// Inform the player what level they are on and how many lives they have
if (mGameState == GameState.Game)
{
Message msg = new Message(
Content,
"Level " + mCurrentLevel,
null, @"Fonts\dialogfont",
new Vector2(0f, -50f),
Vector2.Zero,
Color.LimeGreen,
1f,
8f,
true,
GraphicsDevice.Viewport);
msg.SpriteBatch = mSpriteBatch;
mMessages.Add(msg);
}
if (mGameState == GameState.Game)
{
Message msg = new Message(
Content,
" x " + mPlayerLives,
@"MiniGames\CheetahIcon", @"Fonts\dialogfont",
new Vector2(0f, 10f),
Vector2.Zero,
Color.Aquamarine,
1f,
8f,
true,
GraphicsDevice.Viewport);
msg.Scale = .4f;
msg.SpriteBatch = mSpriteBatch;
mMessages.Add(msg);
}
// Adjust the HUD
mCockpit.Visible = false;
mInitialized = true;
}
// Update the ship
if (mPlayerShip != null)
{
mPlayerShip.Update(gameTime);
UpdateHealthBarPosition();
mWormholeConnectionBeamCounter -= dt;
if (isFrozen)
{
mFreezeTimer -= dt;
if (mFreezeTimer < 0)
unFreezePlayer();
}
if (mGameState == GameState.Tutorial)
mDotShields = 1f;
// Test for death
if (mDotShields < 0)
{
GotoAfterlife();
}
}
// Update the unit's flotsam/powerup
if (mCollectible != null)
{
if (mCollectible.Alive)
{
// Update the collectible's position and test for collision
mCollectible.Update(gameTime, mPlayerShip);
if (mPlayerShip != null)
{
if (mCollectible.Z < mMinShooterZ)
{
mCollectible.Alive = false;
}
else if (mPlayerShip.Visible && Entity.Collides3D(mCollectible, mPlayerShip))
{
mCollectible.CollideWithPlayer(mPlayerShip);
}
}
}
else
{
// Collectible has hit the player, so remove it from the game
mGameBoard.RemoveEntity(mCollectible);
mCollectible = null;
mRemainingTrials--;
}
}
// Update the projectiles
foreach (PhotonTorpedo projectile in mProjectiles)
{
projectile.Update(gameTime);
if (projectile.Friendly)
{
if (mUnit != null && Entity.Collides3D(projectile, mUnit))
{
mUnit.GetHit(projectile.Damage);
projectile.Alive = false;
}
if (mCollectible != null && Entity.Collides3D(projectile, mCollectible))
{
mCollectible.GetHit(projectile.Damage);
projectile.Alive = false;
}
}
else
{
if (mPlayerShip != null && mPlayerShip.Visible && Entity.Collides3D(projectile, mPlayerShip))
{
ShooterShieldHit(projectile.Damage);
projectile.Alive = false;
}
}
}
// Update unit wormholes (there can only be one at a time)
if (mUnitWormhole != null)
{
mUnitWormhole.Update(gameTime);
}
mUnitWormholeCounter -= dt;
if (mUnitWormholeCounter < 0)
{
if (mUnitWormhole == null && (mCollectible == null || mCollectible.Visible == false) && mGameState == GameState.Game && mRemainingTrials > 0 && (mUnit == null || (mUnit != null && !mUnit.Alive)))
{
// It's time for a new wormhole
float tempArcPosition = MathHelper.TwoPi * Random.NextFloat();
mUnitWormhole = new Wormhole(
mShipScale * .9f,
mShipScale * .9f,
0f,
tempArcPosition,
false);
mUnitWormhole.LoadContent(Content);
Vector2 PositionFromOrigin = new Vector2((float)Math.Cos(tempArcPosition), (float)Math.Sin(tempArcPosition));
mUnitWormhole.X = .8F * PositionFromOrigin.X;
mUnitWormhole.Y = .8F * PositionFromOrigin.Y;
mUnitWormhole.Z = mMaxShooterZ - .1f;
mUnitWormhole.Visible = false;
mUnitIsWarping = false;
mUnitHasWarped = false;
mPlayerOpenedWormhole = false;
// Log the wormhole as soon as it is visible
logger.Write((int)EventCode.MD_ShooterPresentWormhole, EventCode.MD_ShooterPresentWormhole.ToString());
}
if (mUnitWormhole != null && !mUnitWormhole.Visible && !mUnitIsWarping && !mUnitHasWarped && mPlayerShip != null)
{
// Make sure the wormhole's area is clear of meteors before fading in (new meteors will not be spawned here)
bool areaIsClear = true;
const float scaler = 5f;
// Create a dummy collision box to make sure there is extra clearance for the path from the player to the wormhole
Meteor collider = new Meteor(mPlayerShip.Width * scaler, mPlayerShip.Height * scaler, mPlayerShip.Depth * scaler, 0f, 0f, 0f, Content);
collider.Position = new Vector3(mUnitWormhole.X, mUnitWormhole.Y, (mMaxShooterZ - mMinShooterZ) * .5f);
collider.Depth = mMaxShooterZ - mMinShooterZ;
// Test this dummy collision box agains meteors to see if the area is actually clear
foreach (Meteor meteor in mMeteors)
{
if (Entity.Collides3D(collider, meteor))
{
areaIsClear = false;
break;
}
}
if (areaIsClear)
{
mUnitWormhole.FadeIn(WARP_IN_TIME);
mUnitIsWarping = true;
mUnitWarpCounter = WARP_IN_TIME;
}
}
if (mUnitWormhole != null && mUnitWormhole.Visible && mUnitIsWarping && !mUnitHasWarped && mPlayerOpenedWormhole)
{
// See if it's time to warp a UFO out of a unit wormhole
mUnitWarpCounter -= dt;
if (mUnitWarpCounter < 0 || mForceFriendlySpawn || mForceBogieSpawn)
{
mUnitIsWarping = false;
mUnitHasWarped = true;
mCollectibleThrown = false;
mUnitWormhole.FadeOut(0.0001f);
// Warp in either a friend or foe with equal probability
if (!mForceBogieSpawn && (Random.Bool() || mForceFriendlySpawn))
{
// Warp in a friend
mUnit = new Friendly(mFriendlyTexturePath, .6F * mShipScale, .6F * mShipScale, .6F * mShipScale, (int)(SHIP_HEALTH * .20f), Friendly.PowerUpType.Resource, mShooterSpeed, this);
mUnit.LoadContent(Content);
((Friendly)mUnit).ArcPosition = mPlayerShip.ArcPosition;
mUnit.Z = mUnitWormhole.Z - .5f;
mUnit.Velocity = new Vector3(0, 0, mShooterSpeed * -1);
mGameBoard.AddEntity(mUnit);
// See if the tutorial forced this entity to spawn. If so, make it impossible to kill
if (mForceFriendlySpawn)
mUnit.HitPoints *= 100;
// Log the friend as soon as it is displayed
Rectangle proj = Space3D.Project(mUnit.X, mUnit.Y, mUnit.Z, 1f, 1f);
if (mGameState == GameState.Game)
{
//logger.Write((int)EventCode.MD_ShooterPresentFriendly, EventCode.MD_ShooterPresentFriendly.ToString());
//The logOnDraw setting immediately below replaces the commented-out logger call immediately above. This mechanism improves the correspondence between the time at which the event code is written to the parallel port and the time at which the stimulus actually appears on the display.
logOnDraw = EventCode.MD_ShooterPresentFriendly;
}
}
else
{
// Warp in a foe
mUnit = new SpacePirate(mBogieTexturePath, .6F * mShipScale, .6F * mShipScale, 0.1f,
(int)(SHIP_HEALTH + SHIP_HEALTH_MODIFIER * mCurrentLevel),
Math.Max(0.01f, ENEMY_FIRING_DELAY - (ENEMY_DELAY_MODIFIER * mCurrentLevel)), this);
mUnit.LoadContent(Content);
((SpacePirate)mUnit).ArcPosition = mPlayerShip.ArcPosition;
mUnit.Z = mUnitWormhole.Z - .5f;
mUnit.Velocity = new Vector3(0, 0, mShooterSpeed * -1);
mGameBoard.AddEntity(mUnit);
// See if the tutorial forced this entity to spawn. If so, make it really easy to kill
if (mForceBogieSpawn)
mUnit.HitPoints *= .5f;
// Log the foe as soon as it is displayed
Rectangle proj = Space3D.Project(mUnit.X, mUnit.Y, mUnit.Z, 1f, 1f);
if (mGameState == GameState.Game)
{
//logger.Write((int)EventCode.MD_ShooterPresentEnemy, EventCode.MD_ShooterPresentEnemy.ToString());
//The logOnDraw setting immediately below replaces the commented-out logger call immediately above. This mechanism improves the correspondence between the time at which the event code is written to the parallel port and the time at which the stimulus actually appears on the display.
logOnDraw = EventCode.MD_ShooterPresentEnemy;
}
}
}
}
if (mUnitWormhole != null && !mUnitWormhole.Visible && !mUnitIsWarping && mUnitHasWarped)
{
// The wormhole has spawned a UFO and faded out, so get rid of it
mUnitWormholeCounter = Random.NextFloat() * (mUnitWormholeMaxInterval - mUnitWormholeMinInterval) + mUnitWormholeMinInterval;
mUnitWormhole = null;
}
}
// Check for meteor collisions with the player, enemy ship or projectiles
foreach (Meteor meteor in mMeteors)
{
if (meteor.Alive)
{
if (mUnit != null)
{
// Since meteors fade out, it cannot be assumed that every visible meteor is alive
if (Entity.Collides3D(meteor, mUnit))
{
DestroyMeteor(meteor, null);
mUnit.GetHit(mMeteorDamage);
}
}
if (mPlayerShip != null)
{
if (Entity.Collides3D(meteor, mPlayerShip))
{
SoundManager.SoundManager.PlayEffect("Smash");
DestroyMeteor(meteor, mPlayerShip.Position);
ShooterShieldHit(mMeteorDamage);
}
}
foreach (PhotonTorpedo projectile in mProjectiles)
{
if (Entity.Collides3D(meteor, projectile))
{
// Player shot the meteor
SoundManager.SoundManager.PlayEffect("Smash");
projectile.Alive = false;
DestroyMeteor(meteor, projectile.Position);
// Check for lucky reward
float luck = Random.NextFloat();
if (luck < LUCKY_CHANCE)
{
int numCoins = Random.Next(1, 4);
float scaler = .075f;
// Check for big jackpot reward
if (luck < JACKPOT_CHANCE)
{
numCoins = Random.Next(7, 10);
scaler *= 1.5f;
}
// Spawn some reward money
for (int i = 0; i < numCoins; i++)
{
float scale = scaler * mShipScale * Random.NextFloat(.5f, .75f);
Flotsam coin = new Flotsam(Pickup.Credits, 10, @"General\Credits", scale, scale, mShipScale * .1f, this);
coin.LoadContent(Content);
coin.HitPoints = 100;
coin.Position = meteor.Position;
coin.Z += i * .1f;
Vector3 velocity = new Vector3(
Random.NextFloat(-1f, 1f),
Random.NextFloat(-1f, 1f),
0f);
velocity.Normalize();
velocity = Vector3.Multiply(velocity, mShooterSpeed * Random.NextFloat(.5f, 1f));
velocity.Z = -mShooterSpeed;
coin.Velocity = velocity;
coin.Tint = new Color(
(byte)(coin.Tint.R * Random.NextFloat(.9f, 1f)),
(byte)(coin.Tint.G * Random.NextFloat(.6f, 1f)),
(byte)(coin.Tint.B * Random.NextFloat(.7f, 1f)));
mJackpotCollectibles.Add(coin);
}
}
}
}
}
}
// Perform general game updates
if (mPlayerShip != null && mPlayerShip.Visible || mPlayerLossed)
{
// See if we need more meteors
mMeteorSpawnCounter -= 2f * Random.NextFloat() * Meteor.SPAWN_RATE * dt;
if (mGameState == GameState.Game && mMeteorSpawnCounter < 0)
{
mMeteorSpawnCounter += Meteor.SPAWN_RATE * Random.NextFloat(.75f, 1.25f);
// Randomize the meteor's appearance
float newMeteorSize = (Meteor.MIN_SIZE + (Meteor.MAX_SIZE - Meteor.MIN_SIZE) * Random.NextFloat());
// Spawn a new meteor in an area that is not close to a unit wormhole
Meteor newMeteor = new Meteor(newMeteorSize, newMeteorSize, newMeteorSize, mShooterSpeed, mMaxShooterZ, -mMaxShooterZ, Content);
if (mUnitWormhole != null)
{
bool areaIsClear = false;
float scaler = 2f;
Meteor collider = new Meteor(mUnitWormhole.Width * scaler, mUnitWormhole.Height * scaler, 5f, 0f, 0f, 0f, Content);
collider.Position = new Vector3(mUnitWormhole.X, mUnitWormhole.Y, (mMaxShooterZ - mMinShooterZ) * .5f);
collider.Depth = mMaxShooterZ - mMinShooterZ;
int failSafe = 0;
// No! Bad!
// TODO: Fix this
while (!areaIsClear && failSafe < 1000)
{
newMeteor = new Meteor(newMeteorSize, newMeteorSize, newMeteorSize, mShooterSpeed, mMaxShooterZ, -mMaxShooterZ, Content);
if (Entity.Collides3D(collider, newMeteor))
areaIsClear = false;
else
areaIsClear = true;
failSafe++;
}
}
newMeteor.FadeIn(4);
mMeteors.Add(newMeteor);
}
// React to player response
if (!mPlayerLossed && mPlayerShip != null)
{
// NOTE: Shooter Mode input
while (mInputHandler.HasEvent())
{
InputEvent e = mInputHandler.GetNextEvent();
switch ((EventCode)e.EventCode)
{
case EventCode.MD_ShooterActivateMovePort:
mMovingToPort = true;
if (mGameState == GameState.Tutorial)
{
mLPressed = true;
}
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
break;
case EventCode.MD_ShooterCeaseMovePort:
mMovingToPort = false;
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
break;
case EventCode.MD_ShooterActivateMoveStarboard:
mMovingToStarboard = true;
if (mGameState == GameState.Tutorial)
{
mRPressed = true;
}
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
break;
case EventCode.MD_ShooterCeaseMoveStarboard:
mMovingToStarboard = false;
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
break;
case EventCode.MD_ShooterActivateFireWeapon:
mFiring = true;
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
break;
case EventCode.MD_ShooterCeaseFireWeapon:
mFiring = false;
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
break;
case EventCode.MD_ShooterActivateOpenWormholeBeam:
TryingToOpenWormhole = true;
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
break;
case EventCode.MD_ShooterCeaseOpenWormholeBeam:
TryingToOpenWormhole = false;
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
break;
case EventCode.MD_OpenConsole:
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
OpenConsole();
return;
case EventCode.MD_Pause:
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
OpenPauseMenu();
return;
default:
e.WriteToLog(logger, "IGNORE " + ((EventCode)e.EventCode).ToString());
return;
}
}
// Move left
if (mMovingToPort && mAllowTurns && !isFrozen)
{
mPlayerShip.MoveLeft(dt);
}
// Move Right
if (mMovingToStarboard && mAllowTurns && !isFrozen)
{
mPlayerShip.MoveRight(dt);
}
// Fire weapons
if (mFiring && mAllowFire && mWeaponCooldownCounter < 0)
{
SoundManager.SoundManager.PlayEffect("Pew");
mWeaponCooldownCounter = mPlayerShip.WeaponCooldown;
mProjectiles.Add(mPlayerShip.FireTorpedo());
logger.Write((int)EventCode.MD_ShooterPlayerWeaponFired, EventCode.MD_ShooterPlayerWeaponFired.ToString());
}
mWeaponCooldownCounter -= dt;
// Connect a wormhole
if (TryingToOpenWormhole && mAllowConnect && !isFrozen)
{
if (mUnitWormhole != null &&
mUnitWormhole.Visible &&
!mPlayerOpenedWormhole &&
Entity.Collides2D(mUnitWormhole, mPlayerShip))
{
mPlayerShip.Lerp(mUnitWormhole.SpawnedArcPosition, .5f);
SoundManager.SoundManager.PlayEffect("Wherrrrr");
mPlayerOpenedWormhole = true;
mUnitWarpCounter = WARP_IN_TIME;
freezePlayer();
ShootSuccessfulWormholeBeam();
// Destroy any meteors that are currently in the way
float scaler = 7.5f;
Meteor collider = new Meteor(mPlayerShip.Width * scaler, mPlayerShip.Height * scaler, (mMaxShooterZ - mMinShooterZ), 0f, 0f, 0f, Content);
collider.Position = new Vector3(mPlayerShip.X, mPlayerShip.Y, (mMaxShooterZ - mMinShooterZ) * .5f);
foreach (Meteor meteor in mMeteors)
{
if (Entity.Collides3D(collider, meteor))
DestroyMeteor(meteor, null);
}
logger.Write((int)EventCode.MD_ShooterOpenWormholeSuccess, EventCode.MD_ShooterOpenWormholeSuccess.ToString());
mConnected = true;
}
else
{
ShootDudWormholeBeam();
}
}
}
}
#endregion
} // Shooter phase
else if (mCurrentPhase == MaritimeDefenderPhases.Boss)
{
#region Boss
mVictoryTimer -= dt;
mFlyAwayTimer -= dt;
#region Phase Initializer
// Reset necessary values to initial shooter position
if (!mInitialized && mNewRoundWaitTimer < 0f)
{
// Either make sure the ship looks right or respawn it
if (mPlayerShip != null)
{
// Make sure the ship looks right if it is alive
Vector3 pos = mPlayerShip.Position;
float rot = mPlayerShip.ArcPosition;
mPlayerShip.KillEngineFlare();
mGameBoard.RemoveEntity(mPlayerShip);
mPlayerShip = new CheetahFighter(@"MiniGames\Cheetah", .3F * mShipScale, .24F * mShipScale, .2F * mShipScale, this);
mPlayerShip.LoadContent(Content);
mPlayerShip.Visible = true;
mPlayerShip.Position = pos;
mPlayerShip.ArcPosition = rot;
mGameBoard.AddEntity(mPlayerShip);
}
else
{
// Setup initial ship and player wormhole values
SoundManager.SoundManager.PlayEffect("WarpIn");
if (mPlayerShip != null)
mPlayerShip.KillEngineFlare();
mPlayerShip = new CheetahFighter(@"MiniGames\Cheetah", .3F * mShipScale, .24F * mShipScale, .2F * mShipScale, this);
mPlayerShip.LoadContent(Content);
mPlayerShip.Visible = false;
mGameBoard.AddEntity(mPlayerShip);
mPlayerWormhole = new Wormhole(
mShipScale,
mShipScale,
mShipScale,
mPlayerShip.ArcPosition,
true);
mPlayerWormhole.LoadContent(Content);
mPlayerWormhole.X = mPlayerShip.X;
mPlayerWormhole.Y = mPlayerShip.Y;
mPlayerWormhole.Z = mPlayerShip.Z;
mPlayerWormhole.FadeIn(mWarpDelay * 0.125f);
mWarpCounter = mWarpDelay * 0.5f;
mUnitWormhole = null;
// Destroy any meteors in the way
foreach (Meteor meteor in mMeteors)
{
if (Entity.Collides2D(meteor, mPlayerWormhole))
DestroyMeteor(meteor, null);
}
// Inform the player of how many lives they have
if (mGameState == GameState.Game) {
Message msg = new Message(
Content,
" x " + mPlayerLives,
@"MiniGames\CheetahIcon", @"Fonts\dialogfont",
new Vector2(0f, GraphicsDevice.Viewport.Height * .22f),
Vector2.Zero,
Color.Aquamarine,
1f,
8f,
true,
GraphicsDevice.Viewport);
msg.Scale = .4f;
msg.SpriteBatch = mSpriteBatch;
mMessages.Add(msg);
}
}
mInitialized = true;
}
#endregion
#region Life Checks
// Update the player ship
if (mPlayerShip != null)
{
mPlayerShip.Update(gameTime);
UpdateHealthBarPosition();
}
// Update the boss
if (mBoss != null)
{
mBoss.Update(gameTime);
mBossMeter.Life1 = mBoss.ShieldLife;
mBossMeter.Life2 = mBoss.RocketPodLife;
mBossMeter.Life3 = mBoss.HullLife;
if (!mBoss.Alive)
{
mGameBoard.RemoveEntity(mBoss);
mBoss = null;
CurrentState = States.Victory;
Raise((GameScreen)CSharpHelper.DoSimpleFile(RootDirectory + @"\Content\Scripts\Victory.script", typeof(GameScreen)));
mFlyAwayTimer = 5f;
mVictoryTimer = 15f;
mAllowFire = false;
}
}
else
{
if (mPlayerShip != null && mFlyAwayTimer <= 0)
{
if (mPlayerShip.dZ == 0f)
mPlayerShip.Velocity = new Vector3(0, 0, 1f);
mPlayerShip.dZ *= 1.0075f;
}
if (mVictoryTimer <= 0 && mDoneWithEndingDialog)
CompletePhase();
}
// Test for player death
if (mDotShields < 0)
{
GotoAfterlife();
}
#endregion
#region Phase Collision
Entity mSpace3DCollider1 = new Entity();
Entity mSpace3DCollider2 = new Entity();
// Update the projectiles
foreach (PhotonTorpedo projectile in mProjectiles)
{
projectile.Update(gameTime);
mSpace3DCollider1.Position = projectile.Position;
mSpace3DCollider1.Size = projectile.Size;
if (projectile.Friendly && mBoss != null)
{
mSpace3DCollider2.Position = new Vector3(projectile.Position.X, projectile.Position.Y, mBoss.Position.Z);
mSpace3DCollider2.Size = mBoss.Size;
if (mBoss != null && Entity.Collides3D(projectile, mSpace3DCollider2))
{
if (mBoss.ShieldLife > 0)
{
mBoss.GetHit(projectile.Damage, mBoss.Position);
projectile.Alive = false;
}
else
{
// Test for a hit on one of the boss's rocket pods
List pods = mBoss.GetVulnerableRocketPods();
if (pods != null)
{
List potentialCollisions = new List();
foreach (RocketPod pod in pods)
{
mSpace3DCollider2.Position = new Vector3(pod.Position.X, pod.Position.Y, mBoss.Position.Z);
mSpace3DCollider2.Size = new Vector3(pod.Size.Y * 5f, pod.Size.Y * 5f, pod.Size.Z * 100f);
if (Entity.Collides3D(projectile, mSpace3DCollider2))
{
potentialCollisions.Add(pod);
}
}
// Find the BEST collision (in 2 Dimensions)
RocketPod closestPod = null;
float closestDistance = float.MaxValue;
foreach (RocketPod pod in potentialCollisions)
{
float thisDistance = Vector2.DistanceSquared(new Vector2(pod.Position.X, pod.Position.Y), new Vector2(projectile.Position.X, projectile.Position.Y));
if (thisDistance < closestDistance)
{
closestPod = pod;
closestDistance = thisDistance;
}
}
// Hit the pod or the ship
if (closestPod != null)
{
closestPod.GetHit(projectile.Damage, mBoss.Position);
projectile.Alive = false;
}
else
{
mBoss.GetHit(projectile.Damage, projectile.Position);
projectile.Alive = false;
}
}
}
}
}
else
{
if (mPlayerShip != null && Entity.Collides3D(mSpace3DCollider1, mPlayerShip))
{
ShooterShieldHit(projectile.Damage);
mInvulnerableTimer = mBossProjectileDamageCooldown;
}
}
}
#endregion
#region Phase Input
// React to player response
if (!mPlayerLossed && mPlayerShip != null)
{
// NOTE: Boss Mode input
while (mInputHandler.HasEvent())
{
InputEvent e = mInputHandler.GetNextEvent();
switch ((EventCode)e.EventCode)
{
case EventCode.MD_ShooterActivateMovePort:
mMovingToPort = true;
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
break;
case EventCode.MD_ShooterCeaseMovePort:
mMovingToPort = false;
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
break;
case EventCode.MD_ShooterActivateMoveStarboard:
mMovingToStarboard = true;
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
break;
case EventCode.MD_ShooterCeaseMoveStarboard:
mMovingToStarboard = false;
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
break;
case EventCode.MD_ShooterActivateFireWeapon:
mFiring = true;
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
break;
case EventCode.MD_ShooterCeaseFireWeapon:
mFiring = false;
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
break;
case EventCode.MD_OpenConsole:
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
OpenConsole();
return;
case EventCode.MD_Pause:
e.WriteToLog(logger, ((EventCode)e.EventCode).ToString());
OpenPauseMenu();
return;
default:
e.WriteToLog(logger, "IGNORE " + ((EventCode)e.EventCode).ToString());
return;
}
}
// Move left
if (mMovingToPort)
{
mPlayerShip.MoveLeft(dt);
}
// Move Right
if (mMovingToStarboard)
{
mPlayerShip.MoveRight(dt);
}
// Fire weapons
if (mFiring && mAllowFire && mWeaponCooldownCounter < 0)
{
SoundManager.SoundManager.PlayEffect("Pew");
mWeaponCooldownCounter = mPlayerShip.WeaponCooldown;
mProjectiles.Add(mPlayerShip.FireTorpedo());
}
mWeaponCooldownCounter -= dt;
}
#endregion
#endregion
} // Boss
else if (mCurrentPhase == MaritimeDefenderPhases.DotTest2ShooterTransition)
{
#region DotTest2Shooter
mInputHandler.ClearKeyBindings();
mMovingToPort = false;
mMovingToStarboard = false;
mFiring = false;
TryingToOpenWormhole = false;
// Start the warp effect
CSharpHelper.DoSimpleFile(RootDirectory + @"\Content\Scripts\LeaveWarp.script", this, "game");
mNewRoundWaitTimer = 6f;
// Trigger the scrolling stars
mStationaryDots.SetActive(false);
mCoherenceDots.SetActive(false);
mWarping.SetActive(true);
mStarField.SetActive(true);
mParticleManager.DrawOrder = DrawOrder + 2;
// Update transition variables
mCurrentLevel++;
mCurrentPhase = MaritimeDefenderPhases.Shooter;
mInitialized = false;
#endregion
} // Dot to Shooter transition phase
else if (mCurrentPhase == MaritimeDefenderPhases.Shooter2DotTestTransition)
{
#region Shooter2DotTest
mInitialized = false;
// If there is a new wormhole opening up, close it
mUnitWormhole = null;
// Update any remaining ships
if (mPlayerShip != null)
{
mPlayerShip.Update(gameTime);
UpdateHealthBarPosition();
}
if (mUnit != null)
mUnit.Update(gameTime);
// Update any remainng projectiles
foreach (PhotonTorpedo projectile in mProjectiles)
{
projectile.Update(gameTime);
}
// Make a wormhole for the player to jump into
if (mPlayerWormhole != null)
{
if (mPlayerWormhole.Visible == false)
{
// Build-up the engine flare
mPlayerShip.KillEngineFlare();
mWarpPrepare.SetEnginePosition(ConvertPosition(new Vector3(mPlayerShip.Position.X, mPlayerShip.Position.Y, 0.05f)));
mWarpPrepare.SetActive(true);
mPlayerWormhole = new Wormhole(
mShipScale,
mShipScale,
0F,
mPlayerShip.ArcPosition,
true);
mPlayerWormhole.LoadContent(Content);
mPlayerWormhole.X = mPlayerShip.X;
mPlayerWormhole.Y = mPlayerShip.Y;
mPlayerWormhole.Z = mMaxShooterZ;
mPlayerWormhole.FadeIn(mWarpDelay);
mPlayerJumpCountdown = mWarpDelay;
}
mPlayerWormhole.Update(gameTime);
mPlayerJumpCountdown -= dt;
}
Message msg = new Message(
Content,
"Initiating Subspace Jump",
null, @"Fonts\dialogfont",
new Vector2(0f, 50f),
Vector2.Zero,
Color.LimeGreen,
1f,
.1f,
false,
GraphicsDevice.Viewport);
msg.SpriteBatch = mSpriteBatch;
mMessages.Add(msg);
if (mPlayerJumpCountdown < 0)
{
if (mPlayerShip.Opacity == 1f)
{
// Jump the player through the wormhole
SoundManager.SoundManager.PlayEffect("WarpDrive");
mPlayerShip.FadeOut(2f);
JumpThroughWormhole();
mPlayerShip.Position = mPlayerWormhole.Position;
foreach (Meteor meteor in mMeteors)
DestroyMeteor(meteor, null);
// If there is still a unit visible (ie, the player destroyed the collectible on the last trial), remove it without blowing it up
if (mUnit != null)
{
mGameBoard.RemoveEntity(mUnit);
mUnit = null;
}
mDotTestBeginDelay = 3f;
}
else if (!mPlayerShip.Visible)
{
mWarpPrepare.SetActive(false);
mNewRoundWaitTimer = 4f;
mCurrentPhase = MaritimeDefenderPhases.DotTest;
mParticleManager.DrawOrder = DrawOrder - 1;
CreateAndLoadCockpit();
mCockpit.Visible = true;
mPlayerWormhole.Visible = false;
mInputHandler.ClearKeyBindings();
}
mStarField.SetActive(false);
}
#endregion
} // Shooter to Dot transition phase
else if (mCurrentPhase == MaritimeDefenderPhases.Shooter2BossTransition)
{
#region Shooter2Boss
// If there is a new wormhole opening up, close it
mUnitWormhole = null;
mPlayerWormhole = null;
// Update any remaining ships
mPlayerShip.Update(gameTime);
UpdateHealthBarPosition();
if (mUnit != null)
mUnit.Update(gameTime);
// Get the meteors out of the way of the player so he/she can focus on reading
foreach (Meteor meteor in mMeteors)
{
meteor.FadeOut(3f);
}
// Extend gameboard's farplane since the boss can go farther back than objects in the shooter phase
mGameBoard.MinZ = mMinShooterZ;
mGameBoard.MaxZ = mMaxShooterZ * 100f;
// Make the game go faster according to increased difficulty
mShooterSpeed = INITIAL_SHOOTER_SPEED + SHOOTER_SPEED_MODIFIER * mCurrentLevel;
// Inform the player that the boss is approacting
DisallowFireAndConnect();
CurrentState = States.Boss;
Raise((GameScreen)CSharpHelper.DoSimpleFile(RootDirectory + @"\Content\Scripts\BossEncounter.script", this, "game", typeof(GameScreen)));
Message msg = new Message(
Content,
"Approaching Enemy Bomber ",
null, @"Fonts\dialogfont",
new Vector2(0f, 50f),
Vector2.Zero,
Color.LimeGreen,
1f, 5f, true,
GraphicsDevice.Viewport);
msg.SpriteBatch = mSpriteBatch;
mMessages.Add(msg);
// Spawn the boss
mBoss = new Boss(this, 3f * mShipScale, 3f * mShipScale, 7f * mShipScale, mMaxShooterZ, mMaxShooterZ * 5f, BOSS_SHIELD, BOSS_HEALTH);
mGameBoard.AddEntity(mBoss);
// Adjust the HUD
mCockpit.Visible = false;
mBossMeter.Visible = true;
mPlayerHealthTimer = CheetahFighter.HEALTH_TIME;
mInitialized = false;
mCurrentPhase = MaritimeDefenderPhases.Boss;
#endregion
} // Shooter to Boss transition phase
} // GameState == Menu || Tutorial
}
private void unFreezePlayer()
{
mPlayerShip.ActivateEngineFlare();
isFrozen = false;
}
private void freezePlayer()
{
mFreezeTimer = PLAYER_FREEZE_TIME;
mPlayerShip.KillEngineFlare();
isFrozen = true;
}
private void CreateAndLoadCockpit()
{
mCockpit = new Cockpit(this, logger);
mCockpit.LoadContent(Content);
mCockpit.Visible = false;
mWidget2Ds.Add(mCockpit);
}
///
/// Draws all objects registered with the gameboard
///
public override void Draw(GameTime gameTime)
{
mSpriteBatch.Begin();
if ( mUnitWormhole != null )
{
mUnitWormhole.Draw(mSpriteBatch, mGameBoard);
}
if ( mPlayerWormhole != null )
{
mPlayerWormhole.Draw(mSpriteBatch, mGameBoard);
}
if (mGameState == GameState.Game || mGameState == GameState.Tutorial)
{
// Render the objects registered in the gameboard
mGameBoard.Render(mSpriteBatch);
foreach (Entity e in mEntities)
{
e.Draw(mSpriteBatch);
}
// Render ship identity test
if (mCurrentPhase == MaritimeDefenderPhases.IdentityTest)
{
if (mEnemyID != null && mFriendlyID != null && mArrowID != null)
{
mEnemyID.Draw(mSpriteBatch);
mFriendlyID.Draw(mSpriteBatch);
mArrowID.Draw(mSpriteBatch);
}
}
}
// Draw messages
foreach (Message msg in mMessages)
{
msg.Draw();
}
// Draw sprites to the spritebatch
foreach (StaticSprite sprite in mSprites)
{
sprite.Draw(mSpriteBatch);
}
// Draw 2D widgets
foreach (Widget2D widget in mWidget2Ds)
{
if (widget.mVisible)
{
widget.Draw(mSpriteBatch);
}
}
// Draw the cursor
if (mShowMousePointer)
{
mMouseLocation.X = mInputHandler.MouseLocation.X;
mMouseLocation.Y = mInputHandler.MouseLocation.Y;
mSpriteBatch.Draw(mMousePointer, mMouseLocation, Color.White);
}
mSpriteBatch.End();
// since this game explicity wants the particle effects to be drawn over everything, set it to
GraphicsDevice.RenderState.DepthBufferFunction = CompareFunction.Always;
base.Draw(gameTime);
if (logOnDraw != EventCode.Null)
{
logger.Write((int)logOnDraw, logOnDraw.ToString());
logOnDraw = EventCode.Null;
}
}
///
/// Performs necessary logic and visual effects for the player getting hit. If mInvulnerableTimer > 0, then player shields are unaffected.
///
public void ShooterShieldHit(int damage)
{
if (mInvulnerableTimer <= 0f)
{
// Projectiles actually collide with the player for two game cycles before getting removed from memory,
// so use this cheap hack to take away the correct amount of damage
mDotShields -= damage / 50f;
}
mPlayerHealthTimer = CheetahFighter.HEALTH_TIME;
mPlayerShip.GetHit();
logger.Write((int)EventCode.MD_ShooterPlayerGetsHit, EventCode.MD_ShooterPlayerGetsHit.ToString());
}
///
/// -----
/// Adjusts the difficulty of the next dot trial according to the BEST PEST algorithm. Random "Gimme Trials"
/// are built into this calculation to help the player feel better. Also flags that a new trial
/// should begin as soon as the HUD settles into its idle state.
/// -----
/// The 'Gimme Trial' functionality as been commented out.
///
private void PESTAdjust(double lastValue, DotTrialResults result)
{
// Save old values for "fading"
mOldCoherence = mDotCoherencePercentage;
mOldDirection = mDirection;
// PEST's range is from -1 to 1, so we must adjust the coherence range of 0 to 1 to fit the PEST's range
double adjustedLastValue = (lastValue * 2) - 1;
// Record the last values, but ignore it if the user correctly abstained from pressing anything
//if (!(lastValue == 0 && lastResponse == false))
switch(result){
case DotTrialResults.Correct:
mPester.Record(adjustedLastValue, true);
break;
case DotTrialResults.False:
mPester.Record(adjustedLastValue, false);
break;
case DotTrialResults.Incorrect: // Mistaken coherence counts double
if (mOldCoherence * 100 < Settings.mDotTrialIncorrectIgnoreThreshold) // Only if they are below the threshold
{
mPester.Record(adjustedLastValue, false);
mPester.Record(mPester.NextValue(), false);
}
break;
}
// Adjust trial length
mDotTrialCountdown = (float)(Settings.DotTrialLength + Random.NextDouble(Settings.DotTrialJitter));
// Wait for EEG to read activity for this coherence
mHoldCoherenceTimer = (float)(Settings.DotRefreshDelay + Random.NextDouble(Settings.DotRefreshDelayJitter));
// Is this next trial a coherent one?
// Pick a new direction if this is a coherent trial
if (!Settings.HaveNonCoherentTrials || Random.Bool())
{
// Map from PEST's range to the coherence range
mDotCoherencePercentage = Math.Min(1f, (float)(mPester.NextValue() + 1) * .5f);
mDirection.X = Random.Sign();
mDirection.Y = 0f;
mDirection.Z = 0f;
}
else
{
mDotCoherencePercentage = 0f;
mDirection.X = 0f;
mDirection.Y = 0f;
mDirection.Z = 0f;
}
mWaitingForNextTrial = true;
}
///
/// Kills the meteor and spawns an explosion at its previous location
///
private void DestroyMeteor(Meteor meteor, Vector3? hitFromPosition)
{
meteor.Alive = false;
if (hitFromPosition.HasValue)
{
mMeteorHit.SetEnginePosition(ConvertPosition(hitFromPosition.Value));
}
else
{
mMeteorHit.SetEnginePosition(ConvertPosition(meteor.TargetPosition));
}
mMeteorHit.SetActive(true);
logger.Write((int)EventCode.MD_ShooterMeteorExplosion, EventCode.MD_ShooterMeteorExplosion.ToString());
}
///
/// Spawns particles and sounds to make it look like the player crashed in the cockpit
///
private void CrashInSubspace()
{
mPlayerShip.DestroyPlayer();
}
///
/// Draws a trail of particle effects from the player to the unit wormhole
///
private void ShootSuccessfulWormholeBeam()
{
mWormholeConnectionBeamCounter = WORMHOLE_CONNECTION_BEAM_COOLDOWN;
mSuccessBeam.SetEnginePosition(ConvertPosition(new Vector3(mUnitWormhole.X, mUnitWormhole.Y, 0.2f)));
mSuccessBeam.SetActive(true);
}
///
/// Draws a trail of particle effects from the player to the center of the screen, appearing to trail off to infinity
///
private void ShootDudWormholeBeam()
{
if (mWormholeConnectionBeamCounter > 0)
{
return;
}
mWormholeConnectionBeamCounter = WORMHOLE_CONNECTION_BEAM_COOLDOWN;
mFailBeam.SetEnginePosition(ConvertPosition(mPlayerShip.Position));
mFailBeam.SetActive(true);
}
///
/// Draws a trail of ship particle effects from the player position to the player wormhole, as if the player just enterd warp drive
///
private void JumpThroughWormhole()
{
mWarpPrepare.SetActive(false);
mWarpDrive.SetEnginePosition(ConvertPosition(mPlayerShip.Position));
mWarpDrive.SetActive(true);
}
///
/// Moves the Shooter phase's health bar to stay next to the ship
///
private void UpdateHealthBarPosition()
{
Rectangle playerScreenPosition = Space3D.Project(
mPlayerShip.Position.X,
mPlayerShip.Position.Y,
mPlayerShip.Position.Z,
mPlayerShip.Width,
mPlayerShip.Height);
mPlayerHealthBar.X = playerScreenPosition.X;
mPlayerHealthBar.Y = playerScreenPosition.Y;
if (playerScreenPosition.Y < GraphicsDevice.Viewport.Height / 3f)
{
mPlayerHealthBar.Y += playerScreenPosition.Height >> 1;
mPlayerHealthAboveLastTime = false;
}
else if (playerScreenPosition.Y > GraphicsDevice.Viewport.Height * (2f / 3f))
{
mPlayerHealthBar.Y -= playerScreenPosition.Height >> 1;
mPlayerHealthAboveLastTime = true;
}
else if (mPlayerHealthAboveLastTime)
{
mPlayerHealthBar.Y -= playerScreenPosition.Height >> 1;
}
else
{
mPlayerHealthBar.Y += playerScreenPosition.Height >> 1;
}
}
///
/// Adds a new graphical message item to the game
///
/// Text to be displayed
/// Location of the image
/// Location of the font to use
/// Position offset from center of screen
/// Speed and direction in which the object moves
/// Color of the message display
/// Opacity of the message display
/// How long the message displays for
/// Whether the message fades in or out
public void AddNewMessage(string text, string imagePath, string fontPath, Vector2 offsetFromCenter, Vector2 velocity,
Color color, float opacity, float displayDuration, bool fade)
{
Message msg = new Message(
Content,
text,
imagePath,
fontPath,
offsetFromCenter,
velocity,
color,
opacity,
displayDuration,
fade,
GraphicsDevice.Viewport);
msg.SpriteBatch = mSpriteBatch;
mMessages.Add(msg);
}
///
/// Converts a position used in SpriteBatch to the one used with the perspective 3D camera
///
/// Position in sprite batch coordinates
/// The 3D vector in the perspective 3D camera space
public static Vector3 ConvertPosition(Vector3 originalPos)
{
return new Vector3(originalPos.X * 5f, originalPos.Y * 5f, originalPos.Z * 4f);
}
public override void Reinitialize()
{
switch (CurrentState)
{
case States.Defeat:
mDoneWithEndingDialog = true;
break;
case States.Boss:
mBoss.Start();
AllowFire();
break;
case States.Victory:
mDoneWithEndingDialog = true;
break;
case States.Console:
logger.Write((int)EventCode.MD_Unpause, EventCode.MD_Unpause.ToString());
mInputHandler.Enable();
Enabled = true;
mParticleManager.Enabled = true;
break;
case States.Pause:
logger.Write((int)EventCode.MD_Unpause, EventCode.MD_Unpause.ToString());
mInputHandler.Enable();
Enabled = true;
mParticleManager.Enabled = true;
break;
case States.ShipIdentDisplay:
DialogDone = true;
break;
}
CurrentState = States.Normal;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
mPester.Dispose();
if (mGameBoard != null)
{
mGameBoard.Dispose();
}
mGameBoard = null;
if (mSpriteBatch != null)
{
mSpriteBatch.Dispose();
}
}
base.Dispose(disposing);
}
// Functions:
public void RestartGame()
{
RemoveParticles();
// Remove entities
mEntities.Clear();
mEnemyID = null;
mFriendlyID = null;
mArrowID = null;
// Dispose components
if (mPester != null)
mPester.Dispose();
if (mGameBoard != null)
mGameBoard.Dispose();
if (mSpriteBatch != null)
mSpriteBatch.Dispose();
// Reset
Initialize();
LoadContent();
StartGame();
}
public void ReturnToTitleScreen()
{
RemoveParticles();
Done();
}
public void Quit()
{
RemoveParticles();
Done();
Done();
}
private void RemoveParticles()
{
mPirateDeath.SetActive(false);
mMeteorHit.SetActive(false);
mStarField.SetActive(false);
mWarping.SetActive(false);
mFailBeam.SetActive(false);
mSuccessBeam.SetActive(false);
mWarpDrive.SetActive(false);
mWarpPrepare.SetActive(false);
mStationaryDots.SetActive(false);
mCoherenceDots.SetActive(false);
mPirateDeath.ToDestory = true;
mMeteorHit.ToDestory = true;
mStarField.ToDestory = true;
mWarping.ToDestory = true;
mFailBeam.ToDestory = true;
mSuccessBeam.ToDestory = true;
mWarpDrive.ToDestory = true;
mWarpPrepare.ToDestory = true;
mStationaryDots.ToDestory = true;
mCoherenceDots.ToDestory = true;
mParticleManager.Dispose();
}
private void OpenPauseMenu()
{
CurrentState = States.Pause;
logger.Write((int)EventCode.MD_Pause, EventCode.MD_Pause.ToString());
mInputHandler.Disable();
Enabled = false;
mParticleManager.Enabled = false;
Raise(new PauseScreen(this));
}
private void OpenConsole()
{
CurrentState = States.Console;
logger.Write((int)EventCode.MD_Pause, EventCode.MD_Pause.ToString());
mInputHandler.Disable();
Enabled = false;
mParticleManager.Enabled = false;
Raise(new CSharpConsoleScreen(this));
}
internal void StartGame()
{
mPhaseQueue = Settings.PhaseQueue;
// Start the first phase
MaritimeDefenderTest curTest = mPhaseQueue.Dequeue();
mCurrentPhase = curTest.PhaseName;
mRemainingTrials = curTest.Trials;
switch (mCurrentPhase)
{
case MaritimeDefenderPhases.DotTest:
logger.Write((int)EventCode.MD_DotPhaseBegin, EventCode.MD_DotPhaseBegin.ToString());
break;
case MaritimeDefenderPhases.Shooter:
logger.Write((int)EventCode.MD_ShooterPhaseBegin, EventCode.MD_ShooterPhaseBegin.ToString());
break;
}
CurrentState = States.ShipIdentDisplay;
Raise((GameScreen)CSharpHelper.DoSimpleFile(RootDirectory + @"\Content\Scripts\ShipIdentifier.script", this, "game", typeof(GameScreen)));
DialogDone = false;
mGameState = GameState.Game;
mShowMousePointer = false;
}
internal void StartTutorial()
{
// Begin the tutorial
mGameState = GameState.Tutorial;
Raise((GameScreen)CSharpHelper.DoSimpleFile(RootDirectory + @"\Content\Scripts\Tutorial.script", this, "game", typeof(GameScreen)));
}
///
/// Called within the tutorial script. Clears old key bindings and binds dot coherence bindings.
///
public void SetDotTutorialBindings()
{
mInputHandler.ClearKeyBindings();
mInputHandler.BindButton(Keys.OemTilde, Trigger.Activated, (int)EventCode.MD_OpenConsole);
mInputHandler.BindButton(Keys.Escape, Trigger.Activated, (int)EventCode.MD_Pause);
mInputHandler.BindButton(Keys.Left, Trigger.Activated, (int)EventCode.MD_DotTrialUserRespondLeft);
mInputHandler.BindButton(Keys.Right, Trigger.Activated, (int)EventCode.MD_DotTrialUserRespondRight);
}
}
}