/* * StellarProspectorGameScreen.cs * Authors: Mike DeMauro, Brian Murphy * 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 tAC_Engine.Graphics.Entities; using TACParticleEngine; using Util; using Random = Util.Random; using tAC_Engine.GUI; namespace StellarProspector { /// /// Phases of StellarProspector /// public enum Phases { /// /// First phase: Central and peripheral stimulus without distractors or sound cues for /// whenever the early detection cue changes /// One, /// /// Second phase: Central and peripheral stimulus with distractors nut no sound cues for /// whenever the early detection cue changes /// Two, /// /// Third phase: Central and peripheral stimulus with distractors and sound cues for /// whenever the early detection cue changes /// Three, /// /// The tutorial mode /// Tutorial } /// /// This is the main type for your game /// public class StellarProspectorGameScreen : GameScreen { #region Constants // Constant for the amount of desired frames per second private const int FRAMES_PER_SECOND = 60; // Constant for the width of the sector frame private const int SECTOR_FRAME_WIDTH = 323; // Constant for the height of the sector frame private const int SECTOR_FRAME_HEIGHT = 284; // Constant for the number of sector frames private const int NUM_SECTOR_FRAMES = 5; // Constant for the radius of the inner semi-circle area private const int INNER_RADIUS = 110; // Constant for the number of flickering sectors in the outer areas private const int NUM_SECTORS = 4; // Constant for how fast the energy corrodes while the central stimulus is active private const float CORRODE_SPEED = 0.3f; // Constant for how long it takes before another response can be accepted after any response input private const float COOLDOWN_TIME = 1f; // Constant for how long it takes for the drain to reoccur during the tutorial private const float DRAIN_DELAY = 0.01f; // Constant for the number of kinds of distractors private const int NUM_OF_DISTRACTORS = 4; // Constant value for the amount of the max progress needed to get to phase 2 internal const float PHASE_TWO_PERCENT = 0.33f; // Constant value for the amount of the max progress needed to get to phase 3 internal const float PHASE_THREE_PERCENT = 0.66f; #endregion #region Fields // General mini game objects private Logger mLogger; private InputHandler inputHandler; // Dialog objects private readonly List dialogs = new List(); private DialogComponent mCurrentDialog; // Sprite batch for drawing private SpriteBatch spriteBatch; // Camera for drawing private Camera mActiveCamera; // Particle Effect variables private ParticleManager mParticleManager; // Various graphical components private EntitySprite mSector1; private EntitySprite mSector2; private EntitySprite mSector3; private EntitySprite mSector4; private EntitySprite mInterior; private EntitySprite mCenterPanel; private EntitySprite mCenterResource; private EntitySprite mCenterOverlay; private Texture2D mCenterStaticTexture1; private Texture2D mCenterStaticTexture2; private EntityStimulusCentral mCenterStatic; private EntityStimulusPeripheral mStimulusPeripheral; private EntitySpawnable mCurrentStimulus; private EntityProgressBar mProgressBar; private EntitySprite mCue; private EntityDistractor[] mDistractors; // Current phase of the mini gmae private Phases mPhase; // Position of the central stimulus spawn zone private Vector2 bottomCenter; // Various time counters private float mGrabDelay; private float mDrainCounter; private float mCooldownCounter; private float mCorrodeCounter; // Values used for graphical positioning private float mCameraWidth, mCameraHeight; // Booleans to keep track of various states private bool mPlaySound; private bool mAutoGrab; private bool mProgressDrain; private bool mGrabberPressed; private bool mPaused; private bool mTutorialPeripheral; private bool mTutorialCentral; // Duration of time between flickers in terms of frames with 60 frames per second private int mSector1FramesPerCycle; private int mSector2FramesPerCycle; private int mSector3FramesPerCycle; private int mSector4FramesPerCycle; private int mCenterFramesPerCycle; // Amount of frames in a row that the sector is flickered on private int mSector1OnFrames; private int mSector2OnFrames; private int mSector3OnFrames; private int mSector4OnFrames; private int mCenterOnFrames; // Amount of frames in a row that the sector is flickered off private int mSector1OffFrames; private int mSector2OffFrames; private int mSector3OffFrames; private int mSector4OffFrames; private int mCenterOffFrames; // Degree of percent intensity on the flickering while on. 1.0 denotes 100%. private double mSector1Intensity; private double mSector2Intensity; private double mSector3Intensity; private double mSector4Intensity; private static double mCenterIntensity; // Used to keep track of when one of the 60 frames a second has passed. private double mFrameCounter; // Integers for storing current sectors for the stimuli and early detection cue private int sectorNum; private int cueStimuli; // The maximum radius from the outer edge of the early detection region to // the outside edge of where peripheral stimulus and distractors spawn private int outerRadius; // Frame counter for flickering effect private int frameCount; // The index of the current distractor private int mCurrentDistractor; // Holds the maximum intensity of all the sectors private static double mMaxIntensity; #endregion #region Properties /// /// Gets the color intensity of the center sector /// public static float CenterIntensity { get { return (float)mCenterIntensity; } } /// /// Gets the maximum intensity between all of the sectors /// public static float MaxIntensity { get { return (float)mMaxIntensity; } } /// /// Whether or not the progress bar is currently being drained or not /// public bool ProgressDrain { get { return mProgressDrain; } } /// /// Whether or not the button corresponding to a peripheral stimulus /// response has been pressed /// public bool TutorialPeripheral { get { return mTutorialPeripheral; } set { mTutorialPeripheral = value; } } /// /// Whether or not the button corresponding to a central stimulus /// response has been pressed /// public bool TutorialCentral { get { return mTutorialCentral; } set { mTutorialCentral = value; } } /// /// Whether or not the button corresponding to a peripheral stimulus /// response has been pressed /// public bool GrabberPressed { get { return mGrabberPressed; } set { mGrabberPressed = value; } } #endregion #region Creation /// /// Stellar Prospector's main game constructor /// /// Which phase the game starts in, usually either one or tutorial public StellarProspectorGameScreen(Phases phase) { mPhase = phase; mDistractors = new EntityDistractor[NUM_OF_DISTRACTORS]; } #endregion #region Initialization /// /// Allows the game to perform any initialization it needs to before starting to run. /// This is where it can query for any required services and load any non-graphic /// related content. Calling base.Initialize will enumerate through any components /// and initialize them as well. /// public override void Initialize() { // Logger setup mLogger = GetLogger(); mLogger.Initialize(); //Game.IsFixedTimeStep = true; //true by default GraphicsDeviceManager.SynchronizeWithVerticalRetrace = true; // Input setup inputHandler = GetInputHandler(); inputHandler.Initialize(); inputHandler.BindButton(Keys.Up, Trigger.Activated, (int)EventCodes.PeripheralStimulusResponsePressed); inputHandler.BindButton(Keys.Down, Trigger.Activated, (int)EventCodes.CentralStimulusResponsePressed); inputHandler.BindButton(Keys.Escape, Trigger.Activated, (int)EventCodes.Pause); inputHandler.BindButton(Keys.Space, Trigger.Activated, (int)EventCodes.Menu_Select); // Camera setup mActiveCamera = new Perspective3DCamera(new Vector3(0, 0, -5), Vector3.Zero, Vector3.Up, MathHelper.PiOver2, 1, 1, 100); // Particle engine setup mParticleManager = new ParticleManager(Content, mActiveCamera, null, new Viewport()); AddComponent(mParticleManager); // Creation of distractor for (int i = NUM_OF_DISTRACTORS - 1; i >= 0; --i) { mDistractors[i] = new EntityDistractor(Content, @"Textures\distractor" + (i + 1) + "b"); mDistractors[i].Visible = false; mDistractors[i].BlendMode = SpriteBlendMode.AlphaBlend; mDistractors[i].Enabled = false; AddComponent(mDistractors[i]); } // Creation of peripheral stimulus mStimulusPeripheral = new EntityStimulusPeripheral(Content, @"Textures\meteorite"); mStimulusPeripheral.ParticleManager = mParticleManager; mStimulusPeripheral.Visible = false; mStimulusPeripheral.BlendMode = SpriteBlendMode.AlphaBlend; AddComponent(mStimulusPeripheral); // Creation of early detection cue mCue = new EntitySprite(Content, @"Textures\cue"); mCue.BlendMode = SpriteBlendMode.AlphaBlend; AddComponent(mCue); // Creation of flickering sectors mSector1 = new EntitySprite(Content, @"Textures\sector1_static"); mSector2 = new EntitySprite(Content, @"Textures\sector2_static"); mSector3 = new EntitySprite(Content, @"Textures\sector3_static"); mSector4 = new EntitySprite(Content, @"Textures\sector4_static"); mSector1.BlendMode = SpriteBlendMode.Additive; mSector2.BlendMode = SpriteBlendMode.Additive; mSector3.BlendMode = SpriteBlendMode.Additive; mSector4.BlendMode = SpriteBlendMode.Additive; mSector2.Rotation = -MathHelper.PiOver4; mSector3.Rotation = -MathHelper.PiOver2; mSector4.Rotation = -MathHelper.PiOver4 - MathHelper.PiOver2; AddComponent(mSector1); AddComponent(mSector2); AddComponent(mSector3); AddComponent(mSector4); // Creation of various entities mInterior = new EntitySprite(Content, @"Textures\interior"); mInterior.BlendMode = SpriteBlendMode.AlphaBlend; AddComponent(mInterior); mCenterPanel = new EntitySprite(Content, @"Textures\centerPanel"); mCenterPanel.BlendMode = SpriteBlendMode.AlphaBlend; AddComponent(mCenterPanel); mCenterOverlay = new EntitySprite(Content, @"Textures\centerOverlay"); mCenterOverlay.BlendMode = SpriteBlendMode.AlphaBlend; AddComponent(mCenterOverlay); mProgressBar = new EntityProgressBar(Content, @"Textures\progressBar"); mProgressBar.BlendMode = SpriteBlendMode.AlphaBlend; AddComponent(mProgressBar); mCenterStatic = new EntityStimulusCentral(Content, @"Textures\centerStatic"); mCenterStatic.BlendMode = SpriteBlendMode.Additive; mCenterStatic.ParticleManager = mParticleManager; AddComponent(mCenterStatic); mCenterResource = new EntitySprite(Content, @"Textures\meteorite"); mCenterResource.BlendMode = SpriteBlendMode.AlphaBlend; AddComponent(mCenterResource); // Setting of various draw orders mSector1.DrawOrder = DrawOrder; mSector2.DrawOrder = DrawOrder; mSector3.DrawOrder = DrawOrder; mSector4.DrawOrder = DrawOrder; mParticleManager.DrawOrder = DrawOrder + 1; mStimulusPeripheral.TractorBeam.DrawOrder = DrawOrder + 1; mStimulusPeripheral.FadeEffect.DrawOrder = DrawOrder + 1; for (int i = NUM_OF_DISTRACTORS - 1; i >= 0; --i) { mDistractors[i].DrawOrder = DrawOrder + 2; } mStimulusPeripheral.DrawOrder = DrawOrder + 2; mCenterPanel.DrawOrder = DrawOrder + 3; mInterior.DrawOrder = DrawOrder + 3; mCue.DrawOrder = DrawOrder + 4; mProgressBar.DrawOrder = DrawOrder + 4; mCenterStatic.DrawOrder = DrawOrder + 5; mCenterResource.DrawOrder = DrawOrder + 5; mCenterStatic.ImplosionEffect.DrawOrder = DrawOrder + 6; mCenterStatic.ExplosionEffect.DrawOrder = DrawOrder + 5; mCenterOverlay.DrawOrder = DrawOrder + 7; AutoClear(DrawOrder - 1); mCue.UpdateOrder = UpdateOrder + 1; mSector1.UpdateOrder = UpdateOrder + 1; mSector2.UpdateOrder = UpdateOrder + 1; mSector3.UpdateOrder = UpdateOrder + 1; mSector4.UpdateOrder = UpdateOrder + 1; mInterior.UpdateOrder = UpdateOrder + 1; mCenterStatic.UpdateOrder = UpdateOrder + 1; mCenterPanel.UpdateOrder = UpdateOrder + 1; for (int i = NUM_OF_DISTRACTORS - 1; i >= 0; --i) { mDistractors[i].UpdateOrder = UpdateOrder + 2; } mStimulusPeripheral.UpdateOrder = UpdateOrder + 2; base.Initialize(); // Setting of graphical positioning parameters mCameraHeight = -10f / GraphicsDevice.Viewport.Height; mCameraWidth = -10f / GraphicsDevice.Viewport.Width; mStimulusPeripheral.CameraHeight = mCameraHeight; mStimulusPeripheral.CameraWidth = mCameraWidth; mCenterStatic.CameraHeight = mCameraHeight; mCenterStatic.CameraWidth = mCameraWidth; // Initialize the flickering sectors information if (Settings.UseFlickering) { mSector1FramesPerCycle = (int)(FRAMES_PER_SECOND / Settings.Sector1Hertz); mSector2FramesPerCycle = (int)(FRAMES_PER_SECOND / Settings.Sector2Hertz); mSector3FramesPerCycle = (int)(FRAMES_PER_SECOND / Settings.Sector3Hertz); mSector4FramesPerCycle = (int)(FRAMES_PER_SECOND / Settings.Sector4Hertz); mCenterFramesPerCycle = (int)(FRAMES_PER_SECOND / Settings.CenterHertz); if (Settings.AutoCalculateFlickering) { mSector1OnFrames = mSector1FramesPerCycle >> 1; mSector2OnFrames = mSector2FramesPerCycle >> 1; mSector3OnFrames = mSector3FramesPerCycle >> 1; mSector4OnFrames = mSector4FramesPerCycle >> 1; mCenterOnFrames = mCenterFramesPerCycle >> 1; mSector1OffFrames = (mSector1FramesPerCycle + 1) >> 1; mSector2OffFrames = (mSector2FramesPerCycle + 1) >> 1; mSector3OffFrames = (mSector3FramesPerCycle + 1) >> 1; mSector4OffFrames = (mSector4FramesPerCycle + 1) >> 1; mCenterOffFrames = (mCenterFramesPerCycle + 1) >> 1; if (mSector1OnFrames != 0) mSector1Intensity = mSector1OffFrames / mSector1OnFrames; else mSector1Intensity = 1; if (mSector2OnFrames != 0) mSector2Intensity = mSector2OffFrames / mSector2OnFrames; else mSector2Intensity = 1; if (mSector3OnFrames != 0) mSector3Intensity = mSector3OffFrames / mSector3OnFrames; else mSector3Intensity = 1; if (mSector4OnFrames != 0) mSector4Intensity = mSector4OffFrames / mSector4OnFrames; else mSector4Intensity = 1; if (mCenterOnFrames != 0) mCenterIntensity = mCenterOffFrames / mCenterOnFrames; else mCenterIntensity = 1; } else { mSector1OnFrames = Settings.Sector1OnFrames; mSector2OnFrames = Settings.Sector2OnFrames; mSector3OnFrames = Settings.Sector3OnFrames; mSector4OnFrames = Settings.Sector4OnFrames; mCenterOnFrames = Settings.CenterOnFrames; mSector1OffFrames = Settings.Sector1OffFrames; mSector2OffFrames = Settings.Sector2OffFrames; mSector3OffFrames = Settings.Sector3OffFrames; mSector4OffFrames = Settings.Sector4OffFrames; mCenterOffFrames = Settings.CenterOffFrames; mSector1Intensity = Settings.Sector1Intensity; mSector2Intensity = Settings.Sector2Intensity; mSector3Intensity = Settings.Sector3Intensity; mSector4Intensity = Settings.Sector4Intensity; mCenterIntensity = Settings.CenterIntensity; mSector1FramesPerCycle = mSector1OnFrames + mSector1OffFrames; mSector2FramesPerCycle = mSector2OnFrames + mSector2OffFrames; mSector3FramesPerCycle = mSector3OnFrames + mSector3OffFrames; mSector4FramesPerCycle = mSector4OnFrames + mSector4OffFrames; mCenterFramesPerCycle = mCenterOnFrames + mCenterOffFrames; } } else // NOT USING FLICKERING, SET INTENSITY { mSector1Intensity = Settings.Sector1Intensity; mSector2Intensity = Settings.Sector2Intensity; mSector3Intensity = Settings.Sector3Intensity; mSector4Intensity = Settings.Sector4Intensity; mCenterIntensity = Settings.CenterIntensity; } mMaxIntensity = mSector1Intensity; if (mSector2Intensity > mMaxIntensity) { mMaxIntensity = mSector2Intensity; } if (mSector3Intensity > mMaxIntensity) { mMaxIntensity = mSector3Intensity; } if (mSector4Intensity > mMaxIntensity) { mMaxIntensity = mSector4Intensity; } if (mCenterIntensity > mMaxIntensity) { mMaxIntensity = mCenterIntensity; } mSector1.Color = new Color(Color.White.ToVector4() / (float)mMaxIntensity * (float)mSector1Intensity); mSector2.Color = new Color(Color.White.ToVector4() / (float)mMaxIntensity * (float)mSector2Intensity); mSector3.Color = new Color(Color.White.ToVector4() / (float)mMaxIntensity * (float)mSector3Intensity); mSector4.Color = new Color(Color.White.ToVector4() / (float)mMaxIntensity * (float)mSector4Intensity); mCenterStatic.Color = new Color(mCenterStatic.Color.ToVector4() / (float)mMaxIntensity * (float)mCenterIntensity); #if DEBUG ShowFPS(); #endif // Initial gameplay settings mProgressBar.Progress = 0; mProgressBar.MaxProgress = Settings.MaxProgress; setPhase(mPhase); } /// /// Reinitialize will be called on the screen after a screen which was raised /// above it is done. /// public override void Reinitialize() { base.Reinitialize(); inputHandler.Enable(); } #endregion #region Management /// /// LoadContent will be called once per game and is the place to load /// all of your content. /// protected override void LoadContent() { mParticleManager.Viewport = GraphicsDevice.Viewport; // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); mParticleManager.SpriteBatch = spriteBatch; mStimulusPeripheral.SpriteBatch = spriteBatch; mCue.SpriteBatch = spriteBatch; mSector1.SpriteBatch = spriteBatch; mSector2.SpriteBatch = spriteBatch; mSector3.SpriteBatch = spriteBatch; mSector4.SpriteBatch = spriteBatch; mInterior.SpriteBatch = spriteBatch; mCenterPanel.SpriteBatch = spriteBatch; mCenterStatic.SpriteBatch = spriteBatch; for (int i = NUM_OF_DISTRACTORS - 1; i >= 0; --i) { mDistractors[i].SpriteBatch = spriteBatch; } mProgressBar.SpriteBatch = spriteBatch; mCenterResource.SpriteBatch = spriteBatch; mCenterOverlay.SpriteBatch = spriteBatch; bottomCenter = new Vector2(mInterior.Texture.Width >> 1, mInterior.Texture.Height); // Progress bar settings of graphical dependent parameters mProgressBar.Position = new Vector2(bottomCenter.X - (mProgressBar.Texture.Width >> 1), bottomCenter.Y); mProgressBar.RotationOrigin = new Vector2(mProgressBar.Texture.Width >> 1, 0); // Flickering sector setting of graphical dependent parameters Vector2 sectorOrigin = new Vector2(-INNER_RADIUS * (float)Math.Cos(MathHelper.PiOver4), mSector1.Texture.Height); mSector1.RotationOrigin = sectorOrigin; mSector2.RotationOrigin = sectorOrigin; mSector3.RotationOrigin = sectorOrigin; mSector4.RotationOrigin = sectorOrigin; mSector1.Position = bottomCenter; mSector2.Position = bottomCenter; mSector3.Position = bottomCenter; mSector4.Position = bottomCenter; // Early detection cue setting of graphical dependent parameters mCue.RotationOrigin = new Vector2(0, mCue.Texture.Height); mCue.Position = bottomCenter; // Central stimulus setting of graphical dependent parameters mCenterPanel.Position = bottomCenter - new Vector2(mCenterPanel.Texture.Width >> 1, mCenterPanel.Texture.Height >> 1); mCenterResource.Position = bottomCenter - new Vector2(mCenterResource.Texture.Width >> 1, mCenterResource.Texture.Height >> 1); mCenterOverlay.Position = bottomCenter - new Vector2(mCenterOverlay.Texture.Width >> 1, mCenterOverlay.Texture.Height >> 1); mCenterStatic.RotationOrigin = mCenterStatic.TextureCenter; mCenterStaticTexture1 = Content.Load(@"Textures\centerStatic"); mCenterStaticTexture2 = Content.Load(@"Textures\centerStaticInverse"); mCenterStatic.Position = bottomCenter; mCenterStatic.MaxLifeTime = Settings.StimulusLifeMax; mCenterStatic.MaxWaitTime = Settings.StimulusWaitMax; mCenterStatic.MinWaitTime = Settings.StimulusWaitMin; mCenterStatic.Logger = mLogger; outerRadius = (int)bottomCenter.X; // Peripheral stimulus setting of graphical dependent parameters mStimulusPeripheral.Origin = bottomCenter; mStimulusPeripheral.MinSpawnRadius = INNER_RADIUS; mStimulusPeripheral.MaxSpawnRadius = outerRadius; mStimulusPeripheral.MaxLifeTime = Settings.StimulusLifeMax; mStimulusPeripheral.MaxWaitTime = Settings.StimulusWaitMax; mStimulusPeripheral.MinWaitTime = Settings.StimulusWaitMin; mStimulusPeripheral.NumSectors = NUM_SECTORS; mStimulusPeripheral.SectorAngle = MathHelper.PiOver4; mStimulusPeripheral.Logger = mLogger; // Distractor setting of graphical dependent parameters for (int i = NUM_OF_DISTRACTORS - 1; i >= 0; --i) { mDistractors[i].Origin = bottomCenter; mDistractors[i].MinSpawnRadius = INNER_RADIUS; mDistractors[i].MaxSpawnRadius = outerRadius; mDistractors[i].MaxLifeTime = Settings.DistractorLifeMax; mDistractors[i].MaxWaitTime = Settings.DistractorWaitMax; mDistractors[i].WaitTime = Random.NextDouble(Settings.DistractorWaitMin, Settings.DistractorWaitMax); mDistractors[i].NumSectors = NUM_SECTORS; mDistractors[i].SectorAngle = MathHelper.PiOver4; mDistractors[i].Logger = mLogger; } if (ExtendedDisplayIdentificationData.HasProfile) { Util.Settings.PhysicalScreenWidth = ExtendedDisplayIdentificationData.HorizontalSize; Util.Settings.PhysicalScreenHeight = ExtendedDisplayIdentificationData.VerticalSize; } } /// /// This will clean up all the necessary components on disposal of this class /// /// Whether or not this class is being disposed protected override void Dispose(bool disposing) { if (disposing) { spriteBatch.Dispose(); //if (mLogger != null) //{ // mLogger.Dispose(); //} } base.Dispose(disposing); } #endregion #region Update /// /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// /// Provides a snapshot of timing values. public override void Update(GameTime gameTime) { //Handle Input while (inputHandler.HasEvent()) { InputEvent inputEvent = inputHandler.GetNextEvent(); switch ((EventCodes)inputEvent.EventCode) { case EventCodes.PeripheralStimulusResponsePressed: if (!mPaused) { if (mPhase != Phases.Tutorial) { inputEvent.WriteToLog(mLogger, "SP_PeripheralStimulusResponsePressed" + " PeripheralStimulus=" + ((mCurrentStimulus is EntityStimulusPeripheral && mCurrentStimulus.State == EntitySpawnable.SpawnableState.Alive) ? "" : "in") + "active" + " CentralStimulus=" + ((mCurrentStimulus is EntityStimulusCentral && mCurrentStimulus.State == EntitySpawnable.SpawnableState.Alive) ? "" : "in") + "active" + " Gather=" + ((mCooldownCounter <= 0f) ? "" : "in") + "active"); } else { inputEvent.WriteToLog(mLogger, "IGNORE SP_Tutorial_PeripheralStimulusResponsePressed"); } if (mCooldownCounter <= 0f) { if (mCurrentStimulus is EntityStimulusPeripheral && mCurrentStimulus.State == EntitySpawnable.SpawnableState.Alive) { ((EntityStimulusPeripheral)(mCurrentStimulus)).SetTractorBeam(); mCurrentStimulus.ProgressToCollect = (int)(Settings.PeripheralProgress * (mCurrentStimulus.LifeTime / mCurrentStimulus.MaxLifeTime)); if (mPhase == Phases.Tutorial) { mTutorialPeripheral = false; mAutoGrab = false; } } else { SoundManager.SoundManager.PlayEffect("Wrong"); mGrabberPressed = true; mProgressBar.Progress -= Settings.ProgressLostPerMiss; } mCooldownCounter = COOLDOWN_TIME; } } break; case EventCodes.CentralStimulusResponsePressed: if (!mPaused) { if (mPhase != Phases.Tutorial) { inputEvent.WriteToLog(mLogger, "SP_CentralStimulusResponsePressed" + " PeripheralStimulus=" + ((mCurrentStimulus is EntityStimulusPeripheral && mCurrentStimulus.State == EntitySpawnable.SpawnableState.Alive) ? "" : "in") + "active" + " CentralStimulus=" + ((mCurrentStimulus is EntityStimulusCentral && mCurrentStimulus.State == EntitySpawnable.SpawnableState.Alive) ? "" : "in") + "active" + " Gather=" + ((mCooldownCounter <= 0f) ? "" : "in") + "active"); } else { inputEvent.WriteToLog(mLogger, "IGNORE SP_Tutorial_CentralStimulusResponsePressed"); } if (mCooldownCounter <= 0f) { if (mCurrentStimulus is EntityStimulusCentral && mCurrentStimulus.State == EntitySpawnable.SpawnableState.Alive) { ((EntityStimulusCentral)mCurrentStimulus).Explode(); mCenterResource.Visible = false; mCorrodeCounter = 0f; if (mPhase == Phases.Tutorial) { mTutorialCentral = false; } } else { SoundManager.SoundManager.PlayEffect("Wrong"); mProgressBar.Progress -= Settings.ProgressLostPerMiss; } mCooldownCounter = COOLDOWN_TIME; } } break; case EventCodes.Pause: if (mPhase != Phases.Tutorial) { SetPaused(true); inputHandler.Disable(); Raise(new PauseMenu(this, mLogger)); inputEvent.WriteToLog(mLogger, "SP_Pause"); } else { inputEvent.WriteToLog(mLogger, "IGNORE SP_Tutorial_Pause"); Done(); } break; case EventCodes.Menu_Select: if (mCurrentDialog != null) { inputEvent.WriteToLog(mLogger, "SP_MenuSelectButtonPressed"); mCurrentDialog.Next(); } else { inputEvent.WriteToLog(mLogger, "IGNORE SP_Tutorial_DialogAdvance"); } break; } } if (mCooldownCounter > 0) { mCooldownCounter -= (float)gameTime.ElapsedGameTime.TotalSeconds; } if (mCurrentStimulus is EntityStimulusCentral && mCurrentStimulus.State == EntitySpawnable.SpawnableState.Alive) { mCorrodeCounter += (float)gameTime.ElapsedGameTime.TotalSeconds; if (mCorrodeCounter > CORRODE_SPEED) { --mProgressBar.Progress; mCorrodeCounter -= CORRODE_SPEED; } } if (!mPaused) { if (mPhase != Phases.Tutorial) { // Update Progress if (mCurrentStimulus.State == EntitySpawnable.SpawnableState.Dead) { mProgressBar.Progress += mCurrentStimulus.ProgressToCollect; mCurrentStimulus.ProgressToCollect = 0; } // Update Phase if (mProgressBar.Progress >= Settings.MaxProgress * PHASE_TWO_PERCENT && mPhase == Phases.One) { setPhase(Phases.Two); } else if (mProgressBar.Progress >= Settings.MaxProgress * PHASE_THREE_PERCENT && mPhase == Phases.Two) { setPhase(Phases.Three); } else if (mProgressBar.Progress >= Settings.MaxProgress) { endGame(); } // Update Stimulus if (mCurrentStimulus.State == EntitySpawnable.SpawnableState.Waiting && mCurrentStimulus.WaitTime <= 0) { mCurrentStimulus.Spawn(sectorNum, true); foreach (EntityDistractor distractor in mDistractors) { if (distractor.State == EntitySpawnable.SpawnableState.Waiting) { distractor.Wait(); } } if (mCurrentStimulus is EntityStimulusPeripheral) { mLogger.Write((int)EventCodes.PeripheralStimulusSpawn, "SP_PeripheralStimulusSpawn" + " Sector=" + mCurrentStimulus.Sector + " X=" + (mCurrentStimulus.X - bottomCenter.X) + " Y=" + ((mCurrentStimulus.Y - bottomCenter.Y) * -1) + " ThetaRadians=" + mCurrentStimulus.Theta + " RadialDistanceInPixels=" + mCurrentStimulus.RadialDistance + " ScreenDistanceInCm=" + Util.Settings.PhysicalScreenDistance + " RhoRadians=" + mCurrentStimulus.Rho(Math.Sqrt((GraphicsDevice.Viewport.Height * GraphicsDevice.Viewport.Height) + (GraphicsDevice.Viewport.Width * GraphicsDevice.Viewport.Width))) + " AzimuthPhiRadians=" + mCurrentStimulus.AzimuthPhi(GraphicsDevice.Viewport.Width, bottomCenter.X) + " ElevationLambdaRadians=" + mCurrentStimulus.ElevationLambda(GraphicsDevice.Viewport.Height, bottomCenter.Y)); } else { mLogger.Write((int)EventCodes.CentralStimulusSpawn, "SP_CentralStimulusSpawn"); } } else if (mCurrentStimulus.State == EntitySpawnable.SpawnableState.Dead) { generateStimulus(); } // Update Distractor(s) if (mDistractors[mCurrentDistractor].Enabled) { if (mDistractors[mCurrentDistractor].State == EntitySpawnable.SpawnableState.Waiting && mDistractors[mCurrentDistractor].WaitTime <= 0) { mCurrentDistractor = Random.Next(NUM_OF_DISTRACTORS); mDistractors[mCurrentDistractor].Spawn(Random.Next(mDistractors[mCurrentDistractor].NumSectors), true); if (mStimulusPeripheral.State == EntitySpawnable.SpawnableState.Waiting) { mStimulusPeripheral.Wait(); } mLogger.Write((int)EventCodes.DistractorSpawn, "SP_DistractorSpawn" + " Sector=" + mDistractors[mCurrentDistractor].Sector + " X=" + (mDistractors[mCurrentDistractor].X - bottomCenter.X) + " Y=" + ((mDistractors[mCurrentDistractor].Y - bottomCenter.Y) * -1) + " ThetaRadians=" + mDistractors[mCurrentDistractor].Theta + " RadialDistanceInPixels=" + mDistractors[mCurrentDistractor].RadialDistance + " ScreenDistanceInCm=" + Util.Settings.PhysicalScreenDistance + " RhoRadians=" + mDistractors[mCurrentDistractor].Rho(Math.Sqrt((GraphicsDevice.Viewport.Height * GraphicsDevice.Viewport.Height) + (GraphicsDevice.Viewport.Width * GraphicsDevice.Viewport.Width))) + " AzimuthPhiRadians=" + mDistractors[mCurrentDistractor].AzimuthPhi(GraphicsDevice.Viewport.Width, bottomCenter.X) + " ElevationLambdaRadians=" + mDistractors[mCurrentDistractor].ElevationLambda(GraphicsDevice.Viewport.Height, bottomCenter.Y)); } else if (mDistractors[mCurrentDistractor].State == EntitySpawnable.SpawnableState.Dead) { mDistractors[mCurrentDistractor].Wait(); } } } else { if (mCurrentStimulus != null) { mCurrentStimulus.LifeTime = mCurrentStimulus.MaxLifeTime; } if (mTutorialPeripheral) { mCurrentStimulus = mStimulusPeripheral; // Update Stimulus if (mCurrentStimulus.State == EntitySpawnable.SpawnableState.Waiting && mCurrentStimulus.WaitTime <= 0) { mCurrentStimulus.Spawn(Random.Next(NUM_SECTORS), true); } else if (mCurrentStimulus.State == EntitySpawnable.SpawnableState.Dead) { mStimulusPeripheral.Wait(); } } else if (mTutorialCentral) { // Update Stimulus if (mCurrentStimulus.State == EntitySpawnable.SpawnableState.Waiting && mCurrentStimulus.WaitTime <= 0) { mCurrentStimulus.Spawn(Random.Next(NUM_SECTOR_FRAMES), true); } else if (mCurrentStimulus.State == EntitySpawnable.SpawnableState.Dead) { mCurrentStimulus = mCenterStatic; mCurrentStimulus.Wait(); } } if (mAutoGrab) { if (mGrabDelay <= 0f) { mAutoGrab = false; if (mCurrentStimulus is EntityStimulusPeripheral) { ((EntityStimulusPeripheral)(mCurrentStimulus)).SetTractorBeam(); mCurrentStimulus.ProgressToCollect = (int)(Settings.PeripheralProgress * (mCurrentStimulus.LifeTime / mCurrentStimulus.MaxLifeTime)); } } else { mGrabDelay -= (float)gameTime.ElapsedGameTime.TotalSeconds; } } if (mProgressDrain) { if (mDrainCounter <= 0f) { mProgressBar.Progress -= Settings.CentralStimulusProgressDrain; mDrainCounter = DRAIN_DELAY; } else { mDrainCounter -= (float)gameTime.ElapsedGameTime.TotalSeconds; } if (mProgressBar.Progress <= 0) { mProgressBar.Progress = 0; mProgressDrain = false; } } } SoundManager.SoundManager.Update(); } if(Settings.UseFlickering) updateFlickering(gameTime); base.Update(gameTime); } /// /// Updates each sector to be either visible or not based on time in relation to FPS in order /// to give the various flashing effects we want /// /// Current elapsed time in game protected void updateFlickering(GameTime gameTime) { mFrameCounter += gameTime.ElapsedGameTime.TotalSeconds; while (mFrameCounter > 1.0 / FRAMES_PER_SECOND) { ++frameCount; mSector1.Visible = frameCount % mSector1FramesPerCycle < mSector1OnFrames; mSector2.Visible = frameCount % mSector2FramesPerCycle < mSector2OnFrames; mSector3.Visible = frameCount % mSector3FramesPerCycle < mSector3OnFrames; mSector4.Visible = frameCount % mSector4FramesPerCycle < mSector4OnFrames; mCenterStatic.Texture = frameCount % mCenterFramesPerCycle < mCenterOnFrames ? mCenterStaticTexture1 : mCenterStaticTexture2; mFrameCounter -= 1.0 / FRAMES_PER_SECOND; if (frameCount > 60) { frameCount = 0; } } } #endregion #region Render /// /// This is called when the game should draw itself. /// /// Provides a snapshot of timing values. public override void Draw(GameTime gameTime) { base.Draw(gameTime); } #endregion #region Gamestate Management /// /// Resets the game to phase one with all in-game parameters reset to what they /// would normally be at start. /// public void ResetGame() { if (mCurrentStimulus != null) mCurrentStimulus.Die(); setPhase(Phases.One); mProgressBar.Progress = 0; mProgressBar.MaxProgress = Settings.MaxProgress; } /// /// Sets the game to the beginning of a phase. /// /// The phase to set public void setPhase(Phases newPhase) { mPhase = newPhase; if (mCurrentDialog != null) { mCurrentDialog.Dispose(); } switch (mPhase) { case Phases.One: SetPaused(true); dialogs.Clear(); dialogs.Add(new Dialog("CDR NOVAH", "The iron gatherer has been damaged by phosphorus. Until it's repaired, you'll have to collect the ore manually.", "Portraits/CDRNovah", Corner.BottomRight, 0f, true)); dialogs.Add(new Dialog("CDR NOVAH", "Remember, keep your eyes on the centre so that you can eject any bad ore before it damages the processor more. Good luck.", "Portraits/CDRNovah", Corner.BottomRight, 0f, true)); mCurrentDialog = new DialogComponent(dialogs, Content); mCurrentDialog.DrawOrder = DrawOrder + 15; AddComponent(mCurrentDialog); mCurrentDialog.VisibleChanged += dialogVisibleChanged; for (int i = NUM_OF_DISTRACTORS - 1; i >= 0; --i) { mDistractors[i].Enabled = false; mDistractors[i].Visible = false; mDistractors[i].State = EntitySpawnable.SpawnableState.Dead; } mLogger.Write((int)EventCodes.Phase1Begin, "SP_Phase1Begin"); break; case Phases.Two: SetPaused(true); dialogs.Clear(); dialogs.Add(new Dialog("CDR NOVAH", "There are pieces of space debris floating around. Try to ignore them while I make repairs. Keep up the good work.", "Portraits/CDRNovah", Corner.BottomRight, 0f, true)); mCurrentDialog = new DialogComponent(dialogs, Content); mCurrentDialog.DrawOrder = DrawOrder + 15; AddComponent(mCurrentDialog); mCurrentDialog.VisibleChanged += dialogVisibleChanged; for (int i = NUM_OF_DISTRACTORS - 1; i >= 0; --i) { mDistractors[i].Enabled = true; } mLogger.Write((int)EventCodes.Phase2Begin, "SP_Phase2Begin"); break; case Phases.Three: SetPaused(true); dialogs.Clear(); dialogs.Add(new Dialog("CDR NOVAH", "I've got the radar alarm working. We're almost through.", "Portraits/CDRNovah", Corner.BottomRight, 0f, true)); mCurrentDialog = new DialogComponent(dialogs, Content); mCurrentDialog.DrawOrder = DrawOrder + 15; AddComponent(mCurrentDialog); mCurrentDialog.VisibleChanged += dialogVisibleChanged; for (int i = NUM_OF_DISTRACTORS - 1; i >= 0; --i) { mDistractors[i].Enabled = true; } mPlaySound = true; mLogger.Write((int)EventCodes.Phase3Begin, "SP_Phase3Begin"); break; case Phases.Tutorial: mCue.Visible = false; Raise((GameScreen)CSharpHelper.DoSimpleFile(RootDirectory + @"\Content\Scripts\Tutorial.script", this, "game", typeof(GameScreen))); break; } generateStimulus(); } /// /// Pauses or unpauses all stimuli and related objects /// /// Whether or not to pause public void SetPaused(bool paused) { mPaused = paused; if (mPaused) { for (int i = NUM_OF_DISTRACTORS - 1; i >= 0; --i) { mDistractors[i].Enabled = false; } } else { if (mPhase == Phases.Two || mPhase == Phases.Three) { for (int i = NUM_OF_DISTRACTORS - 1; i >= 0; --i) { mDistractors[i].Enabled = true; } } } mInterior.Enabled = !paused; mCenterStatic.Enabled = !paused; mCue.Enabled = !paused; mStimulusPeripheral.Enabled = !paused; mParticleManager.Enabled = !paused; } /// /// Ends the game. /// public void endGame() { dialogs.Clear(); dialogs.Add(new Dialog("CDR NOVAH", "The gatherer has been repaired. Great job out there.", "Portraits/CDRNovah", Corner.BottomRight, 0f, false)); if (mCurrentDialog != null) { mCurrentDialog.Dispose(); } mCurrentDialog = new DialogComponent(dialogs, Content); mCurrentDialog.DrawOrder = DrawOrder + 15; AddComponent(mCurrentDialog); mCurrentDialog.VisibleChanged += endDialogVisibleChanged; SetPaused(true); mLogger.Write((int)EventCodes.GameEnd, "SP_End"); } #endregion #region General Game Methods /// /// Selects a new sector to cue /// private void chooseNewSector() { if (mPlaySound) { // Sound may need to be changed. SoundManager.SoundManager.PlayEffect("Cue"); } int newCueSector = Random.Next(NUM_SECTORS - 1); if (newCueSector >= sectorNum) { ++newCueSector; } sectorNum = newCueSector; mCue.Rotation = -MathHelper.PiOver4 * (sectorNum); cueStimuli = Random.Next(Settings.StimuliPerCueMin, Settings.StimuliPerCueMax + 1); if (mPhase != Phases.Tutorial) { mLogger.Write((int)EventCodes.CueChange, "SP_CueChange Sector=" + newCueSector + " Sound=" + (mPlaySound ? "true" : "false")); } } /// /// Randomly chooses between a central (33% chance) and peripheral (66% chance) stimulus /// protected void generateStimulus() { // Cue a new sector if the current cue is depleted if (cueStimuli <= 0) { chooseNewSector(); } if (Random.Next(-1, 5) <= 0) { mCurrentStimulus = mCenterStatic; } else { mCurrentStimulus = mStimulusPeripheral; } mCurrentStimulus.Wait(); mCenterResource.Visible = true; --cueStimuli; } /// /// Called when Enable property of this screen is changed. All components of /// this screen will be enabled or disabled along with the screen. /// /// The sender of the event /// Arguments associated with the event protected override void OnEnabledChanged(object sender, EventArgs args) { if (Enabled) { inputHandler.Enable(); if (mPhase == Phases.Two || mPhase == Phases.Three) { for (int i = NUM_OF_DISTRACTORS - 1; i >= 0; --i) { mDistractors[i].Enabled = true; } } } else { inputHandler.Disable(); for (int i = NUM_OF_DISTRACTORS - 1; i >= 0; --i) { mDistractors[i].Enabled = true; } } mSector1.Enabled = Enabled; mSector2.Enabled = Enabled; mSector3.Enabled = Enabled; mSector4.Enabled = Enabled; mInterior.Enabled = Enabled; mCenterStatic.Enabled = Enabled; mCue.Enabled = Enabled; mStimulusPeripheral.Enabled = Enabled; mParticleManager.Enabled = Enabled; if (mCurrentDialog != null) { mCurrentDialog.Enabled = Enabled; } base.OnEnabledChanged(sender, args); } /// /// Sets the progress to the given value /// /// The value to set the progress bar to public void SetProgress(int progress) { mProgressBar.Progress = progress; } #endregion #region Dialog Based Events /// /// If visibility of dialog has changed, stimuli and other related items will be paused/unpaused /// /// The dialog object whose visibilty has changed /// The associated arguments of the event private void dialogVisibleChanged(object sender, EventArgs e) { DialogComponent dialog = sender as DialogComponent; if (dialog != null) { SetPaused(dialog.Visible); } } /// /// If visibility of end game dialog has changed, end game menu will be displayed /// /// The dialog object whose visibilty has changed /// The associated arguments of the event private void endDialogVisibleChanged(object sender, EventArgs e) { if (sender is DialogComponent) { // Score game progress MiniGameInfo.HasPlayed = true; MiniGameInfo.ScoreValue += 5000; // Lock the controls, relying on the score display to unlock them inputHandler.Disable(); // 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("Completion Bonus: ", "" + 5000 + " points"); scores.Add("Total Score: ", "" + MiniGameInfo.ScoreValue + " points"); // Set the title screen.DisplayScores("Stellar Prospector", scores); } } #endregion #region Tutorial Specific Methods /// /// Based on the tutorial section number given, does the appropriate logging /// *Note* This will need to be updated if ever the tutorial is changed /// /// The number of the tutorial section completed public void TutorialEventSelect(int sectionNum) { switch (sectionNum) { case 0: // Start of the tutorial. Beginning Section 1. mLogger.Write((int)EventCodes.TutorialStart, "SP_TutorialStart Event=Dialogue"); break; case 1: // End of section 1: 1 dialogue. Beginning Section 2. mLogger.Write((int)EventCodes.Section1, "SP_Tutorial1End Event=Dialogue"); break; case 2: // End of section 2: 1 dialogue and peripheral response key press. Beginning Section 3. mLogger.Write((int)EventCodes.Section2, "SP_Tutorial2End Event=PeripheralResponse Event=Dialogue Event=SectorCue"); break; case 3: // End of section 3: 1 dialog and quick sector cue display. Beginning Section 4. mLogger.Write((int)EventCodes.Section3, "SP_Tutorial3End Event=Animation"); break; case 4: // End of section 4: In-sector spawn and grab animation, fixed time. Beginning Section 5. mLogger.Write((int)EventCodes.Section4, "SP_Tutorial4End Event=Animation"); break; case 5: // End of section 5: Out-sector spawn and grab animation, fixed time. Beginning Section 6. mLogger.Write((int)EventCodes.Section5, "SP_Tutorial5End Event=Animation"); break; case 6: // End of section 6: In-sector spawn and fast grab animation, fixed time. Beginning Section 7. mLogger.Write((int)EventCodes.Section6, "SP_Tutorial6End Event=Animation"); break; case 7: // End of section 7: In-sector spawn and slow grab animation, fixed time. Beginning Section 8. mLogger.Write((int)EventCodes.Section7, "SP_Tutorial7End Event=Dialogue"); break; case 8: // "End of section 8: 1 dialog. Beginning Section 9."); mLogger.Write((int)EventCodes.Section8, "SP_Tutorial8End Event=Animation"); break; case 9: // End of section 9: Energy usage animation, fixed time. Beginning Section 10. mLogger.Write((int)EventCodes.Section9, "SP_Tutorial9End Event=Dialogue"); break; case 10: // End of section 10: 1 dialog. Beginning Section 11. mLogger.Write((int)EventCodes.Section10, "SP_Tutorial10End Event=Dialogue"); break; case 11: // End of section 11: 1 dialog and peripheral response key press. Beginning Section 12. mLogger.Write((int)EventCodes.Section11, "SP_Tutorial11End Event=PeripheralResponse Event=Dialogue Event=CentralStimulus"); break; case 12: // End of section 12: 1 dialog and spawning of central stimulus. Beginning Section 13. mLogger.Write((int)EventCodes.Section12, "SP_Tutorial12End Event=Animation"); break; case 13: // End of section 13: Corrosion animation, fixed time. Beginning Section 14. mLogger.Write((int)EventCodes.Section13, "SP_Tutorial13End Event=Dialogue"); break; case 14: // End of section 14: 1 dialog. Beginning Section 15. mLogger.Write((int)EventCodes.Section14, "SP_Tutorial14End Event=Dialogue"); break; case 15: // End of section 15: 1 dialog and central response key press. Beginning Section 16. mLogger.Write((int)EventCodes.Section15, "SP_Tutorial15End Event=CentralResponse Event=Dialogue Event=Dialogue"); break; case 16: // End of section 16: 2 dialogs. Ending tutorial. mLogger.Write((int)EventCodes.Section16, "SP_Tutorial16End"); break; } } /// /// Returns the key used for responsed to the peripheral stimuli /// /// The key used for responses to the peripheral stimuli public string GetGrabbingKey() { Keys retVal = inputHandler.GetBoundKey((int)EventCodes.PeripheralStimulusResponsePressed); if (retVal == Keys.Up || retVal == Keys.Down || retVal == Keys.Left || retVal == Keys.Right) { return retVal + "-arrow key"; } return retVal + " key"; } /// /// Returns the key used for responses to the central stimuli /// /// The key used for responses to the central stimuli public string GetNotGrabbingKey() { Keys retVal = inputHandler.GetBoundKey((int)EventCodes.CentralStimulusResponsePressed); if (retVal == Keys.Up || retVal == Keys.Down || retVal == Keys.Left || retVal == Keys.Right) { return retVal + "-arrow key"; } return retVal + " key"; } /// /// Sets the cues visibility /// /// True if visible public void SetCueVisibility(bool visible) { mCue.Visible = visible; } /// /// Spawns a peripheral stimulus inside the cued sector /// public void SpawnPeripheralInsideCue() { mCurrentStimulus = mStimulusPeripheral; mCurrentStimulus.Spawn(sectorNum % NUM_SECTORS, false); } /// /// Spawns a peripheral stimulus outside the cued sector /// public void SpawnPeripheralOutsideCue() { mCurrentStimulus = mStimulusPeripheral; mCurrentStimulus.Spawn((sectorNum + Random.Next(1,3)) % NUM_SECTORS, false); } /// /// Returns whether the current stimulus is dead or not /// /// The current stimulus public bool StimulusDead() { return (mCurrentStimulus.State == EntitySpawnable.SpawnableState.Dead); } /// /// Ready resource grab with timed delay /// /// How long, in seconds, the delay is public void ReadyDelayGrab(float seconds) { mGrabDelay = seconds; mAutoGrab = true; } /// /// Readies the progress bar to show progress drain /// public void ReadyProgressDrain() { mProgressBar.Progress = mProgressBar.MaxProgress - 1; mProgressDrain = true; mDrainCounter = DRAIN_DELAY; } /// /// Readies the Center to emulate corrosion /// public void ReadyCenterWarning() { mCurrentStimulus = mCenterStatic; mCurrentStimulus.Color = new Color(Color.Red.ToVector4() / (float)mMaxIntensity * (float)mCenterIntensity); } /// /// Adds progress gained from autograb to the progress bar /// public void AddAutoGrabProgress() { mProgressBar.Progress += mCurrentStimulus.ProgressToCollect; mCurrentStimulus.ProgressToCollect = 0; } /// /// Simply ends the tutorial /// public void EndTutorial() { mLogger.Write((int)EventCodes.TutorialEnd, "SP_Tutorial_End"); Done(); } #endregion } }