Skip to content

Commit

Permalink
Add the new source files (1.1.0)
Browse files Browse the repository at this point in the history
  • Loading branch information
Wirmaple73 authored Jan 24, 2024
1 parent 5928ed2 commit 64847b4
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 70 deletions.
3 changes: 1 addition & 2 deletions Source/EscapeTheMaze/Classes/Entities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public Entity() { }
public Entity(Position position) => Position = position;

public void Draw() => IOManager.WriteAt(Character, Position, Color);
public void Hide() => IOManager.WriteAt(" ", Position);
public void Hide() => IOManager.WriteAt(' ', Position);
public void RedrawAt(Position position)
{
Hide();
Expand All @@ -26,7 +26,6 @@ public void RedrawAt(Position position)
}

public bool IsAtPosition(Position position) => Position == position;
public bool IsCloseTo(Entity entity) => Position.IsCloseTo(entity.Position);
}

public class Player : Entity
Expand Down
136 changes: 100 additions & 36 deletions Source/EscapeTheMaze/Classes/Managers/GameManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace EscapeTheMaze.Managers
public static class GameManager
{
// Constants
public const int MaxRounds = 10;
private const int Rounds = 10;

// Constants - Score/Balance modifiers
public const int ExitPointModifier = 30;
Expand All @@ -34,8 +34,8 @@ public static class GameManager

// Constants - Walls
public const int WallTopOffset = 2;
private const int WallDensityMin = 520;
private const int WallDensityMax = 600;
private const int WallDensityMin = 750;
private const int WallDensityMax = 900;

// Utilities
private static readonly GameRandom random = new(Environment.TickCount + Guid.NewGuid().GetHashCode());
Expand Down Expand Up @@ -77,7 +77,7 @@ public static void Play()
roundTimer.Elapsed += RoundTimer_Elapsed;
ResetGameVariables();

while (++currentRound <= MaxRounds)
while (++currentRound <= Rounds)
{
IOManager.StartNewPage();

Expand Down Expand Up @@ -176,18 +176,71 @@ static void GenerateWalls()
static void SpawnEntities()
{
// Primary entities
SpawnEntityAt(EntityType.Player, random.NextPosition(true));
SpawnEntityAt(EntityType.ExitPoint, random.NextPositionFarFrom(player.Position, true));
Position playerPosition, exitPointPosition;

do
{
// Ensure there's no softlock
playerPosition = random.NextPosition(true);
exitPointPosition = random.NextPositionFarFrom(playerPosition, true);
} while (!ArePositionsConnected(playerPosition, exitPointPosition));

SpawnEntityAt(EntityType.Player, playerPosition);
SpawnEntityAt(EntityType.ExitPoint, exitPointPosition);

// Secondary entities
SpawnEntityWithChance(EntityType.BonusPoint, BonusPointSpawnChance, MaxBonusPoints);
SpawnEntityWithChance(EntityType.Coin, CoinSpawnChance, MaxCoins);
SpawnEntityWithChance(EntityType.FirstAidKit, FirstAidKitSpawnChance, MaxFirstAidKits);
SpawnEntityWithChance(EntityType.Hourglass, HourglassSpawnChance, MaxHourglasses);

// Ensure that no walls surround the player & exit point

// Obsolete: the softlock is now fixed, so there's no need to clear the nearby walls anymore
/*
ClearWallsAroundEntity(player);
ClearWallsAroundEntity(exitPoint);
*/

static bool ArePositionsConnected(Position subject, Position target)
{
// Basically the flood-fill algorithm along with an additional list to keep track of checked positions, which greatly speeds the check up

var checkedPositions = new List<Position>();

var q = new Queue<Position>();
q.Enqueue(subject);

while (q.Count > 0)
{
var n = q.Dequeue();

if (!walls.Any(wall => wall.IsAtPosition(n)))
{
if (n == target)
return true;

EnqueueIfNecessary(-1, 0); // West
EnqueueIfNecessary(1, 0); // East
EnqueueIfNecessary(0, -1); // North
EnqueueIfNecessary(0, 1); // South

if (Program.DisplayFloodFillTracers)
IOManager.WriteAt("0", n, Cyan);
}

void EnqueueIfNecessary(int leftOffset, int topOffset)
{
var position = new Position(n.Left + leftOffset, n.Top + topOffset);

if (checkedPositions.Contains(position) || walls.Any(wall => wall.IsAtPosition(position)))
return;

q.Enqueue(position);
checkedPositions.Add(position);
}
}

return false;
}

static void SpawnEntityWithChance(EntityType entityType, double chance, int maxOccurrences)
{
Expand All @@ -203,6 +256,7 @@ static void SpawnEntityWithChance(EntityType entityType, double chance, int maxO
}
}

/*
static void ClearWallsAroundEntity(Entity entity)
{
var position = entity.Position;
Expand All @@ -221,6 +275,7 @@ static void ClearWallsAroundEntity(Entity entity)
}
entity.Draw();
}
*/
}

static void SpawnEntityAt(EntityType entityType, Position position)
Expand Down Expand Up @@ -353,29 +408,22 @@ static void SetTimersEnabled(bool enabled)
static EntityType GetCollisionType()
{
if (player.IsAtPosition(exitPoint.Position))
{
return EntityType.ExitPoint;
}
else if (walls.Any(IsCollidingWithPlayer()))
{

if (walls.Any(IsCollidingWithPlayer()))
return EntityType.Wall;
}
else if (bonusPoints.Any(IsCollidingWithPlayer()))
{

if (bonusPoints.Any(IsCollidingWithPlayer()))
return EntityType.BonusPoint;
}
else if (coins.Any(IsCollidingWithPlayer()))
{

if (coins.Any(IsCollidingWithPlayer()))
return EntityType.Coin;
}
else if (firstAidKits.Any(IsCollidingWithPlayer()))
{

if (firstAidKits.Any(IsCollidingWithPlayer()))
return EntityType.FirstAidKit;
}
else if (hourglasses.Any(IsCollidingWithPlayer()))
{

if (hourglasses.Any(IsCollidingWithPlayer()))
return EntityType.Hourglass;
}

return EntityType.None;
}
Expand Down Expand Up @@ -477,10 +525,20 @@ static void DisplayRoundStats()
}

IOManager.WriteHeader($"Round {currentRound} statistics");
Console.WriteLine($"Hearts: {currentHearts}");
Console.WriteLine($"Score: {currentScore}");
Console.WriteLine($"Balance: ${currentBalance}");
Console.WriteLine($"Time elapsed: {roundStopwatch.Elapsed:mm':'ss'.'ff}");

IOManager.WriteColored(false, false,
("Hearts: ", Constants.KeyColor),
($"{currentHearts}\n", wallColor),

("Score: ", Constants.KeyColor),
($"{currentScore}\n", wallColor),

("Balance: ", Constants.KeyColor),
($"{currentBalance}\n", wallColor),

("Time elapsed: ", Constants.KeyColor),
($"{roundStopwatch.Elapsed:mm':'ss'.'ff}\n", wallColor)
);

if (roundState == RoundState.Failure)
IOManager.WriteColored("\nDon't worry, you can always do better!", Cyan, true);
Expand All @@ -497,9 +555,15 @@ static void DisplayGameStats()
IOManager.WriteHeader("Game statistics");

IOManager.WriteColored(false, false,
($"Total score: {currentScore} {(currentScore > CurrentUser.TopScore ? "(New top score!)" : "")}\n", Gray),
($"Total cash collected: ${currentBalance}\n", Gray),
($"Total time elapsed: {gameStopwatch.Elapsed:mm':'ss'.'ff}\n\n", Gray)
("Total score: ", Constants.KeyColor),
(currentScore.ToString(), wallColor),
($"{(currentScore > CurrentUser.TopScore ? " (New top score!)" : "")}\n", Constants.KeyColor),

("Total cash collected: ", Constants.KeyColor),
($"${currentBalance}\n", wallColor),

("Total time elapsed: ", Constants.KeyColor),
($"{gameStopwatch.Elapsed:mm':'ss'.'ff}\n\n", wallColor)
);

if (roundState == RoundState.Successful)
Expand All @@ -510,9 +574,9 @@ static void DisplayGameStats()
if (currentScore >= ExtraBonusScoreThreshold)
{
IOManager.WriteColored(false, false,
("You've received an additional ", Gray),
("You've received an additional ", Constants.KeyColor),
($"${ExtraBonusAmount} ", Green),
("bonus for your performance, keep it up!\n", Gray)
("bonus for your performance, keep it up!\n", Constants.KeyColor)
);

currentBalance += ExtraBonusAmount;
Expand Down Expand Up @@ -565,14 +629,14 @@ private static void RoundTimer_Elapsed(object sender, ElapsedEventArgs e)

ConsoleColor valueColor = wallColor;

bool isLowOnHearts = currentHearts <= 2;
bool isLowOnHearts = currentHearts <= 2;
bool isRunningOutOfTime = currentTimeLeft <= 10;

IOManager.ClearLine(0);
IOManager.ClearLine(1);

IOManager.WriteColored(false, true,
($"Round ", Constants.KeyColor), ($"{currentRound}", valueColor), ("/", Constants.KeyColor), ($"{MaxRounds}", valueColor),
($"Round ", Constants.KeyColor), ($"{currentRound}", valueColor), ("/", Constants.KeyColor), ($"{Rounds}", valueColor),
($"{separator}Hearts: ", Constants.KeyColor), (currentHearts.ToString(), isLowOnHearts ? LowValueColor : valueColor),
($"{separator}Armors: ", Constants.KeyColor), (currentArmors.ToString(), valueColor),
($"{separator}Score: ", Constants.KeyColor), (currentScore.ToString(), valueColor),
Expand Down
13 changes: 12 additions & 1 deletion Source/EscapeTheMaze/Classes/Managers/IOManager.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Linq;
using System.Runtime.CompilerServices;

namespace EscapeTheMaze.Managers
Expand Down Expand Up @@ -109,6 +108,18 @@ public static void StartNewPage(bool isCursorVisible = false)
Console.CursorVisible = isCursorVisible;
}

public static string Read(string prompt = null, ConsoleColor color = ConsoleColor.Gray, bool trimWhitespace = false)
{
if (prompt is not null)
Console.Write(prompt);

Console.ForegroundColor = color;
string value = Console.ReadLine();

Console.ResetColor();
return trimWhitespace ? value.StripExtraWhitespace().Trim() : value;
}

public static ConsoleKeyInfo WaitForKeyPress(string prompt = null, bool acceptOnlyEnter = false, bool playAudioEffect = true)
{
ConsoleKeyInfo keyInfo;
Expand Down
49 changes: 27 additions & 22 deletions Source/EscapeTheMaze/Classes/Managers/UIManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public static class UIManager
private static readonly Random random = new();

private static readonly ConsoleColor[] logoColors = { Yellow, Cyan, Magenta, Green, White };
private static readonly string[] goodbyeMessages = { "Have a great day!", "See you later!" };
private static readonly string[] goodbyeMessages = { "Have a great day!", "See you later!", "See you soon!" };

private static readonly Encoding defaultEncoding = Encoding.UTF8;

Expand Down Expand Up @@ -48,7 +48,7 @@ In the name of God
██ ██ ██ ██
██ ███████ █████
██ ██ ██ ██
██ ██ ██ ███████", 0, 0, Gray);
██ ██ ██ ███████", 0, 0, Constants.KeyColor);

IOManager.WriteAt(@$"
███╗ ███╗ █████╗ ███████╗███████╗
Expand All @@ -73,10 +73,11 @@ public static void DisplayLoginPageAndStoreUser()
{
IOManager.StartNewPage(true);

Console.WriteLine($"Please choose a username to use in-game [Max length: {maxUsernameLength} characters]");
Console.WriteLine("(Please make sure to enter your exact username if you wish to log in):");
username = IOManager.Read(
$"Please choose a username to use in-game [Max length: {maxUsernameLength} characters]\n(Please make sure to enter your exact username if you wish to log in):\n",
Yellow, true
);

username = Console.ReadLine().StripExtraWhitespace().Trim();
} while (string.IsNullOrWhiteSpace(username) || username.Length > maxUsernameLength);

UserManager.StoreCurrentUserIndex(username);
Expand All @@ -88,9 +89,13 @@ public static SelectedMenuItem DisplayMainMenu()
while (true)
{
IOManager.StartNewPage(true);

DisplayVersionInfo();
Console.WriteLine($"{(UserManager.IsNewUser ? "Hello there" : "Welcome back")}, {CurrentUser.Username}!\n");

IOManager.WriteColored(false, false,
($"{(UserManager.IsNewUser ? "Hello there" : "Welcome back")}, ", Constants.KeyColor),
(CurrentUser.Username, Yellow),
("!\n\n", Constants.KeyColor)
);

IOManager.DrawMenu(
"Play", "Leaderboard", "Upgrade shop", "Change account", "Check for updates", "About", "Exit"
Expand All @@ -99,7 +104,7 @@ public static SelectedMenuItem DisplayMainMenu()
if (Program.IsDebugModeEnabled)
IOManager.DrawMenu((8, "[DEBUG] Import users"), (9, "[DEBUG] Export users"));

char selectedOption = IOManager.WaitForKeyPress("\nPlease select an option [1-7]: ").KeyChar;
char selectedOption = IOManager.WaitForKeyPress($"\nPlease select an option [1-{(Program.IsDebugModeEnabled ? 9 : 7)}]: ").KeyChar;

switch (selectedOption)
{
Expand All @@ -124,7 +129,7 @@ public static bool DisplayGameGuide()
IOManager.StartNewPage();
IOManager.SetBufferHeight(5);

IOManager.WriteColored("Welcome to Escape The Maze, a game where you have to reach the 'Exit point' while dodging 'Walls', optionally collecting 'Bonus points' for a score bonus and also 'Coins' which can be spent in the game's upgrade shop.\n", Gray, true, true);
IOManager.WriteColored("Welcome to Escape The Maze, a game where you have to reach the 'Exit point' while dodging 'Walls', optionally collecting 'Bonus points' for a score bonus and also 'Coins' which can be spent in the game's upgrade shop.\n", Constants.KeyColor, true, true);

IOManager.WriteHeader("Game entities and their descriptions");
DisplayEntityInfo<Player>();
Expand Down Expand Up @@ -224,12 +229,12 @@ public static void DisplayUpgradeShop()
IOManager.StartNewPage();
IOManager.SetBufferHeight(upgrades.Length + 20);

IOManager.WriteColored("Welcome to the upgrade shop! you can purchase new upgrades for your character here with the coins you collect in-game.\n\n", Gray, wrapText: true);
IOManager.WriteColored("Welcome to the upgrade shop! you can purchase new upgrades for your character here with the coins you collect in-game.\n\n", Constants.KeyColor, wrapText: true);
IOManager.WriteColored(false, false,
("Your balance: ", Gray),
($"${CurrentUser.Balance:N0}", Green),
($"/", Gray),
($"${UpgradeManager.WalletCapacity:N0}\n", Green),
("Your balance: ", Constants.KeyColor),
($"${CurrentUser.Balance:N0}", Constants.ValueColor),
($"/", Constants.KeyColor),
($"${UpgradeManager.WalletCapacity:N0}\n", Constants.ValueColor),
("Your level: ", Constants.KeyColor),
($"{CurrentUser.Level}\n\n", Constants.ValueColor)
);
Expand Down Expand Up @@ -281,11 +286,11 @@ public static void DisplayUpgradeShop()
if (CurrentUser.Level >= selectedUpgrade.RequiredLevel)
{
bool isConfirmed = IOManager.WriteConfirmationMessage(
("Are you sure you want to purchase the upgrade \"", Gray),
("Are you sure you want to purchase the upgrade \"", Constants.KeyColor),
(selectedUpgrade.Name, Cyan),
("\" for ", Gray),
($"${selectedUpgrade.Price:N0}", Green),
("?", Gray)
("\" for ", Constants.KeyColor),
($"${selectedUpgrade.Price:N0}", Constants.ValueColor),
("?", Constants.KeyColor)
);

if (isConfirmed)
Expand All @@ -296,11 +301,11 @@ public static void DisplayUpgradeShop()
AudioManager.Play(AudioEffect.UpgradePurchase);

IOManager.WriteColored(true, false,
("Successfully purchased the upgrade \"", Gray),
("Successfully purchased the upgrade \"", Constants.KeyColor),
(selectedUpgrade.Name, Cyan),
("\" for ", Gray),
($"${selectedUpgrade.Price:N0}", Green),
(".\n", Gray)
("\" for ", Constants.KeyColor),
($"${selectedUpgrade.Price:N0}", Constants.ValueColor),
(".\n", Constants.KeyColor)
);

// Handle 'special' upgrades
Expand Down
Loading

0 comments on commit 64847b4

Please sign in to comment.