#define WINDOWS using System; using System.Diagnostics; using System.Linq; using System.Media; using System.Reflection; using System.Runtime.InteropServices; using static System.Console; //┌─┐ //│ │ //└─┘ // ▀▀▀██████▄▄▄ // ▀▀▀████▄ // ▄███████▀ ▀███▄ // ▄███████▀ ▀███▄ // ▄████████ ███▄ // ██████████▄ ███▌ // ▀█████▀ ▀███▄ ▐███ // ▀█▀ ▀███▄ ▐███ // ▀███▄ ███▌ // ▄██▄ ▀███▄ ▐███ // ▄██████▄ ▀███▄███ // █████▀▀████▄▄ ▄█████ // ████▀ ▀▀█████▄▄▄▄█████████▄ // ▀▀ ▀▀██████▀▀ ▀▀██ namespace testexetrisathlon { internal static class Program { public const string Sqr = "■"; public static int[,] Grid = new int[23, 10]; public static int[,] DroppedTetrominoeLocationGrid = new int[23, 10]; private static Stopwatch _dropTimer = new Stopwatch(); private static int _dropTime; private static int _dropRate = 300; public static bool IsDropped; private static Tetrominoe _tet; private static Tetrominoe _nextTet; private static ConsoleKeyInfo _key; private static bool _isKeyPressed; private static int _linesCleared; private static int _score; private static int _level = 1; private static readonly Assembly Assembly = Assembly.GetExecutingAssembly(); private static readonly ConsoleColor[] Colors = {BackgroundColor, ForegroundColor}; public static bool Debug; public static readonly Random Rnd = new Random(); private static readonly SoundPlayer Intro = new SoundPlayer(Assembly.GetManifestResourceStream("testexetrisathlon.Intro.wav")); private static readonly SoundPlayer InGame1 = new SoundPlayer(Assembly.GetManifestResourceStream("testexetrisathlon.InGame1.wav")); private static readonly SoundPlayer InGame2 = new SoundPlayer(Assembly.GetManifestResourceStream("testexetrisathlon.InGame2.wav")); private static readonly SoundPlayer GameOver = new SoundPlayer(Assembly.GetManifestResourceStream("testexetrisathlon.GameOver.wav")); private static SoundPlayer _inGame = SettingsMan.UsingAltTrack ? InGame2 : InGame1; #if WINDOWS [DllImport("winmm.dll")] private static extern int waveOutSetVolume(IntPtr hwo, uint dwVolume); #endif #if DEBUG private static void Main() { Debug = true; #else private static void Main(string[] args) { Debug = args.Contains("debug"); #endif BackgroundColor = ConsoleColor.Red; ForegroundColor = ConsoleColor.Yellow; SetWindowSize(42, 29); SetCursorPosition(0, 0); Clear(); if (Debug) SetWindowSize(50, 40); #if WINDOWS int newVolume = (ushort.MaxValue / 10) * SettingsMan.Volume; waveOutSetVolume(IntPtr.Zero, ((uint) newVolume & 0x0000ffff) | ((uint) newVolume << 16)); #endif bool playing = true; GameState state = GameState.Menu; try { while (playing) switch (state) { case GameState.Menu: Clear(); GameOver.Stop(); Intro.PlayLooping(); DrawSymbol(); SetCursorPosition(12, 18); Write("HighScore: " + SettingsMan.HighScore); SetCursorPosition(12, 20); Write("Controls: Space"); SetCursorPosition(13, 21); Write("Up, Down, Right"); SetCursorPosition(13, 22); Write("Left"); SetCursorPosition(12, 24); Write("Press s to start"); SetCursorPosition(12, 25); Write("Press x to exit"); SetCursorPosition(12, 26); Write("Press v for settings"); SetCursorPosition(0, 28); Write("Icon made by Freepik from www.flaticon.com"); string tmp = ReadKey(true).KeyChar.ToString().ToLower(); switch (tmp) { case "s": Intro.Stop(); state = GameState.Game; Clear(); DrawBorder(); break; case "x": state = GameState.Exit; break; case "v": SettingsMenu(); break; } break; case GameState.Game: _inGame.PlayLooping(); _dropTimer.Start(); SetCursorPosition(25, 0); WriteLine("Level " + _level); SetCursorPosition(25, 1); WriteLine("Score " + _score + "/" + (Math.Pow(_level, 2) * 100)); SetCursorPosition(25, 2); WriteLine("LinesCleared " + _linesCleared); SetCursorPosition(25, 4); WriteLine("HighScore " + SettingsMan.HighScore); _nextTet = new Tetrominoe(); _tet = _nextTet; _tet.Spawn(); _nextTet = new Tetrominoe(); Update(); _inGame.Stop(); state = GameState.GameOver; break; case GameState.GameOver: SettingsMan.HighScore = _score; GameOver.PlayLooping(); string input = ""; while (input != "y" && input != "n") { Clear(); DrawBorder(); Draw(); SetCursorPosition(0, 0); WriteLine("┌───────────────────┐"); WriteLine("│ Game Over │"); WriteLine("│ Replay? (Y/N) │"); WriteLine("├───────────────────┤"); input = ReadKey().KeyChar.ToString().ToLower(); } Grid = new int[23, 10]; DroppedTetrominoeLocationGrid = new int[23, 10]; _dropTimer = new Stopwatch(); _dropRate = 300; IsDropped = false; _isKeyPressed = false; _linesCleared = 0; _score = 0; _level = 1; GC.Collect(); Clear(); DrawBorder(); state = input == "y" ? GameState.Game : GameState.Menu; break; case GameState.Exit: playing = false; break; default: throw new ArgumentOutOfRangeException(); } } finally { Intro.Dispose(); InGame1.Dispose(); InGame2.Dispose(); GameOver.Dispose(); } BackgroundColor = Colors[0]; ForegroundColor = Colors[1]; SetCursorPosition(0, 0); Clear(); } private static void DrawSymbol() { SetCursorPosition(0, 1); Write( " ▀▀▀██████▄▄▄\r\n" + " ▀▀▀████▄\r\n" + " ▄███████▀ ▀███▄\r\n" + " ▄███████▀ ▀███▄\r\n" + " ▄████████ ███▄\r\n" + " ██████████▄ ███▌\r\n" + " ▀█████▀ ▀███▄ ▐███\r\n" + " ▀█▀ ▀███▄ ▐███\r\n" + " ▀███▄ ███▌\r\n" + " ▄██▄ ▀███▄ ▐███\r\n" + " ▄██████▄ ▀███▄███\r\n" + " █████▀▀████▄▄ ▄█████\r\n" + " ████▀ ▀▀█████▄▄▄▄█████████▄\r\n" + " ▀▀ ▀▀██████▀▀ ▀▀██\r\n\r\n" + " testexetrisathlon v." + Assembly.GetName().Version); } private static void SettingsMenu() { Clear(); DrawSymbol(); #if !WINDOWS SetCursorPosition(2, 19); Write("Volume is not supported in this build!"); #endif bool barActive = true; int currentSetting = 0; while (barActive) { bool curr = SettingsMan.UsingAltTrack; SetCursorPosition(3, 20); ForegroundColor = currentSetting == 0 ? ConsoleColor.White : ConsoleColor.Yellow; Write("Volume: " + new string('=', SettingsMan.Volume * 2) + "[" + SettingsMan.Volume.ToString("00") + "]" + new string('=', 20 - (SettingsMan.Volume * 2))); SetCursorPosition(5, 22); ForegroundColor = currentSetting == 1 ? ConsoleColor.White : ConsoleColor.Yellow; Write($"{(curr ? " Using" : "Not using")} alternative soundtrack "); ForegroundColor = ConsoleColor.Yellow; switch (currentSetting) { case 0: switch (ReadKey().Key) { case ConsoleKey.LeftArrow: SettingsMan.Volume--; break; case ConsoleKey.RightArrow: SettingsMan.Volume++; break; case ConsoleKey.Enter: barActive = false; break; case ConsoleKey.Tab: currentSetting = 1; break; } break; case 1: switch (ReadKey().Key) { case ConsoleKey.LeftArrow: case ConsoleKey.RightArrow: case ConsoleKey.Spacebar: SettingsMan.UsingAltTrack = !curr; break; case ConsoleKey.Enter: barActive = false; break; case ConsoleKey.Tab: currentSetting = 0; break; } break; } #if WINDOWS int newVolume = (ushort.MaxValue / 10) * SettingsMan.Volume; waveOutSetVolume(IntPtr.Zero, ((uint) newVolume & 0x0000ffff) | ((uint) newVolume << 16)); #endif _inGame = SettingsMan.UsingAltTrack ? InGame2 : InGame1; } } private static void Update() { while (true) { _dropTime = (int) _dropTimer.ElapsedMilliseconds; if (_dropTime > _dropRate) { _dropTime = 0; _dropTimer.Restart(); _tet.Drop(); } if (IsDropped) { _tet = _nextTet; _nextTet = new Tetrominoe(); _tet.Spawn(); IsDropped = false; _score += 10; } for (int j = 0; j < 10; j++) if (DroppedTetrominoeLocationGrid[0, j] == 1) return; if (Debug) { SetCursorPosition(0, 25); WriteLine("!DEBUG MODE ENABLED!"); } Input(); ClearBlock(); } } private static void ClearBlock() { int combo = 0; for (int i = 0; i < 23; i++) if (Enumerable.Range(0, 10).All(s => DroppedTetrominoeLocationGrid[i, s] != 0)) { _linesCleared++; combo++; Beep(400, 200); for (int j = 0; j < 10; j++) DroppedTetrominoeLocationGrid[i, j] = 0; int[,] newDroppedTetrominoeLocationGrid = new int[23, 10]; for (int k = 1; k < i; k++) for (int l = 0; l < 10; l++) newDroppedTetrominoeLocationGrid[k + 1, l] = DroppedTetrominoeLocationGrid[k, l]; for (int k = 1; k < i; k++) for (int l = 0; l < 10; l++) DroppedTetrominoeLocationGrid[k, l] = 0; for (int k = 0; k < 23; k++) for (int l = 0; l < 10; l++) if (newDroppedTetrominoeLocationGrid[k, l] == 1) DroppedTetrominoeLocationGrid[k, l] = 1; Draw(); } _score += (int) Math.Round(Math.Sqrt(Math.Max((combo * 50) - 50, 0)) * 5); _level = (int) Math.Round(Math.Sqrt(_score * 0.01)) + 1; _dropRate = 300 - (22 * _level); } private static void Input() { _isKeyPressed = KeyAvailable; SetCursorPosition(0, 24); if (_isKeyPressed) _key = ReadKey(); if ((_key.Key == ConsoleKey.LeftArrow) & !_tet.IsSomethingLeft() & _isKeyPressed) { for (int i = 0; i < 4; i++) _tet.Location[i][1] -= 1; _tet.Update(); } else if ((_key.Key == ConsoleKey.RightArrow) & !_tet.IsSomethingRight() & _isKeyPressed) { for (int i = 0; i < 4; i++) _tet.Location[i][1] += 1; _tet.Update(); } if ((_key.Key == ConsoleKey.DownArrow) & _isKeyPressed) _tet.Drop(); if ((_key.Key == ConsoleKey.UpArrow) & _isKeyPressed) for (; _tet.IsSomethingBelow != true;) _tet.Drop(); if ((_key.Key == ConsoleKey.Spacebar) & _isKeyPressed) { _tet.Rotate(); _tet.Update(); } } public static void Draw() { for (int i = 0; i < 23; ++i) for (int j = 0; j < 10; j++) { SetCursorPosition((2 * j) + 1, i); if ((Grid[i, j] == 1) | (DroppedTetrominoeLocationGrid[i, j] == 1)) { SetCursorPosition((2 * j) + 1, i); Write(Sqr); } else { Write(" "); } } SetCursorPosition(25, 0); WriteLine("Level " + _level); SetCursorPosition(25, 1); WriteLine("Score " + _score + "/" + (Math.Pow(_level, 2) * 100)); SetCursorPosition(25, 2); WriteLine("LinesCleared " + _linesCleared); } public static void DrawBorder() { for (int lengthCount = 0; lengthCount <= 22; lengthCount++) { SetCursorPosition(0, lengthCount); Write("│"); SetCursorPosition(20, lengthCount); Write("│"); } SetCursorPosition(0, 23); Write("└"); for (int widthCount = 0; widthCount <= 18; widthCount++) Write("─"); Write("┘"); } private enum GameState { Exit, Menu, Game, GameOver } } }