using System; using System.IO; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; namespace FreedomFighter; /// /// Port of GameU.pas. The original ran all logic inside the OmegaTimer render /// callback, so this port keeps that structure: everything happens in Draw(), /// paced by a 120 Hz fixed timestep (the original's MaxFPS). /// public class Game1 : Game { readonly GraphicsDeviceManager _graphics; SpriteBatch _sb = null!; SpriteFont _font12 = null!; SpriteFont _font20 = null!; RenderTarget2D _virtualScreen = null!; // fixed 800x600 scene, stretched to the window bool _paused; string _enteredName = ""; DemoShip? _demoShip; // debug screenshot support (--shot) public string? ShotFile; public int ShotFrames = 30; public int StartLevel; // FPS measurement (the original drew OmegaTimer1.FPS) int _fps, _fpsFrames; double _fpsTimer; // precise 120Hz pacing (MonoGame's fixed-timestep Sleep overshoots and drops ticks) const double TickSeconds = 1 / 120.0; readonly System.Diagnostics.Stopwatch _frameClock = System.Diagnostics.Stopwatch.StartNew(); double _nextFrameTime; public Game1() { _graphics = new GraphicsDeviceManager(this) { PreferredBackBufferWidth = G.ScreenWidth, PreferredBackBufferHeight = G.ScreenHeight, SynchronizeWithVerticalRetrace = false, }; Content.RootDirectory = "Content"; IsMouseVisible = true; IsFixedTimeStep = false; // paced manually in EndDraw for an accurate 120Hz Window.Title = "Freedom Fighter"; Window.AllowUserResizing = true; Window.ClientSizeChanged += (_, _) => { int w = Window.ClientBounds.Width, h = Window.ClientBounds.Height; if (w > 0 && h > 0 && (w != _graphics.PreferredBackBufferWidth || h != _graphics.PreferredBackBufferHeight)) { _graphics.PreferredBackBufferWidth = w; _graphics.PreferredBackBufferHeight = h; _graphics.ApplyChanges(); } }; } protected override void LoadContent() { _sb = new SpriteBatch(GraphicsDevice); _font12 = Content.Load("Verdana12"); _font20 = Content.Load("Verdana20"); _virtualScreen = new RenderTarget2D(GraphicsDevice, G.ScreenWidth, G.ScreenHeight); // the Delphi form's Width/Height were the OUTER window size (800x600, sizeable border); // as a DPI-unaware app it was also stretched by Windows, so scale by the current DPI if (System.Windows.Forms.Control.FromHandle(Window.Handle) is System.Windows.Forms.Form form) form.Size = new System.Drawing.Size( G.ScreenWidth * form.DeviceDpi / 96, G.ScreenHeight * form.DeviceDpi / 96); string contentDir = Path.Combine(AppContext.BaseDirectory, "Content"); G.Game = this; G.Sprites = new SpriteManager(); G.Images = new ImageLists(GraphicsDevice, contentDir); G.Music = new MusicManager(); G.Music.Load(contentDir); G.Map = new GameMap(GraphicsDevice, contentDir); G.Input = new OmegaInput(); G.HighScores = new HighScores(); G.HighScores.Load(); // OmegaScreen1Init: bitmap font setup G.BitmapFont1 = new BitmapFont(G.Images.IL2[0], "0123456789"); G.BitmapFont2 = new BitmapFont(G.Images.IL5[0], "ABCDEFGHIJKLMNOPQRSTUVWXYZ "); // FormCreate G.GameTextObj = new GameText("", 60, G.BitmapFont2); G.BitmapFont2.Red = 0; G.BitmapFont2.Green = 200; G.BitmapFont2.Blue = 200; G.State = GameState.Idle; G.MainMenu = [0, 0, 0, 0, 1]; G.Prev = 4; G.Camera.Width = G.ScreenWidth; G.Camera.Height = G.ScreenHeight; G.Music.Songs[G.MUS_TITLE].Volume = 25; G.Music.Songs[G.MUS_TITLE].Play(); if (StartLevel > 0) // debug: jump straight into a level { ResetAll(); G.Level = StartLevel; G.State = GameState.Intermission; G.Counter = 495; } } protected override void EndDraw() { base.EndDraw(); // hybrid sleep/spin wait until the next 1/120s boundary _nextFrameTime += TickSeconds; double now = _frameClock.Elapsed.TotalSeconds; if (now > _nextFrameTime + 0.25) _nextFrameTime = now; // resync after a stall (window drag, load, etc.) while (_nextFrameTime - _frameClock.Elapsed.TotalSeconds > 0.002) System.Threading.Thread.Sleep(1); while (_frameClock.Elapsed.TotalSeconds < _nextFrameTime) System.Threading.Thread.SpinWait(50); } protected override void Update(GameTime gameTime) { // all logic runs in Draw, matching the original's timer callback base.Update(gameTime); } protected override void Draw(GameTime gameTime) { _fpsFrames++; _fpsTimer += gameTime.ElapsedGameTime.TotalSeconds; if (_fpsTimer >= 1) { _fps = _fpsFrames; _fpsFrames = 0; _fpsTimer -= 1; } G.Input.Update(); if (G.Input.PauseClicked) _paused = !_paused; if (!_paused) { GraphicsDevice.SetRenderTarget(_virtualScreen); GraphicsDevice.Clear(Color.Black); _sb.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp); G.Sprites.Move(0); switch (G.State) { case GameState.Intro: DoIntro(); break; case GameState.Idle: DrawMenu(); break; case GameState.Intermission: DoIntermission(); break; case GameState.Playing: GameLoop(); break; case GameState.Stats: DoStats(); break; case GameState.Shop: DoShop(); break; case GameState.GameOver: DoGameOver(); break; case GameState.Credits: DoCredits(); break; case GameState.HighScore: DoHighScore(); break; case GameState.EnterName: DoEnterName(); break; } G.Sprites.Collision(); G.Sprites.RemoveDead(); G.Sprites.Draw(_sb); _sb.End(); GraphicsDevice.SetRenderTarget(null); } // stretch the 800x600 scene to the window, as DirectX presentation did GraphicsDevice.Clear(Color.Black); _sb.Begin(SpriteSortMode.Deferred, BlendState.Opaque, SamplerState.LinearClamp); _sb.Draw(_virtualScreen, new Rectangle(0, 0, GraphicsDevice.PresentationParameters.BackBufferWidth, GraphicsDevice.PresentationParameters.BackBufferHeight), Color.White); _sb.End(); base.Draw(gameTime); if (ShotFile != null && --ShotFrames <= 0) { SaveScreenshot(ShotFile); ShotFile = null; Exit(); } } void SaveScreenshot(string file) { // capture the virtual screen so debug shots are always 800x600 using var fs = File.Create(file); _virtualScreen.SaveAsPng(fs, _virtualScreen.Width, _virtualScreen.Height); } // ================================================================ helpers void PrintFps(int x, int y) => _sb.DrawString(_font12, "FPS: " + _fps, new Vector2(x, y), Color.White); void ResetAll() { G.Change = 0; G.Score = 0; G.Lives = 3; } void ResetPlayer() { var p = new Player(G.Sprites) { Name = "Player" }; // original computed X before assigning Width (Width was still 0) p.X = G.ScreenWidth / 2 - p.Width; p.Y = G.ScreenHeight - 80; p.Health = 16; p.FireRate = 20; p.Width = 73; p.Height = 45; p.Image = G.Images.IL1[0]; p.Weapon = Weapon.Reg; p.ImageIndex = 0; p.DoPixelCheck = true; p.DoCollision = true; p.CenterX = 0.5f; p.CenterY = 0.5f; G.Player = p; } void ClipCamera(float x, float y, int width, int height) { if (x < G.Camera.Width / 2f) G.NewCamX = 0; else G.NewCamX = (int)(x + width / 2f - G.Camera.Width / 2f); if (y < G.Camera.Height / 2f) G.NewCamY = 0; else G.NewCamY = (int)(y + height / 2f - G.Camera.Height / 2f); // the min/max clips were commented out in the original, leaving these unconditional G.NewCamX = G.Map.WidthCount * 32 - G.Camera.Width; G.NewCamY = G.Map.HeightCount * 32 - G.Camera.Height; int frameCamSpeed = 1; if (G.NewCamX > G.Camera.X) { G.Camera.X += frameCamSpeed; if (G.NewCamX < G.Camera.X) G.Camera.X = G.NewCamX; } else if (G.NewCamX < G.Camera.X) { G.Camera.X -= frameCamSpeed; if (G.NewCamX > G.Camera.X) G.Camera.X = G.NewCamX; } // Y seek was commented out in the original } void DrawLayer1() { var tileset = G.Map.Tileset; if (tileset == null) return; for (int a = 0; a <= G.Camera.Width / 32 + 1; a++) for (int b = 0; b <= G.Camera.Height / 32 + 1; b++) { int xid = (a * 32 + G.Camera.X) / 32; int yid = (b * 32 + G.Camera.Y) / 32; int drawX = xid * 32 - G.Camera.X; int drawY = yid * 32 - G.Camera.Y; if (xid < G.Map.WidthCount && yid < G.Map.HeightCount && xid >= 0 && yid >= 0) { int id = G.Map.Layer1[xid][yid]; if (id != -1) tileset.Draw(_sb, drawX, drawY, 0, 0.5f, 0.5f, 1, 1, 255, 255, 255, 255, id); } } } void MoveSelection(int curSelect) { G.MainMenu[G.Prev] = 0; G.MainMenu[curSelect] = 1; G.Prev = curSelect; } // ================================================================ spawning void SpawnObject(ObjectType type, float xPos, float yPos) { switch (type) { case ObjectType.Fighter: _ = new Enemy(G.Sprites) { X = xPos, Y = yPos, YVel = 1.5f, Width = 34, Height = 34, Image = G.Images.IL1[1], ImageIndex = 0, DoCollision = true, DoPixelCheck = true, AI = AI.Normal, Health = 2, HitTimer = 255, }; break; case ObjectType.Kamikaze: _ = new Enemy(G.Sprites) { X = xPos, Y = yPos, YVel = 2, Width = 32, Height = 32, Image = G.Images.IL1[7], ImageIndex = 0, DoCollision = true, DoPixelCheck = true, AI = AI.Hunt, Health = 3, HitTimer = 255, }; break; case ObjectType.Tactical: _ = new Enemy(G.Sprites) { X = xPos, Y = yPos, YVel = 3, Charging = false, Width = 32, Height = 32, Image = G.Images.IL1[15], ImageIndex = 0, DoCollision = true, DoPixelCheck = true, AI = AI.Tactical, Health = 5, HitTimer = 255, }; break; case ObjectType.Mine: _ = new Enemy(G.Sprites) { X = xPos, Y = yPos, CenterX = 0.5f, CenterY = 0.5f, YVel = 0.5f, AnimTicks = 0, ExplodeTime = G.Random(100) + 200, Width = 32, Height = 48, Image = G.Images.IL1[17], ImageIndex = 0, DoCollision = true, DoPixelCheck = true, Health = 10, AI = AI.Mine, MoveDir = "right", }; break; case ObjectType.MissileBase: _ = new Enemy(G.Sprites) { Name = "Missile Base", X = xPos, Y = yPos, CenterX = 0.5f, CenterY = 0.5f, YVel = 1, Width = 32, Height = 32, Image = G.Images.IL1[18], ImageIndex = 1, DoCollision = false, DoPixelCheck = true, Health = 1, AI = AI.None, }; break; case ObjectType.MissileTurret: _ = new Enemy(G.Sprites) { Name = "Missile Turret", X = xPos, Y = yPos, YVel = 1, CenterX = 0.5f, CenterY = 0.5f, Width = 32, Height = 32, Image = G.Images.IL1[18], ImageIndex = 0, DoCollision = true, DoPixelCheck = true, Health = 4, FireRate = 1, AI = AI.Turret, }; break; case ObjectType.Scanner: _ = new Enemy(G.Sprites) { Name = "Scanner", X = xPos, Y = yPos, YVel = 1, CenterX = 0.5f, CenterY = 0.5f, Width = 32, Height = 32, Image = G.Images.IL1[20], ImageIndex = 0, DoCollision = true, DoPixelCheck = true, Health = 10, AI = AI.None, }; break; case ObjectType.Boss: _ = new Boss(G.Sprites) { X = xPos, Y = yPos, YVel = 1, Width = 98, Height = 98, Image = G.Images.IL1[9], ImageIndex = 0, DoCollision = true, DoPixelCheck = true, MoveDir = "right", Health = 50, HitTimer = 255, AI = AI.Boss, }; break; case ObjectType.Boss2: _ = new Boss(G.Sprites) { X = xPos, Y = yPos, YVel = 1, Width = 98, Height = 98, Image = G.Images.IL1[13], ImageIndex = 0, DoCollision = true, DoPixelCheck = true, MoveDir = "down", Health = 200, HitTimer = 255, AI = AI.Boss2, Timer = 0, RandX = 4, }; break; } } void CreateSquad(ObjectType ship, int pattern) { int randomX = G.Random(G.ScreenWidth - 140) + 64; switch (pattern) { case 0: SpawnObject(ship, randomX, -32); SpawnObject(ship, randomX - 32, -64); SpawnObject(ship, randomX + 32, -64); break; case 1: SpawnObject(ship, randomX, -32); SpawnObject(ship, randomX - 32, -64); SpawnObject(ship, randomX + 32, -64); SpawnObject(ship, randomX + 64, -96); SpawnObject(ship, randomX - 64, -96); break; } } // ================================================================ states void DrawMenu() { PrintFps(10, 10); // water background for (int a = 0; a <= G.ScreenWidth / 32; a++) for (int b = 0; b <= G.ScreenHeight / 32; b++) G.Images.IL1[4].Draw(_sb, a * 32, b * 32, 0, 0, 0, 1, 1, 255, 255, 255, 200, 0); G.Images.IL2[3].Draw(_sb, G.ScreenWidth / 2 - 180, 50, pattern: 0); G.Images.IL2[4].Draw(_sb, G.ScreenWidth / 2 - 180, 200, pattern: G.MainMenu[4]); G.Images.IL2[5].Draw(_sb, G.ScreenWidth / 2 - 180, 250, pattern: G.MainMenu[3]); G.Images.IL2[6].Draw(_sb, G.ScreenWidth / 2 - 180, 300, pattern: G.MainMenu[2]); G.Images.IL2[7].Draw(_sb, G.ScreenWidth / 2 - 180, 350, pattern: G.MainMenu[1]); G.Images.IL2[8].Draw(_sb, G.ScreenWidth / 2 - 180, 400, pattern: G.MainMenu[0]); var versionSize = _font12.MeasureString(G.Version); _sb.DrawString(_font12, G.Version, new Vector2(G.ScreenWidth / 2 - versionSize.X / 2, 100), Color.White); if (G.Input.UpClicked) { G.Music.Songs[7].Play(); G.CurSelection++; if (G.CurSelection > 4) G.CurSelection = 0; if (G.CurSelection < 0) G.CurSelection = 4; MoveSelection(G.CurSelection); } if (G.Input.DownClicked) { G.Music.Songs[7].Play(); G.CurSelection--; if (G.CurSelection > 4) G.CurSelection = 0; if (G.CurSelection < 0) G.CurSelection = 4; MoveSelection(G.CurSelection); } if (G.Input.Button3Clicked) { switch (G.CurSelection) { case 0: Exit(); break; case 1: G.Music.Songs[4].Stop(); G.Music.Songs[9].Play(); G.Sprites.KillAll(); G.Sprites.RemoveDead(); G.BitmapFont2.Alpha = 0; G.Counter = 0; G.TextNum = 0; G.TitleText = new GameText("DESIGN AND PROGRAMMING", 30, G.BitmapFont2); G.TitleText.SetSpeed(3); G.IdText = new GameText("BRIAN BICKNELL", 30, G.BitmapFont2); G.IdText.SetSpeed(3); G.State = GameState.Credits; break; case 2: G.State = GameState.HighScore; break; case 3: G.Music.Songs[8].Play(); break; case 4: G.Sprites.KillAll(); G.Sprites.RemoveDead(); ResetAll(); G.Level = 1; G.State = GameState.Intermission; G.Music.Songs[4].Stop(); G.Music.Songs[7].Play(); break; } } if (G.Input.Button6Clicked) // '2' starts the demo intro { G.Sprites.KillAll(); G.Sprites.RemoveDead(); ResetAll(); G.Map.LoadMap("intro.omap"); G.Camera.Y = G.Map.HeightCount * 32 - G.ScreenHeight; var demoShip = new DemoShip(G.Sprites) { Name = "DemoShip" }; demoShip.X = G.ScreenWidth / 2 - demoShip.Width; // Width still 0, like the original demoShip.Y = G.ScreenHeight; demoShip.Width = 73; demoShip.Height = 45; demoShip.Image = G.Images.IL1[0]; demoShip.ImageIndex = 0; demoShip.DoPixelCheck = true; demoShip.DoCollision = true; demoShip.CenterX = 0.5f; demoShip.CenterY = 0.5f; _demoShip = demoShip; G.Music.Songs[4].Stop(); G.Music.Songs[14].Play(); G.TitleText = new GameText("BICK SOFTWARE", 30, G.BitmapFont2); G.IdText = new GameText("PRESENTS", 30, G.BitmapFont2); G.TextCreated = false; G.BossMode = false; G.State = GameState.Intro; } if (G.Input.Button2Clicked) Exit(); } void DoIntro() { if (_demoShip != null && _demoShip.Y > 300) _demoShip.Y -= 0.2f; ClipCamera(G.Camera.X, G.Camera.Y, 32, 32); DrawLayer1(); PrintFps(10, 20); if (!G.TextCreated) { G.TitleText.SetText("BICK SOFTWARE PRESENTS"); G.TextCreated = true; G.BitmapFont2.Alpha = 0; } if (G.Counter == 5) { G.TitleText.FadeOut(_sb, 200, 200, 500); if (G.BitmapFont2.Alpha == 0) { G.TitleText.SetText("OMEGA SQUADREN"); G.Counter = 0; } } else { G.TitleText.FadeIn(_sb, 200, 200, 500); if (G.BitmapFont2.Alpha == 255) G.Counter = 5; } if (G.Music.Songs[14].Position > 36) { if (G.Random(50) == 0) SpawnObject(ObjectType.Fighter, G.Random(G.ScreenWidth), -32); } if (G.Camera.Y <= 0) { G.Camera.Y = 0; if (!G.BossMode) { SpawnObject(ObjectType.Boss, 300, -G.ScreenHeight + 98); G.BossMode = true; } } else G.Camera.Y--; } void DoIntermission() { G.BossMode = false; G.Done = false; if (G.Level > 5) { G.Music.Songs[12].Stop(); G.Music.Songs[3].Play(); G.State = GameState.GameOver; } string label = "Level " + G.Level; var size = _font20.MeasureString("Level" + G.Level); _sb.DrawString(_font20, label, new Vector2(G.ScreenWidth / 2 - size.X / 2, G.ScreenHeight / 2), Color.White); G.Counter++; G.ShipsKilled = 0; if (G.Counter > 500) { switch (G.Level) { case 1: G.Map.LoadMap("test10.omap"); break; case 2: G.Map.LoadMap("test7.omap"); break; case 3: G.Map.LoadMap("test8.omap"); break; case 4: G.Map.LoadMap("bonus.omap"); break; case 5: G.Map.LoadMap("lvl5.omap"); break; } G.State = GameState.Playing; ResetPlayer(); G.Camera.Y = G.Map.HeightCount * 32 - G.ScreenHeight; if (G.Level > 1) G.Music.Songs[G.Level - 2].Stop(); if (G.Level == 1) { G.Music.Songs[G.MUS_LEVEL1].Volume = 20; G.Music.Songs[G.MUS_LEVEL1].Play(); } else if (G.Level == 4) G.Music.Songs[12].Play(); else if (G.Level == 5) { G.Music.Songs[12].Stop(); G.Music.Songs[4].Play(); } else G.Music.Songs[G.Level - 1].Play(); } } void GameLoop() { ClipCamera(G.Camera.X, G.Camera.Y, 32, 32); DrawLayer1(); // level 4: boss chase with a wrapping camera if (G.Level == 4) { if (!G.BossMode) { SpawnObject(ObjectType.Boss2, 300, -G.ScreenHeight + 98); G.BossMode = true; } if (G.Camera.Y <= 0) G.Camera.Y = G.Map.HeightCount * 32 - G.ScreenHeight; else G.Camera.Y -= 2; } int randomNum = G.Random(500); if (randomNum == 0) CreateSquad(ObjectType.Fighter, 0); if (randomNum == 1) CreateSquad(ObjectType.Kamikaze, 1); if (randomNum == 5) SpawnObject(ObjectType.Mine, G.Random(G.ScreenWidth), -48); if (G.Camera.Y <= 0) { G.Camera.Y = 0; if (!G.BossMode) { SpawnObject(ObjectType.Boss, 300, -G.ScreenHeight + 98); G.BossMode = true; } } else G.Camera.Y--; GetStats(); G.Counter++; if (G.Counter > 10) { G.Change++; if (G.Change > 2) G.Change = 0; G.Counter = 0; } PrintFps(10, 10); _sb.DrawString(_font12, "Sprites: " + G.Sprites.Count, new Vector2(10, 30), Color.White); if (G.Lives < 0) { G.Sprites.KillAll(); G.Sprites.RemoveDead(); G.Music.Songs[G.Level - 1].Stop(); G.State = GameState.GameOver; } if (G.Done) { G.Sprites.KillAll(); G.ShipsKilled++; G.Level++; G.State = GameState.Stats; G.Counter = 0; } // spawn entities from map triggers at/below the camera for (int a = 0; a < G.Map.WidthCount; a++) for (int b = Math.Max(0, G.Camera.Y / 32); b < G.Map.HeightCount; b++) { string? action = G.Map.TriggerActions[a, b]; if (action == null) continue; int tempX = a * 32; int tempY = b - 128; // original quirk: tile row minus 128 pixels switch (action) { case "fighter": SpawnObject(ObjectType.Fighter, tempX, tempY); G.Map.TriggerActions[a, b] = null; break; case "kamikaze": SpawnObject(ObjectType.Kamikaze, tempX, tempY); G.Map.TriggerActions[a, b] = null; break; case "tactical": SpawnObject(ObjectType.Tactical, tempX, tempY); G.Map.TriggerActions[a, b] = null; break; case "missileturret": SpawnObject(ObjectType.MissileTurret, tempX, tempY); SpawnObject(ObjectType.MissileBase, tempX, tempY); G.Map.TriggerActions[a, b] = null; break; case "scanner": SpawnObject(ObjectType.Scanner, tempX, tempY); G.Map.TriggerActions[a, b] = null; break; } } if (G.Input.Button2Clicked) { G.Sprites.KillAll(); G.Sprites.RemoveDead(); G.Music.Songs[G.Level - 1].Stop(); G.Music.Songs[G.MUS_TITLE].Play(); G.State = GameState.Idle; } } void GetStats() { int imageIdx = G.Player.Weapon switch { Weapon.Reg => 0, Weapon.Super => 1, Weapon.Multi => 2, _ => -1, }; G.Images.IL3[2].Draw(_sb, 300, 560, pattern: imageIdx); int colWidth = -10; for (int i = 0; i < G.Lives; i++) { G.Images.IL1[0].Draw(_sb, G.ScreenWidth - 800 + colWidth, G.ScreenHeight - 50, 0, 0.5f, 0.5f, 0.5f, 0.5f, 255, 255, 255, 255, 0); colWidth += 30; } G.Images.IL1[6].Draw(_sb, 5, 50, pattern: 0); G.BitmapFont1.Print(_sb, 75, 50, G.Score.ToString()); G.BitmapFont2.Print(_sb, G.ScreenWidth - 150, G.ScreenHeight - 30, "HEALTH"); G.Images.IL3[0].Draw(_sb, G.ScreenWidth - 150, G.ScreenHeight - 20, pattern: 0); int barWidth = 0; for (int i = 0; i < G.Player.Health; i++) { G.Images.IL3[1].Draw(_sb, G.ScreenWidth - 148 + barWidth, G.ScreenHeight - 18, pattern: 0); barWidth += 8; } G.BitmapFont2.Print(_sb, G.ScreenWidth / 6, G.ScreenHeight - 30, "POWER"); G.Images.IL3[0].Draw(_sb, G.ScreenWidth / 6, G.ScreenHeight - 20, pattern: 0); int energyWidth = 0; for (int i = 0; i < G.Player.Power; i++) { G.Images.IL3[3].Draw(_sb, G.ScreenWidth / 6 + 2 + energyWidth, G.ScreenHeight - 18, 0, 0, 0, 1, 1, 0, 100 + energyWidth, 0, 255, 0); energyWidth += 7; } if (G.Player.Health < 0) { G.Player.Kill(); G.Lives--; ResetPlayer(); } } void DoStats() { if (G.Counter > 10 && G.CurCount < G.ShipsKilled) { G.Music.Songs[5].Play(); G.CurCount++; G.Counter = 0; } if (G.Input.Button1Clicked && G.CurCount != G.ShipsKilled) { G.CurCount = G.ShipsKilled; G.Counter = 0; } string text = "Ships Killed: " + G.CurCount; var size = _font12.MeasureString(text); _sb.DrawString(_font12, text, new Vector2(G.ScreenWidth / 2 - size.X / 2, G.ScreenHeight / 2), Color.White); G.Counter++; _sb.DrawString(_font12, G.Counter.ToString(), new Vector2(10, 10), Color.White); if (G.Counter > 500) { G.Counter = 0; G.CurCount = 0; G.State = GameState.Shop; } } void DoShop() { _sb.DrawString(_font12, "This is the blackmarket shop", new Vector2(10, 10), Color.White); _sb.DrawString(_font12, "PRESS [SPACE] TO CONTINUE", new Vector2(10, 550), Color.White); if (G.Input.Button1Clicked) { G.State = GameState.Intermission; G.Music.Songs[G.Level - 2].Stop(); G.Music.Songs[7].Play(); } } void DoGameOver() { G.Images.IL2[2].Draw(_sb, G.ScreenWidth / 2 - 49, G.ScreenHeight / 2, pattern: 0); G.Images.IL1[6].Draw(_sb, G.ScreenWidth / 2 - 34, G.ScreenHeight / 2 + 100, pattern: 0); G.BitmapFont1.Print(_sb, G.ScreenWidth / 2 + 30, G.ScreenHeight / 2 + 100, G.Score.ToString()); if (G.Input.Button1Clicked) { G.Music.Songs[3].Stop(); G.Music.Songs[9].Play(); G.BitmapFont2.Alpha = 0; G.Counter = 0; G.TextNum = 0; G.TitleText = new GameText("DESIGN AND PROGRAMMING", 30, G.BitmapFont2); G.TitleText.SetSpeed(3); G.IdText = new GameText("BRIAN BICKNELL", 30, G.BitmapFont2); G.IdText.SetSpeed(3); if (G.HighScores.Qualifies(G.Score)) { _enteredName = ""; G.State = GameState.EnterName; // replaces the Form2 dialog } else G.State = GameState.Credits; } } void DoCredits() { G.TitleText.FadeIn(_sb, G.ScreenWidth / 2 - G.TitleText.GetText().Length * G.BitmapFont2.CharWidth / 2, G.ScreenHeight / 2 - 15, 5); if (G.TitleText.IsDone) G.IdText.TypePrint(_sb, G.ScreenWidth / 2 - G.IdText.GetText().Length * G.BitmapFont2.CharWidth / 2, G.ScreenHeight / 2 + 15); if (G.IdText.IsDone) { G.Counter++; if (G.Counter > 400) { G.TextNum++; switch (G.TextNum) { case 1: G.BitmapFont2.Alpha = 0; G.TitleText.SetText("GRAPHICS BY"); G.IdText.SetText("BRIAN MAZUROWSKI"); break; case 2: G.BitmapFont2.Alpha = 0; G.TitleText.SetText("MUSIC BY"); G.IdText.SetText("ADAM HAIRE"); break; case 3: G.BitmapFont2.Alpha = 0; G.TitleText.SetText("SPECIAL THANKS TO"); G.IdText.SetText("THE OMEGA TEAM"); break; case 4: G.BitmapFont2.Alpha = 0; G.TitleText.SetText("THANK YOU FROM"); G.IdText.SetText("BICK SOFTWARE"); break; case 5: G.State = GameState.HighScore; break; } G.Counter = 0; } } if (G.Input.Button2Clicked) { G.Music.Songs[9].Stop(); G.Music.Songs[G.MUS_TITLE].Play(); G.State = GameState.Idle; } } void DoHighScore() { // The original printed via OmegaBitmapFont3, which had no image list assigned; // here the letter and number fonts are combined so the table is actually visible. int delta = 0; int savedAlpha = G.BitmapFont2.Alpha; G.BitmapFont2.Alpha = 255; for (int i = 0; i < 10; i++) { G.BitmapFont2.Print(_sb, 10, 10 + delta, G.HighScores.List[i].Name.ToUpperInvariant()); G.BitmapFont1.Print(_sb, 200, 10 + delta, G.HighScores.List[i].Score.ToString()); delta += 20; } G.BitmapFont2.Alpha = savedAlpha; if (G.Input.Button1Clicked) G.State = GameState.Idle; } void DoEnterName() { int savedAlpha = G.BitmapFont2.Alpha; G.BitmapFont2.Alpha = 255; G.BitmapFont2.Print(_sb, 200, 250, "NEW HIGH SCORE"); G.BitmapFont2.Print(_sb, 200, 280, "ENTER YOUR NAME"); G.BitmapFont2.Print(_sb, 200, 320, _enteredName); G.BitmapFont2.Alpha = savedAlpha; foreach (var key in G.Input.Current.GetPressedKeys()) { if (!G.Input.Previous.IsKeyUp(key)) continue; if (key >= Keys.A && key <= Keys.Z && _enteredName.Length < 20) _enteredName += (char)('A' + (key - Keys.A)); else if (key == Keys.Space && _enteredName.Length < 20) _enteredName += ' '; else if (key == Keys.Back && _enteredName.Length > 0) _enteredName = _enteredName[..^1]; else if (key == Keys.Enter && _enteredName.Length > 0) { G.HighScores.Enter(_enteredName, G.Score); G.State = GameState.Credits; } } } }