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