From feba6acc364fa0dc01dd9f5fb17c889f3e00464e Mon Sep 17 00:00:00 2001 From: Slavasil Date: Sun, 23 Mar 2025 23:13:14 +0300 Subject: [PATCH] implement the main game loop and the `game over` screen --- App/I18n.cs | 3 ++ App/Program.cs | 67 +++++++++++++++++++++++++++++++++++++++++++ App/UI/TextDisplay.cs | 63 +++++++++++++++++++++++++++++++++------- 3 files changed, 122 insertions(+), 11 deletions(-) diff --git a/App/I18n.cs b/App/I18n.cs index 72bf655..d782a3d 100644 --- a/App/I18n.cs +++ b/App/I18n.cs @@ -17,6 +17,7 @@ namespace Game { "A STOPWATCHIONAIRE", "Cannot read/create the game config file because of an unknown error", "Game rules: press any key to continue...", + "Game is over. You gave {0} correct answers out of {1}!", }}, {"ru-RU", new string[] { "Не указано ни одного варианта ответа на вопрос", @@ -32,6 +33,7 @@ namespace Game { "СЕКУНДОМЕРОМ", "Произошла неизвестная ошибка при чтении/создании файла настроек", "Правила игры: Вам будет предложено ответить на вопросы. Отвечайте на них правильно и всё будет в шоколаде. Удачи xD! Нажмите любую клавишу, чтобы продолжить", + "Игра окончена. Вы ответили правильно на {0} вопросов из {1}!", }} }; @@ -53,6 +55,7 @@ namespace Game { TITLE_LINE2, ERROR_READ_CONFIG_UNKNOWN, RULES, + GAME_OVER, } } } \ No newline at end of file diff --git a/App/Program.cs b/App/Program.cs index 4a8b687..0a368e2 100644 --- a/App/Program.cs +++ b/App/Program.cs @@ -43,6 +43,73 @@ namespace Game { display.DrawRules(); Console.ReadKey(); + Random rng = new Random(); + List questions = questionDatabase.questions.OrderBy(_ => rng.Next()).ToList(); + int correntAnswers = 0; + for (int i = 0; i < questions.Count; ++i) { + Question question = questions[i]; + display.ShowMainGameScreenBase(); + display.DrawText(TextDisplay.HAlignment.Center, TextDisplay.VAlignment.Center, 6, display.windowWidth / 2 + 1, question.question, 0, 0x5e61ed); + int x1 = display.windowWidth / 4; + int x2 = display.windowWidth * 3 / 4; + int y1 = display.windowHeight * 2 / 5; + int y2 = Math.Min(y1 + 4, display.windowHeight - 2); + int selectedAnswer = 0; + bool redraw = true; + while (true) { + display.DrawTextBox(TextDisplay.HAlignment.Center, TextDisplay.VAlignment.Center, TextDisplay.BoxType.Simple, y1, x1, question.answers[0], selectedAnswer != 0 ? 0xffffff : 0x1a03a0, selectedAnswer != 0 ? 0xffffff : 0x1a03a0, selectedAnswer != 0 ? 0x1a03a0 : 0xffffff); + if (question.answers.Count >= 2) + display.DrawTextBox(TextDisplay.HAlignment.Center, TextDisplay.VAlignment.Center, TextDisplay.BoxType.Simple, y1, x2, question.answers[1], selectedAnswer != 1 ? 0xffffff : 0x1a03a0, selectedAnswer != 1 ? 0xffffff : 0x1a03a0, selectedAnswer != 1 ? 0x1a03a0 : 0xffffff); + if (question.answers.Count >= 3) + display.DrawTextBox(TextDisplay.HAlignment.Center, TextDisplay.VAlignment.Center, TextDisplay.BoxType.Simple, y2, x1, question.answers[2], selectedAnswer != 2 ? 0xffffff : 0x1a03a0, selectedAnswer != 2 ? 0xffffff : 0x1a03a0, selectedAnswer != 2 ? 0x1a03a0 : 0xffffff); + if (question.answers.Count >= 4) + display.DrawTextBox(TextDisplay.HAlignment.Center, TextDisplay.VAlignment.Center, TextDisplay.BoxType.Simple, y2, x2, question.answers[3], selectedAnswer != 3 ? 0xffffff : 0x1a03a0, selectedAnswer != 3 ? 0xffffff : 0x1a03a0, selectedAnswer != 3 ? 0x1a03a0 : 0xffffff); + + bool end = false; + while (true) { + var key = Console.ReadKey(true); + if (key.Key == ConsoleKey.UpArrow) { + if (selectedAnswer == 2 || selectedAnswer == 3) { + redraw = true; + selectedAnswer -= 2; + break; + } + } else if (key.Key == ConsoleKey.DownArrow) { + if (selectedAnswer == 0 || selectedAnswer == 1) { + redraw = true; + selectedAnswer += 2; + break; + } + } else if (key.Key == ConsoleKey.RightArrow) { + if (selectedAnswer == 0 || selectedAnswer == 2) { + redraw = true; + selectedAnswer += 1; + break; + } + } else if (key.Key == ConsoleKey.LeftArrow) { + if (selectedAnswer == 1 || selectedAnswer == 3) { + redraw = true; + selectedAnswer -= 1; + break; + } + } else if (key.Key == ConsoleKey.Enter) { + end = true; + break; + } + } + if (end) { + if (selectedAnswer == question.correctAnswer) { + correntAnswers++; + } + break; + } + } + } + display.ShowMainGameScreenBase(); + display.DrawText(TextDisplay.HAlignment.Center, TextDisplay.VAlignment.Center, display.windowHeight / 4, display.windowWidth / 2 + 1, String.Format(I18n.GetMessage(I18n.Message.GAME_OVER), correntAnswers, questions.Count), 0xffffff, 0x5e61ed); + + Console.ReadKey(); + display.ResetWindow(); return 0; diff --git a/App/UI/TextDisplay.cs b/App/UI/TextDisplay.cs index 6194983..7af3681 100644 --- a/App/UI/TextDisplay.cs +++ b/App/UI/TextDisplay.cs @@ -1,6 +1,7 @@ using static Game.I18n; using System.Runtime.InteropServices; using System.Text; +using static Game.UI.TextDisplay; namespace Game.UI { public class TextDisplay { @@ -18,7 +19,7 @@ namespace Game.UI { private int currentFgColor = 0xffffff, currentBgColor = 0; private int cursorRow = 0, cursorCol = 0; - private int windowWidth = 0, windowHeight = 0; + public int windowWidth = 0, windowHeight = 0; public bool InitWindow() { if (Console.IsOutputRedirected) { @@ -40,7 +41,7 @@ namespace Game.UI { Console.WriteLine(GetMessage(Message.ERROR_GETCONSOLEMODE)); return false; } - inConsoleMode |= Win32Imports.ENABLE_VIRTUAL_TERMINAL_INPUT; + //inConsoleMode |= Win32Imports.ENABLE_VIRTUAL_TERMINAL_INPUT; //inConsoleMode &= ~Win32Imports.ENABLE_LINE_INPUT; outConsoleMode |= Win32Imports.ENABLE_VIRTUAL_TERMINAL_PROCESSING; if (!Win32Imports.SetConsoleMode(consoleInHandle, inConsoleMode)) { @@ -123,7 +124,7 @@ namespace Game.UI { WriteColored(bottomText, 0x4d4dc0, bgColor); } - void DrawTextBox(HAlignment hAlign, VAlignment vAlign, BoxType boxType, int y, int x, string text, int borderColor, int textColor, int bgColor = -1, int preferredWidth = -1) { + public void DrawTextBox(HAlignment hAlign, VAlignment vAlign, BoxType boxType, int y, int x, string text, int borderColor, int textColor, int bgColor = -1, int preferredWidth = -1) { int maxWidth = windowWidth; switch (hAlign) { case HAlignment.Left: @@ -148,21 +149,61 @@ namespace Game.UI { maxHeight = y - 1; break; } - string[] lines = WordWrap(text, (preferredWidth == -1 ? maxWidth : preferredWidth) - 4, out bool overflow); + string[] lines = WordWrap(text, (preferredWidth == -1 ? maxWidth : preferredWidth) - 2, out bool overflow); bool reflowed = false; - if (preferredWidth != -1 && lines.Length > maxHeight - 4) { + if (preferredWidth != -1 && lines.Length > maxHeight - 2) { reflowed = true; - lines = WordWrap(text, maxWidth - 4, out overflow); + lines = WordWrap(text, maxWidth - 2, out overflow); } - int actualWidth = Math.Min(preferredWidth == -1 ? maxWidth : (reflowed ? maxWidth : preferredWidth), lines.Max(s => s.Length) + 4); - int actualHeight = Math.Min(maxHeight, lines.Length + 4); + int actualWidth = Math.Min(preferredWidth == -1 ? maxWidth : (reflowed ? maxWidth : preferredWidth), lines.Max(s => s.Length) + 4) + 1; + int actualHeight = Math.Min(maxHeight, lines.Length + 2); int left = hAlign == HAlignment.Left ? x : (hAlign == HAlignment.Right ? x - actualWidth + 1 : x - (actualWidth - 1) / 2); int top = vAlign == VAlignment.Top ? y : (vAlign == VAlignment.Bottom ? y - actualHeight + 1 : y - (actualHeight - 1) / 2); DrawBox(boxType, top, left, actualHeight, actualWidth, borderColor, bgColor); SetColors(textColor, -1); - for (int i = 0; i < actualHeight - 4; ++i) { - SetCursor(top + 2 + i, left + 2); + for (int i = 0; i < actualHeight - 2; ++i) { + SetCursor(top + 1 + i, left + 2); + WriteColored(lines[i], textColor, bgColor); + } + } + + public void DrawText(HAlignment hAlign, VAlignment vAlign, int y, int x, string text, int textColor, int bgColor = -1) { + int maxWidth = windowWidth; + switch (hAlign) { + case HAlignment.Left: + maxWidth = windowWidth - x + 1; + break; + case HAlignment.Center: + maxWidth = Math.Min(x - 1, windowWidth - x + 1) * 2; + break; + case HAlignment.Right: + maxWidth = x - 1; + break; + } + int maxHeight = windowHeight; + switch (vAlign) { + case VAlignment.Top: + maxHeight = windowHeight - y + 1; + break; + case VAlignment.Center: + maxHeight = Math.Min(y - 1, windowHeight - y + 1) * 2; + break; + case VAlignment.Bottom: + maxHeight = y - 1; + break; + } + string[] lines = WordWrap(text, maxWidth, out bool overflow); + + int actualWidth = Math.Min(maxWidth, lines.Max(s => s.Length)); + int actualHeight = Math.Min(maxHeight, lines.Length); + + int left = hAlign == HAlignment.Left ? x : (hAlign == HAlignment.Right ? x - actualWidth + 1 : x - (actualWidth - 1) / 2); + int top = vAlign == VAlignment.Top ? y : (vAlign == VAlignment.Bottom ? y - actualHeight + 1 : y - (actualHeight - 1) / 2); + + SetColors(textColor, -1); + for (int i = 0; i < actualHeight; ++i) { + SetCursor(top + i, left); WriteColored(lines[i], textColor, bgColor); } } @@ -253,7 +294,7 @@ namespace Game.UI { int remaining = width; foreach (string word in text.Split(new char[] {' ', '\n'}, StringSplitOptions.RemoveEmptyEntries)) { if (word.Length <= remaining) { - if (line.Length == 0 || line[^1] != ' ') { + if (line.Length != 0 && line[^1] != ' ') { line.Append(' '); remaining -= 1; }