diff --git a/Projects/Console Monsters/Audio/italienne for game.wav b/Projects/Console Monsters/Audio/Asriel-Exploration8Bit.wav similarity index 100% rename from Projects/Console Monsters/Audio/italienne for game.wav rename to Projects/Console Monsters/Audio/Asriel-Exploration8Bit.wav diff --git a/Projects/Console Monsters/Audio/either a cute outdoor place or inside a house.wav b/Projects/Console Monsters/Audio/Asriel-HappyTune8Bit.wav similarity index 100% rename from Projects/Console Monsters/Audio/either a cute outdoor place or inside a house.wav rename to Projects/Console Monsters/Audio/Asriel-HappyTune8Bit.wav diff --git a/Projects/Console Monsters/Audio/either a cute outdoor place or inside a house - piano.wav b/Projects/Console Monsters/Audio/Asriel-HappyTunePiano.wav similarity index 100% rename from Projects/Console Monsters/Audio/either a cute outdoor place or inside a house - piano.wav rename to Projects/Console Monsters/Audio/Asriel-HappyTunePiano.wav diff --git a/Projects/Console Monsters/Audio/AudioController.cs b/Projects/Console Monsters/Audio/AudioController.cs index 8c244de8..cc18d073 100644 --- a/Projects/Console Monsters/Audio/AudioController.cs +++ b/Projects/Console Monsters/Audio/AudioController.cs @@ -6,7 +6,7 @@ public static class AudioController { public static readonly string CoDA_Lullaby = "Console_Monsters.Audio.CoDA-Lullaby.wav"; - private readonly static System.Media.SoundPlayer? soundPlayer; + private static readonly System.Media.SoundPlayer? soundPlayer; private static string? recoursePlaying; diff --git a/Projects/Console Monsters/Audio/backclick.wav b/Projects/Console Monsters/Audio/CoDa-BackClick.wav similarity index 100% rename from Projects/Console Monsters/Audio/backclick.wav rename to Projects/Console Monsters/Audio/CoDa-BackClick.wav diff --git a/Projects/Console Monsters/Audio/Enterclick.wav b/Projects/Console Monsters/Audio/CoDa-EnterClick.wav similarity index 100% rename from Projects/Console Monsters/Audio/Enterclick.wav rename to Projects/Console Monsters/Audio/CoDa-EnterClick.wav diff --git a/Projects/Console Monsters/Audio/Menuclick.wav b/Projects/Console Monsters/Audio/CoDa-MenuClick.wav similarity index 100% rename from Projects/Console Monsters/Audio/Menuclick.wav rename to Projects/Console Monsters/Audio/CoDa-MenuClick.wav diff --git a/Projects/Console Monsters/Audio/flutemusicidea.wav b/Projects/Console Monsters/Audio/US-FluteMusicIdea.wav similarity index 100% rename from Projects/Console Monsters/Audio/flutemusicidea.wav rename to Projects/Console Monsters/Audio/US-FluteMusicIdea.wav diff --git a/Projects/Console Monsters/Audio/lute-string-melody-ideas.wav b/Projects/Console Monsters/Audio/US-LuteStringMelodyIdeas.wav similarity index 100% rename from Projects/Console Monsters/Audio/lute-string-melody-ideas.wav rename to Projects/Console Monsters/Audio/US-LuteStringMelodyIdeas.wav diff --git a/Projects/Console Monsters/Audio/spookylandscapewindsfx.wav b/Projects/Console Monsters/Audio/US-SpookyLandscape.wav similarity index 100% rename from Projects/Console Monsters/Audio/spookylandscapewindsfx.wav rename to Projects/Console Monsters/Audio/US-SpookyLandscape.wav diff --git a/Projects/Console Monsters/Bases/CharacterBase.cs b/Projects/Console Monsters/Bases/CharacterBase.cs index 23de38c5..909d0976 100644 --- a/Projects/Console Monsters/Bases/CharacterBase.cs +++ b/Projects/Console Monsters/Bases/CharacterBase.cs @@ -6,6 +6,8 @@ public abstract class CharacterBase : InteractableBase public string[]? Dialogue { get; set; } + public string[]? QuestDialogue { get; set; } + public string Sprite { get; set; } = Sprites.Error; public string[]? SpriteAnimation { get; set; } diff --git a/Projects/Console Monsters/Bases/ItemBase.cs b/Projects/Console Monsters/Bases/ItemBase.cs index daa96015..4df2ce67 100644 --- a/Projects/Console Monsters/Bases/ItemBase.cs +++ b/Projects/Console Monsters/Bases/ItemBase.cs @@ -6,6 +6,8 @@ public abstract class ItemBase public abstract string? Description { get; } + public virtual ItemCategory Category { get; } + public abstract string Sprite { get; } // we may want to change the following but doing this for now... @@ -14,4 +16,11 @@ public abstract class ItemBase public static bool operator !=(ItemBase a, ItemBase b) => !(a == b); public override bool Equals(object? obj) => obj is ItemBase item && this == item; public override int GetHashCode() => this.GetType().GetHashCode(); + + public enum ItemCategory + { + Potions = 1, + MonsterBoxes = 2, + Miscellaneous= 3, + } } diff --git a/Projects/Console Monsters/Bases/MapBase.cs b/Projects/Console Monsters/Bases/MapBase.cs index 68158526..96ba2e5c 100644 --- a/Projects/Console Monsters/Bases/MapBase.cs +++ b/Projects/Console Monsters/Bases/MapBase.cs @@ -11,15 +11,15 @@ public static (int I, int J) WorldToTile(int i, int j) } /// Relocates the player to the top-left most occurence of a character in a . - public void SpawnCharacterOn(char c) + public void SpawnPlayerOn(char c) { (int I, int J)? tile = FindTileInMap(c); if (tile is null) { throw new InvalidOperationException("Attempting to spawn the player on a non-existing tile."); } - character.I = tile.Value.I * Sprites.Width; - character.J = tile.Value.J * Sprites.Height; + player.I = tile.Value.I * Sprites.Width; + player.J = tile.Value.J * Sprites.Height; } /// Finds the top-left most occurence of a character in a . @@ -57,4 +57,6 @@ public void SpawnCharacterOn(char c) public abstract void PerformTileAction(int i, int j); public abstract char[][] SpriteSheet { get; } + + public string? SpawnType { get; set; } } diff --git a/Projects/Console Monsters/Bases/MonsterBase.cs b/Projects/Console Monsters/Bases/MonsterBase.cs index 20e3c89f..1fc1bf7b 100644 --- a/Projects/Console Monsters/Bases/MonsterBase.cs +++ b/Projects/Console Monsters/Bases/MonsterBase.cs @@ -1,4 +1,5 @@ -using System.Reflection; +using System.Linq; +using System.Reflection; namespace Console_Monsters.Bases; @@ -8,36 +9,44 @@ public abstract class MonsterBase public int Level { get; set; } - public int ExperiencePoints { get; set; } - - public int CurrentHP { get; set; } + public List? MonsterType { get; set; } - public int MaximumHP { get; set; } + public int ExperiencePoints { get; set; } - public int CurrentEnergy { get; set; } + public double HPStat { get; set; } + public double CurrentHP { get; set; } + public double MaximumHP { get; set; } - public int MaximumEnergy { get; set; } + public double BaseEnergy { get; set; } + public double CurrentEnergy { get; set; } + public double MaximumEnergy { get; set; } public int Evolution { get; set; } public abstract string[] Sprite { get; } - public int AttackStat { get; set; } + //// In case we want the monster to follow the player in the map view. + //public abstract string[] SmallSprite { get; } - public int SpeedStat { get; set; } + public int AttackStat { get; set; } + public int SpecialAttackStat { get; set; } public int DefenseStat { get; set; } + public int SpecialDefenseStat { get; set; } - public List? MoveSet { get; set; } + public int SpeedStat { get; set; } - public string? Description { get; set; } + public int AccuracyStat { get; set; } = 100; - //public AnimalType Type { get; set; } + public int EvasionStat { get; set; } = 100; - //public string? StatusCondition { get; set; } + public int Statexp { get; set; } + public List? MoveSet { get; set; } - //public static MonsterBase GetRandom(){} + public string? Description { get; set; } + + public string? StatusCondition { get; set; } public static MonsterBase GetRandom() { @@ -47,4 +56,43 @@ public static MonsterBase GetRandom() MonsterBase monster = (MonsterBase)Activator.CreateInstance(monsterType)!; return monster; } + public static void WildMonster(MonsterBase OpponentMonster) + { + OpponentMonster.Level = SetRandomLevelForWildMonster(partyMonsters); + OpponentMonster.MaximumHP = SetMaxHPFromBase(OpponentMonster.HPStat, OpponentMonster.Level, OpponentMonster.Statexp); + OpponentMonster.CurrentHP = OpponentMonster.MaximumHP; + } + + public static int SetRandomLevelForWildMonster(List playerMonsters) + { + List monsterLvls = new(); + for (int i = 0; i < playerMonsters.Count; i++) + monsterLvls.Add(playerMonsters[i].Level); + + int level = Random.Shared.Next(monsterLvls.AsQueryable().Min()-4, monsterLvls.AsQueryable().Max()+5); + + return level; + } + + public static double SetMaxHPFromBase(double baseHP, int level, int statexp) + { + //int HPStatExp // IN CASE WE HAVE IV's ------ https://bulbapedia.bulbagarden.net/wiki/Stat + double maxHP = ((((baseHP + 6) * 2 + (Math.Sqrt(statexp) / 4)) * level) / 100) + level + 10; + + return maxHP; + } + + public static double SetMaxEnergyFromBase(double baseEN, int level) + { + double maxEN = (((baseEN * 2 + (Math.Sqrt(1) / 4)) * level) / 20) + level + 10; + + return maxEN; + } + + public static double SetMaxOtherStatFromBase(double baseHP, int level) + { + double maxHP = (((baseHP * 2) * level) / 100) + 5; + + return maxHP; + } } diff --git a/Projects/Console Monsters/Bases/MoveBase.cs b/Projects/Console Monsters/Bases/MoveBase.cs index 7223da8b..3a59318d 100644 --- a/Projects/Console Monsters/Bases/MoveBase.cs +++ b/Projects/Console Monsters/Bases/MoveBase.cs @@ -6,24 +6,55 @@ public abstract class MoveBase { public string? Name { get; set; } - public double BaseDamge { get; set; } + public int Priority { get; set; } - public double FinalDamage { get; set; } + public double BaseDamage { get; set; } public int EnergyTaken { get; set; } - public DamageType? DamageType { get; } + public DamageType? DamageType { get; set; } - public Element? Element { get; } + public CMType? Element { get; set; } public string? Description { get; set; } public static MoveBase GetRandomMove() { Assembly assembly = Assembly.GetExecutingAssembly(); - Type[] moveTypes = assembly.GetTypes().Where(t => t.BaseType == typeof(MoveBase)).ToArray(); - Type moveType = moveTypes[Random.Shared.Next(moveTypes.Length)]; + System.Type[] moveTypes = assembly.GetTypes().Where(t => t.BaseType == typeof(MoveBase)).ToArray(); + System.Type moveType = moveTypes[Random.Shared.Next(moveTypes.Length)]; MoveBase move = (MoveBase)Activator.CreateInstance(moveType)!; return move; } + + public double CalculateDamage(MonsterBase attackingMonster, MonsterBase defendingMonster, MoveBase move) + { + //Critical Damage Chance + Random random = new(); + int critical = 1; + + //OG is 256 / 256, but for playablity sake it will be higher until further changes +#warning FIX critical + //int num = random.Next(0, 1001); + //if(num < random.Next(0, 1001) && move.DamageType != Enums.DamageType.Special) + //{ + // critical = (attackingMonster.Level * 2 + 5) / attackingMonster.Level + 5; + //} + + if (attackingMonster.AttackStat > 255) + attackingMonster.AttackStat /= 4; + if (defendingMonster.DefenseStat > 255) + defendingMonster.DefenseStat /= 4; + + double dmg = (((2 * attackingMonster.Level * critical / 5 + 2) + * BaseDamage * attackingMonster.AttackStat / defendingMonster.DefenseStat) / 50 + 2) + * BattleRandom.Next(217, 256) / 255; + + return dmg; + } + + public void CalculateStatChange(MonsterBase opponent, MonsterBase player, MoveBase opponentMove) + { + + } } diff --git a/Projects/Console Monsters/Bases/QuestBase.cs b/Projects/Console Monsters/Bases/QuestBase.cs new file mode 100644 index 00000000..17447761 --- /dev/null +++ b/Projects/Console Monsters/Bases/QuestBase.cs @@ -0,0 +1,18 @@ +namespace Console_Monsters.Bases; + +public abstract class QuestBase +{ + public string? QuestName { get; set; } + + public string? QuestDescription { get; set; } + + public int QuestId { get; set; } + + public List? QuestNPCs { get; set; } + + public bool IsStoryLineQuest { get; set; } + + public abstract void TriggerQuestStart(); + + public abstract void TriggerQuestComplete(); +} diff --git a/Projects/Console Monsters/Bases/ShopBase.cs b/Projects/Console Monsters/Bases/ShopBase.cs new file mode 100644 index 00000000..8acbaf33 --- /dev/null +++ b/Projects/Console Monsters/Bases/ShopBase.cs @@ -0,0 +1,24 @@ +namespace Console_Monsters.Bases; + +public abstract class ShopBase +{ + public abstract string Name { get; } + + public virtual CharacterBase? Character { get; } + + public abstract List Inventory { get; } + + public class Row + { + public ItemBase Item { get; private set; } + public int Price { get; private set; } + public int Quantity { get; set; } + + public Row(ItemBase item, int price, int quantity) + { + Item = item; + Price = price; + Quantity = quantity; + } + } +} diff --git a/Projects/Console Monsters/BattleSystem.cs b/Projects/Console Monsters/BattleSystem.cs index 7fe92891..e661eb23 100644 --- a/Projects/Console Monsters/BattleSystem.cs +++ b/Projects/Console Monsters/BattleSystem.cs @@ -1,93 +1,348 @@ -namespace Console_Monsters; +using Console_Monsters.Moves; +using System.Diagnostics; + +namespace Console_Monsters; public class BattleSystem { - // TEMP FOR DEVELOPMENT, YES VERY MESSY, PLEASE FIX - public static FireLizard FireLizard { get; set; } = new(); - public static Turtle Turtle { get; set; } = new(); - - public static MonsterBase PlayerMonster { get; set; } = Turtle; - public static MonsterBase OpponentMonster { get; set; } = FireLizard; - - public static MonsterBase? AttackingMonster { get; set; } - public static MonsterBase? DefendingMonster { get; set; } + public struct BattleMonsters + { + public MonsterBase Player; + public MonsterBase Opponent; + } - public static void Battle() + public static void Battle(BattleMonsters monsters) { - bool playerTurn = true; bool battleOver = false; + MonsterBase losingMonster = new _EmptyMonster(); + + BattleScreen.Render(monsters.Player, monsters.Opponent); + BattleScreen.DrawStats(monsters.Player, monsters.Opponent); + DrawSingleBattleText($"You Encountered A Wild {monsters.Opponent.Name}", monsters); - if (OpponentMonster.SpeedStat > PlayerMonster.SpeedStat) + //BATTLE LOOP + while (!battleOver) { - playerTurn = false; + Turn(monsters); + BattleScreen.DrawStats(monsters.Player, monsters.Opponent); + + WaitTimeBetweenChange(); + + //Are all monsters dead on one side? + if (monsters.Player.CurrentHP <= 0) + { + battleOver = true; + losingMonster = monsters.Player; + } + else if (monsters.Opponent.CurrentHP <= 0) + { + battleOver = true; + losingMonster = monsters.Opponent; + } } - DrawStats(playerTurn); - while (!battleOver) + + //BATLE IS OVER + PromptBattleText = new string[] { - if (playerTurn) + $"{losingMonster.Name} Fainted", + $"BATTLE OVER Press [ENTER] to continue", + }; + + //Battle is over, remove the losing monster from screen + if (losingMonster == monsters.Opponent) + BattleScreen.Render(monsters.Player, new _EmptyMonster()); + else + BattleScreen.Render(new _EmptyMonster(), monsters.Opponent); + + ConsoleHelper.PressToContinue(); + } + + public static void Turn(BattleMonsters monsters) + { + //PLAYER CHOICE + (int playerPriority, string playerChoice, MoveBase playerMove, MonsterBase monsterToSwitchTo) = BattleSelectionMenu(monsters); + + //OPPONENT CHOICE + MoveBase opponentMove = MoveBase.GetRandomMove(); + int opponentPriority = opponentMove.Priority; + + //TURN DECIDER + bool playerFirst = TurnPlayerStartingMonster(monsters, playerMove, opponentMove); + + WaitTimeBetweenChange(); + + if (playerFirst || playerPriority > opponentPriority) + { + //PLAYER MOVE + switch (playerChoice) { - AttackingMonster = PlayerMonster; - DefendingMonster = OpponentMonster; - if (PlayerMonster.CurrentHP <= 0) - { - Console.Clear(); - Console.WriteLine("Player Lost"); - battleOver = true; - } - else - { + case "Attack": + PlayerAttack(monsters, playerMove); + break; + case "Monsters": + monsters.Player = monsterToSwitchTo; + break; + case "Inventory": - ConsoleHelper.PressToContinue(); - MoveBase playerMove = MoveBase.GetRandomMove(); - PlayerMonster.CurrentEnergy -= playerMove.EnergyTaken; - OpponentMonster.CurrentHP -= (int)playerMove.FinalDamage; - playerTurn = false; - DrawStats(playerTurn); - } + break; } - if (!playerTurn) - { - AttackingMonster = OpponentMonster; - DefendingMonster = PlayerMonster; - if (OpponentMonster.CurrentHP <= 0) + + WaitTimeBetweenChange(); + ClearBattleText(monsters); + + if (!CheckLostCurrentMonsters(monsters)) + //OPPONENT MOVE + OpponentAttack(monsters, opponentMove); + + WaitTimeBetweenChange(); + ClearBattleText(monsters); + } + else + { + //OPPONENT MOVE + OpponentAttack(monsters, opponentMove); + + WaitTimeBetweenChange(); + ClearBattleText(monsters); + + if (!CheckLostCurrentMonsters(monsters)) + //PLAYER MOVE + switch (playerChoice) { - Console.Clear(); - Console.WriteLine("CPU Lost"); - battleOver = true; + case "Attack": + PlayerAttack(monsters, playerMove); + break; + case "Monsters": + monsters.Player = monsterToSwitchTo; + break; + case "Inventory": + + break; } - else + + WaitTimeBetweenChange(); + ClearBattleText(monsters); + } + + } + + public static void PlayerAttack(BattleMonsters monsters, MoveBase playerMove) + { + DrawSingleBattleText($"{monsters.Player.Name} used {playerMove.Name}", monsters); + + monsters.Player.CurrentEnergy -= playerMove.EnergyTaken; + if (playerMove.DamageType != Enums.DamageType.Special && playerMove.BaseDamage != 0) + { + monsters.Opponent.CurrentHP -= + playerMove.CalculateDamage(monsters.Player, monsters.Opponent, playerMove); + } + else + { + playerMove.CalculateStatChange(monsters.Player, monsters.Opponent, playerMove); + } + + if (monsters.Opponent.CurrentHP < 0) monsters.Opponent.CurrentHP = 0; // So the hp will not display under 0 + if (monsters.Opponent.CurrentHP is < 1 and > 0) monsters.Opponent.CurrentHP = 1; //So it doesn't display 0 when decimals. + + BattleScreen.Render(monsters.Player, monsters.Opponent); + BattleScreen.DrawStats(monsters.Player, monsters.Opponent); + } + + public static void OpponentAttack(BattleMonsters monsters, MoveBase opponentMove) + { + DrawSingleBattleText($"{monsters.Opponent.Name} used {opponentMove.Name}", monsters); + + monsters.Opponent.CurrentEnergy -= opponentMove.EnergyTaken; + if (opponentMove.DamageType != Enums.DamageType.Special && opponentMove.BaseDamage != 0) + { + monsters.Player.CurrentHP -= + opponentMove.CalculateDamage(monsters.Opponent, monsters.Player, opponentMove); + } + else + { + opponentMove.CalculateStatChange(monsters.Opponent, monsters.Player, opponentMove); + } + + if (monsters.Player.CurrentHP < 0) monsters.Player.CurrentHP = 0; // So the hp will not display under 0 + if (monsters.Player.CurrentHP is < 1 and > 0) monsters.Player.CurrentHP = 1; //So it doesn't display 0 when decimals. + + BattleScreen.Render(monsters.Player, monsters.Opponent); + BattleScreen.DrawStats(monsters.Player, monsters.Opponent); + } + + public static bool TurnPlayerStartingMonster(BattleMonsters monsters, MoveBase playerMove, MoveBase opponentMove) + { + ClearBattleText(monsters); + + if (playerMove.Priority > opponentMove.Priority) + return true; + else if (opponentMove.Priority > playerMove.Priority) + return false; + + if (monsters.Player.SpeedStat > monsters.Opponent.SpeedStat) + return true; + + //In case they have the same Speed Stat and priority is the same + else if (monsters.Player.SpeedStat == monsters.Opponent.SpeedStat) + return Random.Shared.Next(2) == 0; + + return false; + } + + public static (int, string, MoveBase, MonsterBase) BattleSelectionMenu(BattleMonsters monsters) + { + string playerChoice = string.Empty; + int priority = 0; + + MoveBase playerMove = new _EmptyMove(); + MonsterBase monsterToSwitchTo = new _EmptyMonster(); + + PromptBattleText = new string[] + { + $"1. Attack 3. Inventory", + $"2. Monsters 4. Run" + }; + + BattleScreen.Render(monsters.Player, monsters.Opponent); + BattleScreen.DrawStats(monsters.Player, monsters.Opponent); + + //GET PLAYER INPUT + ReEnter: + ConsoleKey key = Console.ReadKey(true).Key; + switch (key.ToString()) + { + case "D1": // Attack + playerChoice = "Attack"; + PromptBattleText = new string[] + { + $"1. {monsters.Player.MoveSet[0].Name} 3. {monsters.Player.MoveSet[2].Name}", + $"2. {monsters.Player.MoveSet[1].Name} 4. {monsters.Player.MoveSet[3].Name}" + }; + + BattleScreen.Render(monsters.Player, monsters.Opponent); + BattleScreen.DrawStats(monsters.Player, monsters.Opponent); + + playerMove = InputToMonsterMove(monsters); + priority = playerMove.Priority; + + break; + case "D2": // Monsters + playerChoice = "Monsters"; + + //FIX + monsterToSwitchTo = MonsterSelectionMenu(monsters); + priority = 6; + + break; + case "D3": // Inventory + playerChoice = "Inventory"; + //FIX + + priority = 6; + + break; + case "D4": // Run + playerChoice = "Run"; + double escapeOdds = monsters.Player.SpeedStat * 32 / (monsters.Player.SpeedStat / 4) % 256; + if (escapeOdds > 255 || Random.Shared.Next(0, 256) < escapeOdds) { - ConsoleHelper.PressToContinue(); - MoveBase opponentMove = MoveBase.GetRandomMove(); - OpponentMonster.CurrentEnergy -= opponentMove.EnergyTaken; - PlayerMonster.CurrentHP -= (int)opponentMove.FinalDamage; - playerTurn = true; - DrawStats(playerTurn); + //Esacpe FIX } - } + priority = 6; + + break; + default: + goto ReEnter; + break; } - static void DrawStats(bool playerTurn) + return (priority, playerChoice, playerMove, monsterToSwitchTo); + } + + public static MonsterBase MonsterSelectionMenu(BattleMonsters monsters) + { + string empty = string.Empty; + +#warning FIX LOOK + PromptBattleText = new string[] { - //TEMP - Console.SetCursorPosition(63, 34); - Console.WriteLine($"HP:{PlayerMonster.CurrentHP} Energy:{PlayerMonster.CurrentEnergy} "); + $"1. {partyMonsters[0].Name} 2. {(partyMonsters.Count >= 2 ? partyMonsters[1].Name : empty)} 3. {(partyMonsters.Count >= 3 ? partyMonsters[2].Name : empty)}", + $"4. {(partyMonsters.Count >= 4 ? partyMonsters[3].Name : empty)} 5. {(partyMonsters.Count >= 5 ? partyMonsters[4].Name : empty)} 6. {(partyMonsters.Count >= 6 ? partyMonsters[5].Name : empty)}" + }; - Console.SetCursorPosition(102, 13); - Console.WriteLine($"HP:{OpponentMonster.CurrentHP} Energy:{OpponentMonster.CurrentEnergy} "); + BattleScreen.Render(monsters.Player, monsters.Opponent); + BattleScreen.DrawStats(monsters.Player, monsters.Opponent); - Console.SetCursorPosition(35, 5); - string turn; - if (playerTurn) - { - turn = "Player Turn"; - } - else - { - turn = "CPU Turn "; - } - Console.WriteLine(turn); + ConsoleKey key = Console.ReadKey(true).Key; + MonsterBase monsterToSwitchTo = key.ToString() switch + { + "D1" => partyMonsters[0], + "D2" => partyMonsters[1], + "D3" => partyMonsters[2], + "D4" => partyMonsters[3], + "D5" => partyMonsters[4], + "D6" => partyMonsters[5], + _ => MonsterSelectionMenu(monsters), + }; + return monsterToSwitchTo; + } + + public static void DrawSingleBattleText(string prompt, BattleMonsters monsters) + { + PromptBattleText = new string[] + { + //$"{AsciiGenerator.ToAscii($"{prompt}")}", + prompt, + }; + BattleScreen.Render(monsters.Player, monsters.Opponent); + BattleScreen.DrawStats(monsters.Player, monsters.Opponent); + } + public static void ClearBattleText(BattleMonsters monsters) + { + PromptBattleText = new string[] + { + " ", + }; + BattleScreen.Render(monsters.Player, monsters.Opponent); + BattleScreen.DrawStats(monsters.Player, monsters.Opponent); + } + + public static MoveBase InputToMonsterMove(BattleMonsters monsters) + { + ConsoleKey key = Console.ReadKey(true).Key; + MoveBase move = key.ToString() switch + { + "D1" => monsters.Player.MoveSet[0], + "D2" => monsters.Player.MoveSet[1], + "D3" => monsters.Player.MoveSet[2], + "D4" => monsters.Player.MoveSet[3], + _ => InputToMonsterMove(monsters), + }; + return move; + } + + public static void WaitTimeBetweenChange() + { + Stopwatch stopwatch = Stopwatch.StartNew(); + TimeSpan timeTaken = stopwatch.Elapsed; + double timeToWait = FastText ? 0.5 : 2; + + while (timeTaken.TotalSeconds <= timeToWait) + { + timeTaken = stopwatch.Elapsed; } + } + #region Check Lost Monster + public static bool CheckLostCurrentMonsters(BattleMonsters monsters) // Temp + { + if (monsters.Player.CurrentHP <= 0) + return true; + else if (monsters.Opponent.CurrentHP <= 0) + return true; + else + return false; } + #endregion + } diff --git a/Projects/Console Monsters/Characters/Camper.cs b/Projects/Console Monsters/Characters/Camper.cs index 501a8ef6..18aa86dd 100644 --- a/Projects/Console Monsters/Characters/Camper.cs +++ b/Projects/Console Monsters/Characters/Camper.cs @@ -15,7 +15,7 @@ public Camper() public override string? Name => "Camper"; - public static readonly string IdleFront = + private static readonly string IdleFront = @" ((())" + '\n' + @" ((( ^│" + '\n' + @" ╭╰─┬╯" + '\n' + diff --git a/Projects/Console Monsters/Characters/ChineseMan.cs b/Projects/Console Monsters/Characters/ChineseMan.cs index c94fa08c..e8139abe 100644 --- a/Projects/Console Monsters/Characters/ChineseMan.cs +++ b/Projects/Console Monsters/Characters/ChineseMan.cs @@ -15,7 +15,7 @@ public ChineseMan() public override string? Name => "Chinese Man"; - public static readonly string IdleFront = + private static readonly string IdleFront = @"/_____\" + '\n' + @" │'_'│ " + '\n' + @"╭╰───╯╮" + '\n' + diff --git a/Projects/Console Monsters/Characters/CopyPaste.cs b/Projects/Console Monsters/Characters/CopyPaste.cs index a9b0c8fe..7edc14f2 100644 --- a/Projects/Console Monsters/Characters/CopyPaste.cs +++ b/Projects/Console Monsters/Characters/CopyPaste.cs @@ -15,7 +15,7 @@ public name() public override string? Name => "name"; - public static readonly string IdleFront = + private static readonly string IdleFront = @"COPY" + '\n' + @"COPY" + '\n' + @"COPY" + '\n' + diff --git a/Projects/Console Monsters/Characters/LittleGirl.cs b/Projects/Console Monsters/Characters/LittleGirl.cs index aa265078..8c362274 100644 --- a/Projects/Console Monsters/Characters/LittleGirl.cs +++ b/Projects/Console Monsters/Characters/LittleGirl.cs @@ -15,7 +15,7 @@ public LittleGirl() public override string? Name => "Little Girl"; - public static readonly string IdleFront = + private static readonly string IdleFront = @"╭╭───╮╮" + '\n' + @" │^_^│ " + '\n' + @"╭┴───┴╮" + '\n' + diff --git a/Projects/Console Monsters/Characters/MartialArtist.cs b/Projects/Console Monsters/Characters/MartialArtist.cs index 983f2d44..c618001c 100644 --- a/Projects/Console Monsters/Characters/MartialArtist.cs +++ b/Projects/Console Monsters/Characters/MartialArtist.cs @@ -15,7 +15,7 @@ public MartialArtist() public override string? Name => "Martial Artist"; - public static readonly string IdleFront = + private static readonly string IdleFront = @" ╭───╮ " + '\n' + @" │^_^│ " + '\n' + @"╭╰─┬─╯╮" + '\n' + diff --git a/Projects/Console Monsters/Characters/Monk.cs b/Projects/Console Monsters/Characters/Monk.cs index 7c3e9636..127ff177 100644 --- a/Projects/Console Monsters/Characters/Monk.cs +++ b/Projects/Console Monsters/Characters/Monk.cs @@ -14,7 +14,7 @@ public Monk() } public override string? Name => "Scientist"; - public static readonly string IdleFront = + private static readonly string IdleFront = @" ╭───╮ " + '\n' + @" │^_^│ " + '\n' + @"╭╰─┬─╯╮" + '\n' + diff --git a/Projects/Console Monsters/Characters/Nurse.cs b/Projects/Console Monsters/Characters/Nurse.cs index 35cec56f..e82298af 100644 --- a/Projects/Console Monsters/Characters/Nurse.cs +++ b/Projects/Console Monsters/Characters/Nurse.cs @@ -14,7 +14,7 @@ public Nurse() } public override string? Name => "Nurse"; - public static readonly string Idle1 = + private static readonly string Idle1 = @"╭─────╮" + '\n' + @"│╭───╮│" + '\n' + @"╰│^_^│╯" + '\n' + diff --git a/Projects/Console Monsters/Characters/OldMan.cs b/Projects/Console Monsters/Characters/OldMan.cs index f525ab28..857f7b39 100644 --- a/Projects/Console Monsters/Characters/OldMan.cs +++ b/Projects/Console Monsters/Characters/OldMan.cs @@ -9,10 +9,12 @@ public OldMan() public override string? Name => "Old Man"; - public static readonly string IdleFront = + private static readonly string IdleFront = @" ╭───╮ " + '\n' + @" │‾_‾│ " + '\n' + @"╭╰─▼─╯╮" + '\n' + @"╰├───┤╯" + '\n' + @" │_|_│ "; + + public static readonly OldMan Instance = new(); } diff --git a/Projects/Console Monsters/Characters/Samurai.cs b/Projects/Console Monsters/Characters/Samurai.cs index 5a7524d8..3e2ea55f 100644 --- a/Projects/Console Monsters/Characters/Samurai.cs +++ b/Projects/Console Monsters/Characters/Samurai.cs @@ -15,7 +15,7 @@ public Samurai() public override string? Name => "Samurai"; - public static readonly string IdleFront = + private static readonly string IdleFront = @" /███\ " + '\n' + @"/│'_'│\" + '\n' + @"╭╰───╯╮" + '\n' + diff --git a/Projects/Console Monsters/Characters/Scientist.cs b/Projects/Console Monsters/Characters/Scientist.cs index 81a7cd14..b44ae9d4 100644 --- a/Projects/Console Monsters/Characters/Scientist.cs +++ b/Projects/Console Monsters/Characters/Scientist.cs @@ -14,19 +14,21 @@ public Scientist() } public override string? Name => "Scientist"; - public static readonly string IdleFront = + public static readonly Scientist Instance = new(); + + private static readonly string IdleFront = @" ╭───╮ " + '\n' + @" ├■_■┤ " + '\n' + @"╭╰───╯╮" + '\n' + @"╰├───┤╯" + '\n' + @" │_|_│ "; - public static readonly string IdleLeft = + private static readonly string IdleLeft = @" ╭══╮ " + '\n' + @" │■-│ " + '\n' + @" ╰──╯ " + '\n' + @" │||│ " + '\n' + @" │__│ "; - public static readonly string IdleRight = + private static readonly string IdleRight = @" ╭══╮ " + '\n' + @" │ ■│ " + '\n' + @" ╰──╯ " + '\n' + diff --git a/Projects/Console Monsters/Enums/Element.cs b/Projects/Console Monsters/Enums/CMType.cs similarity index 80% rename from Projects/Console Monsters/Enums/Element.cs rename to Projects/Console Monsters/Enums/CMType.cs index d9af07bc..3dbb58ea 100644 --- a/Projects/Console Monsters/Enums/Element.cs +++ b/Projects/Console Monsters/Enums/CMType.cs @@ -1,7 +1,8 @@ namespace Console_Monsters.Enums; -public enum Element +public enum CMType { + Normal, Fire, Water, Earth, diff --git a/Projects/Console Monsters/Items/Coin.cs b/Projects/Console Monsters/Items/Coin.cs new file mode 100644 index 00000000..ce964ffa --- /dev/null +++ b/Projects/Console Monsters/Items/Coin.cs @@ -0,0 +1,17 @@ +namespace Console_Monsters.Items; + +public class Coin : ItemBase +{ + public override string? Name => "Coin"; + + public override string? Description => "Used to buy Items"; + + public override string Sprite => + @" " + "\n" + + @" " + "\n" + + @" $ " + "\n" + + @" " + "\n" + + @" "; + + public static readonly Coin Instance = new Coin(); +} diff --git a/Projects/Console Monsters/Items/HealthPotionLarge.cs b/Projects/Console Monsters/Items/HealthPotionLarge.cs index 4e2f9ea7..2cb2bd4c 100644 --- a/Projects/Console Monsters/Items/HealthPotionLarge.cs +++ b/Projects/Console Monsters/Items/HealthPotionLarge.cs @@ -6,6 +6,8 @@ public class HealthPotionLarge : ItemBase public override string? Description => "Used to restore hp to monsters"; + public override ItemCategory Category => ItemCategory.Potions; + public override string Sprite => @" [╤═╤] " + "\n" + @" ╭╯ ╰╮ " + "\n" + diff --git a/Projects/Console Monsters/Items/HealthPotionMedium.cs b/Projects/Console Monsters/Items/HealthPotionMedium.cs index 0ff906c7..aba8eefb 100644 --- a/Projects/Console Monsters/Items/HealthPotionMedium.cs +++ b/Projects/Console Monsters/Items/HealthPotionMedium.cs @@ -6,6 +6,8 @@ public class HealthPotionMedium : ItemBase public override string? Description => "Used to restore hp to monsters"; + public override ItemCategory Category => ItemCategory.Potions; + public override string Sprite => @" [╤═╤] " + "\n" + @" ╭╯ ╰╮ " + "\n" + diff --git a/Projects/Console Monsters/Items/HealthPotionSmall.cs b/Projects/Console Monsters/Items/HealthPotionSmall.cs index cb8649ed..7b855515 100644 --- a/Projects/Console Monsters/Items/HealthPotionSmall.cs +++ b/Projects/Console Monsters/Items/HealthPotionSmall.cs @@ -6,6 +6,8 @@ public class HealthPotionSmall : ItemBase public override string? Description => "Used to restore hp to monsters"; + public override ItemCategory Category => ItemCategory.Potions; + public override string Sprite => @" [╤╤] " + "\n" + @" ╭╯╰╮ " + "\n" + diff --git a/Projects/Console Monsters/Items/MonsterBox.cs b/Projects/Console Monsters/Items/MonsterBox.cs index cfb734ba..d967c82d 100644 --- a/Projects/Console Monsters/Items/MonsterBox.cs +++ b/Projects/Console Monsters/Items/MonsterBox.cs @@ -6,6 +6,8 @@ public class MonsterBox : ItemBase public override string? Description => "Used to catch monsters"; + public override ItemCategory Category => ItemCategory.MonsterBoxes; + public override string Sprite => Sprites.MonsterBox; public static readonly MonsterBox Instance = new(); diff --git a/Projects/Console Monsters/Maps/Center1.cs b/Projects/Console Monsters/Maps/Palet Town/Center1.cs similarity index 94% rename from Projects/Console Monsters/Maps/Center1.cs rename to Projects/Console Monsters/Maps/Palet Town/Center1.cs index 8c5a4382..99a26d50 100644 --- a/Projects/Console Monsters/Maps/Center1.cs +++ b/Projects/Console Monsters/Maps/Palet Town/Center1.cs @@ -4,13 +4,13 @@ public class Center1 : MapBase { public override string? AudioFile => AudioController.CoDA_Lullaby; - public Nurse nurse; - public LittleGirl littleGirl; + private Nurse nurse; + private Scientist scientist; public Center1() { nurse = new(); - littleGirl = new(); + scientist = new(); } private static readonly char[][] spriteSheet = new char[][] @@ -57,7 +57,7 @@ public override string GetMapTileRender(int tileI, int tileJ) 'r' => Sprites.DeskRight, // NPC's 'k' => nurse.Sprite, - 'q' => littleGirl.Sprite, + 'q' => scientist.Sprite, // Items 's' => Sprites.MonsterBox, // Extra @@ -108,10 +108,8 @@ public override void InteractWithMapTile(int i, int j) spriteSheet[j][i] = ' '; break; case 'q': - PromptText = new string[] - { - "...", - }; + Shop = MonsterCenterShop.Instance; + ShopScreen.Render(); break; } } } @@ -144,7 +142,7 @@ public override void PerformTileAction(int i, int j) { case '0': Map = new PaletTown(); - Map.SpawnCharacterOn('0'); + Map.SpawnPlayerOn('0'); break; } } diff --git a/Projects/Console Monsters/Maps/House1.cs b/Projects/Console Monsters/Maps/Palet Town/House1.cs similarity index 96% rename from Projects/Console Monsters/Maps/House1.cs rename to Projects/Console Monsters/Maps/Palet Town/House1.cs index cd91bfb1..5e730f8a 100644 --- a/Projects/Console Monsters/Maps/House1.cs +++ b/Projects/Console Monsters/Maps/Palet Town/House1.cs @@ -2,6 +2,8 @@ public class House1 : MapBase { + public static bool IsLocked = true; + public override string? AudioFile => AudioController.CoDA_Lullaby; private static readonly char[][] spriteSheet = new char[][] @@ -128,15 +130,15 @@ public override void PerformTileAction(int i, int j) { case '0': Map = new PaletTown(); - Map.SpawnCharacterOn('2'); + Map.SpawnPlayerOn('2'); break; case 'i': Map = new House1SecondFloor(); - Map.SpawnCharacterOn('i'); + Map.SpawnPlayerOn('i'); break; case 'j': Map = new House1SecondFloor(); - Map.SpawnCharacterOn('j'); + Map.SpawnPlayerOn('j'); break; } diff --git a/Projects/Console Monsters/Maps/House1SecondFloor.cs b/Projects/Console Monsters/Maps/Palet Town/House1SecondFloor.cs similarity index 95% rename from Projects/Console Monsters/Maps/House1SecondFloor.cs rename to Projects/Console Monsters/Maps/Palet Town/House1SecondFloor.cs index 8b165b38..7b15eb4c 100644 --- a/Projects/Console Monsters/Maps/House1SecondFloor.cs +++ b/Projects/Console Monsters/Maps/Palet Town/House1SecondFloor.cs @@ -71,6 +71,8 @@ public override bool CanInteractWithMapTile(int i, int j) } return SpriteSheet[j][i] switch { + 'p' => true, + 'q' => true, 'r' => true, 'w' => true, '!' => true, @@ -84,6 +86,9 @@ public override void InteractWithMapTile(int i, int j) { switch (SpriteSheet[j][i]) { + case 'p' or 'q': + PCGamesScreen.Render(); + break; case 'r': PromptText = new string[] { @@ -140,11 +145,11 @@ public override void PerformTileAction(int i, int j) { case 'i': Map = new House1(); - Map.SpawnCharacterOn('1'); + Map.SpawnPlayerOn('1'); break; case 'j': Map = new House1(); - Map.SpawnCharacterOn('2'); + Map.SpawnPlayerOn('2'); break; } } diff --git a/Projects/Console Monsters/Maps/PaletTown.cs b/Projects/Console Monsters/Maps/Palet Town/PaletTown.cs similarity index 89% rename from Projects/Console Monsters/Maps/PaletTown.cs rename to Projects/Console Monsters/Maps/Palet Town/PaletTown.cs index 95a752e7..736ae642 100644 --- a/Projects/Console Monsters/Maps/PaletTown.cs +++ b/Projects/Console Monsters/Maps/Palet Town/PaletTown.cs @@ -2,8 +2,8 @@ class PaletTown : MapBase { - public Scientist scientist; - public ChineseMan chineseMan; + private Scientist scientist; + private ChineseMan chineseMan; public PaletTown() { @@ -13,10 +13,12 @@ public PaletTown() public override string? AudioFile => AudioController.CoDA_Lullaby; - private readonly static char[][] spriteSheet = new char[][] + private static readonly char[][] spriteSheet = new char[][] { + "tttttgggggggTgggggfGGfgggggTgggggttttt".ToCharArray(), + "tttttgggggggTgggggfGGfgggggTgggggttttt".ToCharArray(), "tttttgggggggfgggggf11fgggggfgggggttttt".ToCharArray(), - "tttttggggffffffffff ffffffffggggttttt".ToCharArray(), + "tttttggggffffffffffX ffffffffggggttttt".ToCharArray(), "tttttggggfg gfggggttttt".ToCharArray(), "tttttggggfg bbbb cccc gfggggttttt".ToCharArray(), "tttttggggfg bbbb cccc gfggggttttt".ToCharArray(), @@ -28,7 +30,7 @@ public PaletTown() "tttttggggfg gggg dddddd gfggggttttt".ToCharArray(), "tttttggggfg gggg d0dddd gfggggttttt".ToCharArray(), "tttttggggfg n gfggggttttt".ToCharArray(), - "tttttggggfg X gfggggttttt".ToCharArray(), + "tttttggggfg gfggggttttt".ToCharArray(), "tttttggggfg o FFFsFF gfggggttttt".ToCharArray(), "tttttggggfgggWWWW gggggg gfggggttttt".ToCharArray(), "tttttggggfgggWwwW gggegg gfggggttttt".ToCharArray(), @@ -167,15 +169,18 @@ public override void PerformTileAction(int i, int j) { case '0': Map = new Center1(); - Map.SpawnCharacterOn('0'); + Map.SpawnPlayerOn('0'); break; case '1': Map = new Route1(); - Map.SpawnCharacterOn('0'); + Map.SpawnPlayerOn('0'); break; case '2': - Map = new House1(); - Map.SpawnCharacterOn('0'); + if (!House1.IsLocked) + { + Map = new House1(); + Map.SpawnPlayerOn('0'); + } break; } } diff --git a/Projects/Console Monsters/Maps/Route1.cs b/Projects/Console Monsters/Maps/Route1.cs index 7e14d69b..c7bb617e 100644 --- a/Projects/Console Monsters/Maps/Route1.cs +++ b/Projects/Console Monsters/Maps/Route1.cs @@ -4,10 +4,12 @@ class Route1 : MapBase { private static readonly char[][] spriteSheet = new char[][] { - "ggggggggggggfgggggf11fgggggfgggggggggg".ToCharArray(), - "ggggggggggggfgggggf fgggggfgggggggggg".ToCharArray(), - "ggggggggggggfgggggf fgggggfgggggggggg".ToCharArray(), - "ggggggggggggfgggggf fgggggfgggggggggg".ToCharArray(), + "gggGGGGGGGgggTTTTTs GGGGGGGG eT".ToCharArray(), + "gggGGGGGGGgggTTTTT ~~ TTTTTTTTTTTTTTTT".ToCharArray(), + "fffffffffffffTTTTTf11fTTTTTTTTTTgggggg".ToCharArray(), + "ggggggggggggfTTTTTf fTTTTTTTTTTgggggg".ToCharArray(), + "ggggggggggggfTTTTTf fTTTTTTTTTTgggggg".ToCharArray(), + "ggggggggggggfgggggf fgggggfTTTTgggggg".ToCharArray(), "ggggggggggggfgggggf fgggggfgggggggggg".ToCharArray(), "ggggggggggggfffffff fffffffgggggggggg".ToCharArray(), "ggggggggggggfgggggg ggggggfgggggggggg".ToCharArray(), @@ -72,6 +74,7 @@ public override string GetMapTileRender(int i, int j) 'ş' => Sprites.HalfRockStairsGrass, // Extra ' ' => Sprites.Open, + '~' => Sprites.Open, _ => Sprites.Error, }; } @@ -135,23 +138,41 @@ public override void PerformTileAction(int i, int j) { case '0': Map = new PaletTown(); - Map.SpawnCharacterOn('1'); + Map.SpawnPlayerOn('1'); break; case '1': Map = new Route2(); - Map.SpawnCharacterOn('0'); + Map.SpawnPlayerOn('0'); break; case 'G': - if (!DisableBattle && Random.Shared.Next(2) is 0) // BATTLE CHANCE + //SpawnType = "Grass"; + if (!DisableBattle && IsAnyAvailableMonster() && GetFirstAvailableMonster() != new _ErrorMonster() && Random.Shared.Next(2) is 0) // BATTLE CHANCE { Console.Clear(); if (!DisableBattleTransition) { BattleTransition.Random(); } - BattleScreen.Render(partyMonsters[0], MonsterBase.GetRandom()); - //Battle(); - ConsoleHelper.PressToContinue(); + Type[] typesThatCanSpawn = + { + typeof(Fox), + //typeof(Ant), + //typeof(Goat), + //typeof(Owl), + //typeof(Pig), + //typeof(Pinecone), + //typeof(Ladybug), + }; + Type typeOfMonsterToSpawn = Random.Shared.Choose(typesThatCanSpawn); + + BattleMonsters monsters = new(); + monsters.Opponent = (MonsterBase)Activator.CreateInstance(typeOfMonsterToSpawn)!; + monsters.Player = GetFirstAvailableMonster(); + + MonsterBase.WildMonster(monsters.Opponent); + + Battle(monsters); + } break; } diff --git a/Projects/Console Monsters/Maps/Route2.cs b/Projects/Console Monsters/Maps/Route2.cs index ded7a032..288f00eb 100644 --- a/Projects/Console Monsters/Maps/Route2.cs +++ b/Projects/Console Monsters/Maps/Route2.cs @@ -2,7 +2,7 @@ class Route2 : MapBase { - public Camper camper; + private Camper camper; public Route2() { @@ -11,23 +11,23 @@ public Route2() private static readonly char[][] spriteSheet = new char[][] { - "TTTTTTTTTTTTT ".ToCharArray(), - "TTTTTTTTTTTTT ".ToCharArray(), - "TTTTaaaaaaaaa ".ToCharArray(), - "TTTTaaaaaaaaa ".ToCharArray(), - "TTTTaaaaaaaaa ".ToCharArray(), - "TTTTaaaaaaaaaffffffffffffffffffffffffffffffffffffffffffff".ToCharArray(), - "TTTTaaaaaaaaagggggggggggggggg ggggggggg GGGGGGGf".ToCharArray(), - "TTTTaaaaaabaagggggggggggggggg ggggggggg GGGGGGGf".ToCharArray(), - " !ggggggggggggggggggggggg gggggggggTTTTTTTGGGGGGGf".ToCharArray(), - " fggggggggggggggggggggggg gggggggggggggggT f".ToCharArray(), - " fggggggggggggggggggggggg gggggggggggggggT f".ToCharArray(), - " fggggggggggggggTTTTTTTTTTTTTTggggggggggggggT f".ToCharArray(), - " fgggggggggggggg TTTTTTTTgggggggT 1".ToCharArray(), - " fgggggggggggggg GGGGGGGGgggggggT 1".ToCharArray(), - " fggggggggggggggTTTTTTTTTs GGGGGGGGgggggggTTTTTTTTf".ToCharArray(), - " fggggggggggggggggggggggT TTTTTTTTgggggggggggggggf".ToCharArray(), - " fffffffffffffffffffffffff00fffffffffffffffffffffffff".ToCharArray(), + "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT".ToCharArray(), + "TaaaaaaaaaTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT".ToCharArray(), + "TaaaaaaaaaTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT".ToCharArray(), + "TaaaaaaaaaTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT".ToCharArray(), + "TaaaaaaaaaTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT".ToCharArray(), + "TaaaaaaaaafffffffffffffffffffffffffffffffffffffffffffffffTTTTT".ToCharArray(), + "TaaaaaabaagggggggfggGGGGTTTTf ggggggggg GGGGGGGfTTTTT".ToCharArray(), + "TTTTTfgggggggggggfgggGGGTTTTf ggggggggg GGGGGGGfTTTTT".ToCharArray(), + " 2gggggGGGGGGggggtGGTTTTf TTTTTTTTTTTTTTTTGGGGGGGfTTTTT".ToCharArray(), + " 2gggggGGGGGGfggggGGTTTTf GGGGGGGGgggggggT fTTTTT".ToCharArray(), + "TTTTTffffffffGGGGfggggggTTTTf GGGGGGGGgggggggT fTTTTT".ToCharArray(), + "TTTTTfGGGGG TŕŕŕŕŕŕTTTTTTTTTTGGGGGGGgggggggT ffffff".ToCharArray(), + "TTTTTfGGGGG TGGG TTTTTTTT T 1 ".ToCharArray(), + "TTTTTf TTTTTTTTGGG GGGGGGGG T 1 ".ToCharArray(), + "TTTTTf ggggGGGGGGGgggTTTTTs GGGGGGGG eTTTTTTTTffffff".ToCharArray(), + "TTTTTf ggggGGGGGGGgggTTTTT TTTTTTTTTTTTTTTTgggggggfTTTTT".ToCharArray(), + "TTTTTfffffffffffffffffffTTTTTf00fTTTTTTTTTTTTTTTTffffffffTTTTT".ToCharArray(), }; public override char[][] SpriteSheet => spriteSheet; @@ -40,17 +40,32 @@ public override string GetMapTileRender(int i, int j) } return SpriteSheet[j][i] switch { + // spawn + 'X' => Sprites.Open, + + // Items + 'e' => Sprites.MonsterBoxPickableOnGround, + 'h' => Sprites.MonsterBox, + // actions '0' => Sprites.ArrowHeavyDown, '1' => Sprites.ArrowHeavyRight, - // no actions - 's' => Sprites.SignARight, + '2' => Sprites.ArrowHeavyLeft, + 'b' => camper.Sprite, + + // No actions + 's' => Sprites.SignALeft, 'f' => Sprites.Fence, + 'a' => Sprites.Camping6x9.Get(Subtract((i, j), FindTileInMap('a')!.Value).Reverse()), + + // Nature 'g' => Sprites.GrassDec, 'G' => Sprites.Grass, + 't' => Sprites.Tree, 'T' => Sprites.Tree2, - 'a' => Sprites.Camping6x9.Get(Subtract((i, j), FindTileInMap('a')!.Value).Reverse()), - 'b' => camper.Sprite, + 'ŕ' => Sprites.HalfRockGrass, + + // Other ' ' => Sprites.Open, _ => Sprites.Error, }; @@ -102,7 +117,9 @@ public override bool IsValidCharacterMapTile(int i, int j) ' ' => true, '0' => true, '1' => true, + '2' => true, 'g' => true, + 'X' => true, 'G' => true, _ => false, }; @@ -118,11 +135,14 @@ public override void PerformTileAction(int i, int j) { case '0': Map = new Route1(); - Map.SpawnCharacterOn('1'); + Map.SpawnPlayerOn('1'); break; case '1': Map = new Western(); - Map.SpawnCharacterOn('0'); + Map.SpawnPlayerOn('0'); + break; + case '2': + break; case 'G': if (!DisableBattle && Random.Shared.Next(2) is 0) // BATTLE CHANCE diff --git a/Projects/Console Monsters/Maps/Western.cs b/Projects/Console Monsters/Maps/Western.cs index 5b9feab2..b175f39a 100644 --- a/Projects/Console Monsters/Maps/Western.cs +++ b/Projects/Console Monsters/Maps/Western.cs @@ -86,7 +86,7 @@ public override void PerformTileAction(int i, int j) { case '0': Map = new Route2(); - Map.SpawnCharacterOn('1'); + Map.SpawnPlayerOn('1'); break; case 'a': if (!DisableBattle && Random.Shared.Next(4) is 0) // BATTLE CHANCE diff --git a/Projects/Console Monsters/Monsters/BigMouthTurtle.cs b/Projects/Console Monsters/Monsters/BigMouthTurtle.cs new file mode 100644 index 00000000..8787484c --- /dev/null +++ b/Projects/Console Monsters/Monsters/BigMouthTurtle.cs @@ -0,0 +1,14 @@ +namespace Console_Monsters.Monsters; + +internal class BigMouthTurtle : MonsterBase +{ + public BigMouthTurtle() + { + Name = "Big Mouth Turtle"; + } + + public override string[] Sprite => ( + @" ╭─────╮" + "\n" + + @"╭───╮_│⁰ ˄˄˄┤" + "\n" + + @"╰U─U╯‾╰─────╯").Split('\n'); +} diff --git a/Projects/Console Monsters/Monsters/Chopper.cs b/Projects/Console Monsters/Monsters/Chopper.cs index 59357a16..fc03d6c5 100644 --- a/Projects/Console Monsters/Monsters/Chopper.cs +++ b/Projects/Console Monsters/Monsters/Chopper.cs @@ -5,6 +5,7 @@ public class Chopper : MonsterBase public Chopper() { Name = "Chopper"; + //MonsterType = "Grass"; //Temp } public override string[] Sprite => ( diff --git a/Projects/Console Monsters/Monsters/Egg.cs b/Projects/Console Monsters/Monsters/Egg.cs new file mode 100644 index 00000000..8a04d8ea --- /dev/null +++ b/Projects/Console Monsters/Monsters/Egg.cs @@ -0,0 +1,15 @@ +namespace Console_Monsters.Monsters; + +public class Egg : MonsterBase +{ + public Egg() + { + Name = "Egg"; + } + + public override string[] Sprite => ( + @" ╭───╮ " + "\n" + + @" │^_^│ " + "\n" + + @"ᴄ├˄^˄┤ᴐ" + "\n" + + @" ╰U─U╯ ").Split('\n'); +} diff --git a/Projects/Console Monsters/Monsters/Eggs.cs b/Projects/Console Monsters/Monsters/Eggs.cs new file mode 100644 index 00000000..5b2a9072 --- /dev/null +++ b/Projects/Console Monsters/Monsters/Eggs.cs @@ -0,0 +1,16 @@ +namespace Console_Monsters.Monsters; + +public class Eggs : MonsterBase +{ + public Eggs() + { + Name = "Eggs"; + } + + public override string[] Sprite => ( + @" ╭┬──╮ ╭┌┬─╮" + "\n" + + @" ┌˄^˄┐ │ˋ˾ˊ┤ │▾˾▾│" + "\n" + + @"╭─┴┬╮─╯╭─┴─╮┴╯╭─┴┐╮─╯" + "\n" + + @"├▴˾▴│ │^_^│ │▸˾◂│ " + "\n" + + @"╰┴──╯ ╰───╯ ╰──┴╯ ").Split('\n'); +} diff --git a/Projects/Console Monsters/Monsters/FireChick.cs b/Projects/Console Monsters/Monsters/FireChick.cs new file mode 100644 index 00000000..814142bc --- /dev/null +++ b/Projects/Console Monsters/Monsters/FireChick.cs @@ -0,0 +1,17 @@ +namespace Console_Monsters.Monsters; + +public class FireChick : MonsterBase +{ + public FireChick() + { + Name = "Fire Chick"; + } + + public override string[] Sprite => ( + @" \│/ " + "\n" + + @"╭─╨──╮" + "\n" + + @"│^__^│" + "\n" + + @"╰W W╯" + "\n" + + @" ╰┬┬╯ " + "\n" + + @" ╛╘ ").Split('\n'); +} \ No newline at end of file diff --git a/Projects/Console Monsters/Monsters/FireLizard.cs b/Projects/Console Monsters/Monsters/FireLizard.cs index feff6ff6..39bb89d7 100644 --- a/Projects/Console Monsters/Monsters/FireLizard.cs +++ b/Projects/Console Monsters/Monsters/FireLizard.cs @@ -1,19 +1,34 @@ -namespace Console_Monsters.Monsters; +using Console_Monsters.Moves; + +namespace Console_Monsters.Monsters; public class FireLizard : MonsterBase { public FireLizard() { - Name = "Fire Lizard Small"; - Level = 5; - MaximumHP = 20; - MaximumEnergy = 50; + Name = "Fire Lizard"; + + MaximumHP = SetMaxHPFromBase(HPStat, Level, Statexp); CurrentHP = MaximumHP; + MaximumEnergy = 50; CurrentEnergy = MaximumEnergy; - Evolution = 1; + + HPStat = 44; AttackStat = 10; SpeedStat = 10; DefenseStat = 10; + + Statexp = AttackStat + SpecialAttackStat + DefenseStat + SpecialDefenseStat + SpeedStat; + + MoveSet = new List + { + new Punch(), + new Tackle(), + new Scratch(), + new Growl() + }; + + Evolution = 1; } public override string[] Sprite => ( diff --git a/Projects/Console Monsters/Monsters/FireLizard2.cs b/Projects/Console Monsters/Monsters/FireLizard2.cs index 01d10f7b..eaf392cc 100644 --- a/Projects/Console Monsters/Monsters/FireLizard2.cs +++ b/Projects/Console Monsters/Monsters/FireLizard2.cs @@ -4,7 +4,7 @@ public class FireLizard2 : MonsterBase { public FireLizard2() { - Name = "Fire Lizard Medium"; + Name = "Fire Reptile"; } public override string[] Sprite => ( diff --git a/Projects/Console Monsters/Monsters/FireLizard3.cs b/Projects/Console Monsters/Monsters/FireLizard3.cs index f96f258f..f66bd209 100644 --- a/Projects/Console Monsters/Monsters/FireLizard3.cs +++ b/Projects/Console Monsters/Monsters/FireLizard3.cs @@ -4,7 +4,7 @@ public class FireLizard3 : MonsterBase { public FireLizard3() { - Name = "Fire Lizard Large"; + Name = "Fire Dragon"; } public override string[] Sprite => ( diff --git a/Projects/Console Monsters/Monsters/Fox.cs b/Projects/Console Monsters/Monsters/Fox.cs index 6f1d6371..c47b3277 100644 --- a/Projects/Console Monsters/Monsters/Fox.cs +++ b/Projects/Console Monsters/Monsters/Fox.cs @@ -1,10 +1,37 @@ -namespace Console_Monsters.Monsters; +using Console_Monsters.Moves; -internal class Fox : MonsterBase +namespace Console_Monsters.Monsters; + +public class Fox : MonsterBase { public Fox() { Name = "Fox"; + Level = 5; + + MaximumHP = SetMaxHPFromBase(HPStat, Level, Statexp); + CurrentHP = MaximumHP; + MaximumEnergy = 50; + CurrentEnergy = MaximumEnergy; + + HPStat = 55; + AttackStat = 55; + SpecialAttackStat = 45; + DefenseStat = 50; + SpecialDefenseStat = 65; + SpeedStat = 55; + + Statexp = (int)HPStat + AttackStat + SpecialAttackStat + DefenseStat + SpecialDefenseStat + SpeedStat; + + MoveSet = new List + { + new Punch(), + new Tackle(), + new Scratch(), + new Growl() + }; + + Evolution = 1; } public override string[] Sprite => ( diff --git a/Projects/Console Monsters/Monsters/MultiHeadedBird1.cs b/Projects/Console Monsters/Monsters/MultiHeadedBird1.cs new file mode 100644 index 00000000..2fa34bf9 --- /dev/null +++ b/Projects/Console Monsters/Monsters/MultiHeadedBird1.cs @@ -0,0 +1,19 @@ +namespace Console_Monsters.Monsters; + +public class MultiHeadedBird1 : MonsterBase +{ + public MultiHeadedBird1() + { + Name = "Two Headed Bird"; + } + + public override string[] Sprite => ( + @" ╭───╮ ╭───╮" + "\n" + + @" │⁰v⁰│ │⁰v⁰│" + "\n" + + @" ╰──┬╯ ╰┬──╯" + "\n" + + @" ╰╭───╮╯ " + "\n" + + @" │ │ " + "\n" + + @" ╰┬─┬╯ " + "\n" + + @" │ │ " + "\n" + + @" ┘ └ ").Split('\n'); +} diff --git a/Projects/Console Monsters/Monsters/MultiHeadedBird2.cs b/Projects/Console Monsters/Monsters/MultiHeadedBird2.cs new file mode 100644 index 00000000..a26610d1 --- /dev/null +++ b/Projects/Console Monsters/Monsters/MultiHeadedBird2.cs @@ -0,0 +1,20 @@ +namespace Console_Monsters.Monsters; + +public class MultiHeadedBird2 : MonsterBase +{ + public MultiHeadedBird2() + { + Name = "Three Headed Bird"; + } + + public override string[] Sprite => ( + @" ╭─v─╮ " + "\n" + + @"╭─v─╮│⁰v⁰│╭─v─╮" + "\n" + + @"│⁰v⁰│╰─┬┬╯│⁰v⁰│" + "\n" + + @"╰─┬┬╯ ││ ╰┬┬─╯" + "\n" + + @" ╰╰─╭─┴┴─╮╯╯ " + "\n" + + @" │ │ " + "\n" + + @" ╰╥──╥╯╮╮ " + "\n" + + @" ║ ║ ╰╰╰ " + "\n" + + @" ╝ ╚ ").Split('\n'); +} diff --git a/Projects/Console Monsters/Monsters/Pinecone.cs b/Projects/Console Monsters/Monsters/Pinecone.cs new file mode 100644 index 00000000..4555ba1e --- /dev/null +++ b/Projects/Console Monsters/Monsters/Pinecone.cs @@ -0,0 +1,16 @@ +namespace Console_Monsters.Monsters; + +public class Pinecone : MonsterBase +{ + public Pinecone() + { + Name = "Pinecone"; + } + + public override string[] Sprite => ( + @" ┌┌┐┌┐┐ " + "\n" + + @"[ ^╶╴^ ]" + "\n" + + @"└└┘└┘└┘┘" + "\n" + + @" └└┘└┘┘ " + "\n" + + @" └└┘┘ ").Split('\n'); +} diff --git a/Projects/Console Monsters/Monsters/PsychicElephant.cs b/Projects/Console Monsters/Monsters/PsychicElephant.cs new file mode 100644 index 00000000..99fdf629 --- /dev/null +++ b/Projects/Console Monsters/Monsters/PsychicElephant.cs @@ -0,0 +1,17 @@ +namespace Console_Monsters.Monsters; + +internal class PsychicElephant : MonsterBase +{ + public PsychicElephant() + { + Name = "Psychic Elephant"; + } + + public override string[] Sprite => ( + @" ╭────╮ " + "\n" + + @" <│^ ╮^│> " + "\n" + + @"╭╮╭╰─││─╯╮╭╮" + "\n" + + @"╰─├ᴖᴗᴖᴗᴖᴗ┤─╯" + "\n" + + @" ╰┐ ┌┐ ┌╯ " + "\n" + + @" ╰─╯╰─╯ ").Split('\n'); +} diff --git a/Projects/Console Monsters/Monsters/Scorpion.cs b/Projects/Console Monsters/Monsters/Scorpion.cs new file mode 100644 index 00000000..19e3ede2 --- /dev/null +++ b/Projects/Console Monsters/Monsters/Scorpion.cs @@ -0,0 +1,17 @@ +namespace Console_Monsters.Monsters; + +public class Scorpion : MonsterBase +{ + public Scorpion() + { + Name = "Scorpion"; + } + + public override string[] Sprite => ( + @" (╰┬╯) " + "\n" + + @" )-( " + "\n" + + @" (-) " + "\n" + + @"V ╭─┴─┴─╮ V" + "\n" + + @"╚═│ ^_^ │═╝" + "\n" + + @" ┌╰┬───┬╯┐ ").Split('\n'); +} diff --git a/Projects/Console Monsters/Monsters/SeaHorse.cs b/Projects/Console Monsters/Monsters/SeaHorse.cs new file mode 100644 index 00000000..5c7f112f --- /dev/null +++ b/Projects/Console Monsters/Monsters/SeaHorse.cs @@ -0,0 +1,17 @@ +namespace Console_Monsters.Monsters; + +internal class Seahorse : MonsterBase +{ + public Seahorse() + { + Name = "Seahorse"; + } + + public override string[] Sprite => ( + @" ╭───╮ " + '\n' + + @"o╡^ ≤│ " + '\n' + + @" ╰┬─ │<_)" + '\n' + + @"╭─╮≡ │ " + '\n' + + @"│┬╯┘ │ " + '\n' + + @"╰────╯ ").Split('\n'); +} diff --git a/Projects/Console Monsters/Monsters/SpikyMouse.cs b/Projects/Console Monsters/Monsters/SpikyMouse.cs new file mode 100644 index 00000000..a7788919 --- /dev/null +++ b/Projects/Console Monsters/Monsters/SpikyMouse.cs @@ -0,0 +1,17 @@ +namespace Console_Monsters.Monsters; + +public class SpikyMouse : MonsterBase +{ + public SpikyMouse() + { + Name = "Spiky Mouse"; + } + + public override string[] Sprite => ( + @" ᴧ^ᴧ^ᴧ " + "\n" + + @" <˂╰⁰ ⁰╯╮" + "\n" + + @" <˂ ╰─╯ ╮" + "\n" + + @" ˂< ╰─≥ ≤╯" + "\n" + + @"ᴧ <˂╮ _ ╭╯ " + "\n" + + @"╰───╯ ╰╯ ╰╯ ").Split('\n'); +} diff --git a/Projects/Console Monsters/Monsters/ToadBud.cs b/Projects/Console Monsters/Monsters/ToadBud.cs index f6704f6c..11baf410 100644 --- a/Projects/Console Monsters/Monsters/ToadBud.cs +++ b/Projects/Console Monsters/Monsters/ToadBud.cs @@ -1,10 +1,34 @@ -namespace Console_Monsters.Monsters; +using Console_Monsters.Moves; + +namespace Console_Monsters.Monsters; public class ToadBud : MonsterBase { public ToadBud() { Name = "Toad Bud"; + + MaximumHP = SetMaxHPFromBase(HPStat, Level, Statexp); + CurrentHP = MaximumHP; + MaximumEnergy = 50; + CurrentEnergy = MaximumEnergy; + + HPStat = 45; + AttackStat = 10; + SpeedStat = 10; + DefenseStat = 10; + + Statexp = AttackStat + SpecialAttackStat + DefenseStat + SpecialDefenseStat + SpeedStat; + + MoveSet = new List + { + new Punch(), + new Tackle(), + new Scratch(), + new Growl() + }; + + Evolution = 1; } public override string[] Sprite => ( diff --git a/Projects/Console Monsters/Monsters/Turtle.cs b/Projects/Console Monsters/Monsters/Turtle.cs index 035eb1ab..a4d3247e 100644 --- a/Projects/Console Monsters/Monsters/Turtle.cs +++ b/Projects/Console Monsters/Monsters/Turtle.cs @@ -1,19 +1,40 @@ -namespace Console_Monsters.Monsters; +using Console_Monsters.Moves; + +namespace Console_Monsters.Monsters; public class Turtle : MonsterBase { public Turtle() { Name = "Turtle"; - Level = 5; - MaximumHP = 20; - MaximumEnergy = 50; + Level = 5; //TEMP +#warning Fix level not being set here + + HPStat = 44; + MaximumHP = SetMaxHPFromBase(HPStat, Level, Statexp); CurrentHP = MaximumHP; + + BaseEnergy = 50; + MaximumEnergy = 50; CurrentEnergy = MaximumEnergy; + + AttackStat = 48; + SpecialAttackStat = 50; + DefenseStat = 65; + SpecialDefenseStat = 64; + SpeedStat = 43; + + Statexp = 0; + + MoveSet = new List + { + new Punch(), + new Tackle(), + new Scratch(), + new Growl() + }; + Evolution = 1; - AttackStat = 10; - SpeedStat = 10; - DefenseStat = 10; } public override string[] Sprite => ( diff --git a/Projects/Console Monsters/Monsters/_EmptyMonster.cs b/Projects/Console Monsters/Monsters/_EmptyMonster.cs new file mode 100644 index 00000000..57525968 --- /dev/null +++ b/Projects/Console Monsters/Monsters/_EmptyMonster.cs @@ -0,0 +1,19 @@ +namespace Console_Monsters.Monsters; + +public class _EmptyMonster : MonsterBase +{ + public _EmptyMonster() + { + Name = "Empty Monster"; + AttackStat = 0; + DefenseStat = 0; + SpeedStat = 0; + } + + public override string[] Sprite => ( + " " + "\n" + + " " + "\n" + + " " + "\n" + + " " + "\n" + + " ").Split('\n'); +} diff --git a/Projects/Console Monsters/Monsters/_ErrorMonster.cs b/Projects/Console Monsters/Monsters/_ErrorMonster.cs new file mode 100644 index 00000000..7bb7cfdd --- /dev/null +++ b/Projects/Console Monsters/Monsters/_ErrorMonster.cs @@ -0,0 +1,19 @@ +namespace Console_Monsters.Monsters; + +public class _ErrorMonster : MonsterBase +{ + public _ErrorMonster() + { + Name = "No Monster"; + AttackStat = 0; + DefenseStat = 0; + SpeedStat = 0; + } + + public override string[] Sprite => ( + "╔═════╗" + "\n" + + "║ERROR║" + "\n" + + "║ERROR║" + "\n" + + "║ERROR║" + "\n" + + "╚═════╝").Split('\n'); +} diff --git a/Projects/Console Monsters/Moves/Growl.cs b/Projects/Console Monsters/Moves/Growl.cs new file mode 100644 index 00000000..5366dda5 --- /dev/null +++ b/Projects/Console Monsters/Moves/Growl.cs @@ -0,0 +1,14 @@ +namespace Console_Monsters.Moves; + +public class Growl : MoveBase +{ + public Growl() + { + Name = "Growl"; + BaseDamage = 0; + EnergyTaken = 10; + DamageType = Enums.DamageType.Special; + Element = Enums.CMType.Normal; + Priority = 0; + } +} diff --git a/Projects/Console Monsters/Moves/Punch.cs b/Projects/Console Monsters/Moves/Punch.cs index 193a84ec..5a8f5f4b 100644 --- a/Projects/Console Monsters/Moves/Punch.cs +++ b/Projects/Console Monsters/Moves/Punch.cs @@ -5,8 +5,10 @@ public class Punch : MoveBase public Punch() { Name = "Punch"; - BaseDamge = 40; - FinalDamage = (((2 * AttackingMonster!.Level / 5 + 2) * BaseDamge * AttackingMonster.AttackStat / DefendingMonster!.DefenseStat) / 50 + 2) * BattleRandom.Next(85, 101) / 100; - EnergyTaken = 10; // Temp + BaseDamage = 40; + EnergyTaken = 10; + DamageType = Enums.DamageType.Physical; + Element = Enums.CMType.Normal; + Priority = 0; } } diff --git a/Projects/Console Monsters/Moves/Quick Attack.cs b/Projects/Console Monsters/Moves/Quick Attack.cs new file mode 100644 index 00000000..eee3b843 --- /dev/null +++ b/Projects/Console Monsters/Moves/Quick Attack.cs @@ -0,0 +1,14 @@ +namespace Console_Monsters.Moves; + +public class QuickAttack : MoveBase +{ + public QuickAttack() + { + Name = "Quick Attack"; + BaseDamage = 40; + EnergyTaken = 10; + DamageType = Enums.DamageType.Physical; + Element = Enums.CMType.Normal; + Priority = 1; + } +} diff --git a/Projects/Console Monsters/Moves/Scratch.cs b/Projects/Console Monsters/Moves/Scratch.cs index 63b48626..3d86d93e 100644 --- a/Projects/Console Monsters/Moves/Scratch.cs +++ b/Projects/Console Monsters/Moves/Scratch.cs @@ -5,8 +5,10 @@ public class Scratch : MoveBase public Scratch() { Name = "Scratch"; - BaseDamge = 40; - FinalDamage = (((2 * AttackingMonster!.Level / 5 + 2) * BaseDamge * AttackingMonster.AttackStat / DefendingMonster!.DefenseStat) / 50 + 2) * BattleRandom.Next(85, 101) / 100; - EnergyTaken = 10; // Temp + BaseDamage = 40; + EnergyTaken = 10; + DamageType = Enums.DamageType.Physical; + Element = Enums.CMType.Normal; + Priority = 0; } } diff --git a/Projects/Console Monsters/Moves/Tackle.cs b/Projects/Console Monsters/Moves/Tackle.cs index 21437185..c9dbd7ad 100644 --- a/Projects/Console Monsters/Moves/Tackle.cs +++ b/Projects/Console Monsters/Moves/Tackle.cs @@ -5,8 +5,10 @@ public class Tackle : MoveBase public Tackle() { Name = "Tackle"; - BaseDamge = 40; - FinalDamage = (((2 * AttackingMonster!.Level / 5 + 2) * BaseDamge * AttackingMonster.AttackStat / DefendingMonster!.DefenseStat) / 50 + 2) * BattleRandom.Next(85, 101) / 100; - EnergyTaken = 10; // Temp + BaseDamage = 40; + EnergyTaken = 10; + DamageType = Enums.DamageType.Physical; + Element = Enums.CMType.Normal; + Priority = 0; } } diff --git a/Projects/Console Monsters/Moves/_EmptyMove.cs b/Projects/Console Monsters/Moves/_EmptyMove.cs new file mode 100644 index 00000000..6d6fd2ec --- /dev/null +++ b/Projects/Console Monsters/Moves/_EmptyMove.cs @@ -0,0 +1,10 @@ +namespace Console_Monsters.Moves; + +public class _EmptyMove : MoveBase +{ + public _EmptyMove() + { + Name = "Empty Move"; + Priority = -1; + } +} diff --git a/Projects/Console Monsters/PCGames/2048.cs b/Projects/Console Monsters/PCGames/2048.cs new file mode 100644 index 00000000..0bd67e78 --- /dev/null +++ b/Projects/Console Monsters/PCGames/2048.cs @@ -0,0 +1,215 @@ +using static System.Formats.Asn1.AsnWriter; +using System; + +namespace Console_Monsters.PCGames; + +public class _2048 +{ + public static void Run() + { + try + { + Random random = new(); + while (true) + { + NewBoard: + Console.Clear(); + int?[,] board = new int?[4, 4]; + int score = 0; + while (true) + { + // add a 2 or 4 randomly to the board + bool IsNull((int X, int Y) point) => board[point.X, point.Y] is null; + int nullCount = BoardValues(board).Count(IsNull); + if (nullCount == 0) + { + goto GameOver; + } + int index = random.Next(0, nullCount); + var (x, y) = BoardValues(board).Where(IsNull).ElementAt(index); + board[x, y] = random.Next(10) < 9 ? 2 : 4; + score += 2; + + // make sure there are still valid moves left + if (!TryUpdate((int?[,])board.Clone(), ref score, Direction.Up) && + !TryUpdate((int?[,])board.Clone(), ref score, Direction.Down) && + !TryUpdate((int?[,])board.Clone(), ref score, Direction.Left) && + !TryUpdate((int?[,])board.Clone(), ref score, Direction.Right)) + { + goto GameOver; + } + + Render(board, score); + Direction direction; + GetDirection: + switch (Console.ReadKey(true).Key) + { + case ConsoleKey.UpArrow: direction = Direction.Up; break; + case ConsoleKey.DownArrow: direction = Direction.Down; break; + case ConsoleKey.LeftArrow: direction = Direction.Left; break; + case ConsoleKey.RightArrow: direction = Direction.Right; break; + case ConsoleKey.End: goto NewBoard; + case ConsoleKey.Escape: goto Close; + default: goto GetDirection; + } + if (!TryUpdate(board, ref score, direction)) + { + goto GetDirection; + } + } + GameOver: + Render(board, score); + Console.WriteLine($"Game Over..."); + Console.WriteLine(); + Console.WriteLine("Play Again [enter], or quit [escape]?"); + GetInput: + switch (Console.ReadKey(true).Key) + { + case ConsoleKey.Enter: goto NewBoard; + case ConsoleKey.Escape: goto Close; + default: goto GetInput; + } + } + Close: + Console.Clear(); + } + finally + { + PCGamesScreen.Render(); + } + } + + static bool TryUpdate(int?[,] board, ref int score, Direction direction) + { + (int X, int Y) Adjacent(int x, int y) => + direction switch + { + Direction.Up => (x + 1, y), + Direction.Down => (x - 1, y), + Direction.Left => (x, y - 1), + Direction.Right => (x, y + 1), + _ => throw new NotImplementedException(), + }; + + (int X, int Y) Map(int x, int y) => + direction switch + { + Direction.Up => (board.GetLength(0) - x - 1, y), + Direction.Down => (x, y), + Direction.Left => (x, y), + Direction.Right => (x, board.GetLength(1) - y - 1), + _ => throw new NotImplementedException(), + }; + + bool[,] locked = new bool[board.GetLength(0), board.GetLength(1)]; + + bool update = false; + + for (int i = 0; i < board.GetLength(0); i++) + { + for (int j = 0; j < board.GetLength(1); j++) + { + var (tempi, tempj) = Map(i, j); + if (board[tempi, tempj] is null) + { + continue; + } + KeepChecking: + var (adji, adjj) = Adjacent(tempi, tempj); + if (adji < 0 || adji >= board.GetLength(0) || + adjj < 0 || adjj >= board.GetLength(1) || + locked[adji, adjj]) + { + continue; + } + else if (board[adji, adjj] is null) + { + board[adji, adjj] = board[tempi, tempj]; + board[tempi, tempj] = null; + update = true; + tempi = adji; + tempj = adjj; + goto KeepChecking; + } + else if (board[adji, adjj] == board[tempi, tempj]) + { + board[adji, adjj] += board[tempi, tempj]; + score += board[adji, adjj]!.Value; + board[tempi, tempj] = null; + update = true; + locked[adji, adjj] = true; + } + } + } + return update; + } + + static IEnumerable<(int, int)> BoardValues(int?[,] board) + { + for (int i = board.GetLength(0) - 1; i >= 0; i--) + { + for (int j = 0; j < board.GetLength(1); j++) + { + yield return (i, j); + } + } + } + + static ConsoleColor GetColor(int? value) => + value is null + ? ConsoleColor.DarkGray + : Colors[(value.Value / 2 - 1) % Colors.Length]; + + static void Render(int?[,] board, int score) + { + int horizontal = board.GetLength(0) * 8; + string horizontalBar = new('═', horizontal); + string horizontalSpace = new(' ', horizontal); + + Console.SetCursorPosition(0, 0); + Console.WriteLine("2048"); + Console.WriteLine(); + Console.WriteLine($"╔{horizontalBar}╗"); + Console.WriteLine($"║{horizontalSpace}║"); + for (int i = board.GetLength(1) - 1; i >= 0; i--) + { + Console.Write("║"); + for (int j = 0; j < board.GetLength(0); j++) + { + Console.Write(" "); + ConsoleColor background = Console.BackgroundColor; + Console.BackgroundColor = GetColor(board[i, j]); + Console.Write(string.Format("{0,4}", board[i, j])); + Console.BackgroundColor = background; + Console.Write(" "); + } + Console.WriteLine("║"); + Console.WriteLine($"║{horizontalSpace}║"); + } + Console.WriteLine($"╚{horizontalBar}╝"); + Console.WriteLine($"Score: {score}"); + } + + static ConsoleColor[] Colors = + { + ConsoleColor.DarkBlue, + ConsoleColor.DarkGreen, + ConsoleColor.DarkCyan, + ConsoleColor.DarkRed, + ConsoleColor.DarkMagenta, + ConsoleColor.DarkYellow, + ConsoleColor.Blue, + ConsoleColor.Red, + ConsoleColor.Magenta, + }; +} + + +public enum Direction +{ + Up = 1, + Down = 2, + Left = 3, + Right = 4, +} + diff --git a/Projects/Console Monsters/PCGames/Tents.cs b/Projects/Console Monsters/PCGames/Tents.cs new file mode 100644 index 00000000..aecca5ab --- /dev/null +++ b/Projects/Console Monsters/PCGames/Tents.cs @@ -0,0 +1,425 @@ +using static System.Formats.Asn1.AsnWriter; +using System.Globalization; +using Towel.DataStructures; + +namespace Console_Monsters.PCGames; +public class Tents +{ + static Tile[,] map; + static int[] columnTents; + static int[] rowTents; + static (int Top, int Left) selection; + static bool escape = false; + static int consoleWidth; + static int consoleHeight; + + static char[,] TentSprite = StringToSprite( + @" \/ " + "\n" + + @" /\ " + "\n" + + @" //\\ "); + + static char[,] TreeSprite = StringToSprite( + @" (@@) " + "\n" + + @"(@@@@)" + "\n" + + @" || "); + + static char[,] OpenSprite = StringToSprite( + @" " + "\n" + + @" " + "\n" + + @" "); + + public static void Run() + { + Console.Clear(); + Exception? exception = null; + escape = false; + + try + { + consoleHeight = Console.WindowHeight; + consoleWidth = Console.WindowWidth; + PlayAgain: + selection = (0, 0); + InitializeMapAndCounts(6, 6); + while (!escape && !IsSolved()) + { + RenderBoard(); + RenderPlayingMessage(); + HandleInput(); + } + if (escape) return; + Console.Clear(); + selection = (-1, -1); + RenderBoard(); + RenderSolvedMessage(); + GetEnterOrEscape: + switch (Console.ReadKey(true).Key) + { + case ConsoleKey.Enter: goto PlayAgain; + case ConsoleKey.Escape: return; + default: goto GetEnterOrEscape; + } + } + catch (Exception e) + { + exception = e; + throw; + } + finally + { + Console.ResetColor(); + Console.Clear(); + PCGamesScreen.Render(); + } + } + + static char[,] StringToSprite(string s) + { + string[] splits = s.Split('\n'); + char[,] sprite = new char[splits.Length, splits[0].Length]; + for (int i = 0; i < sprite.GetLength(0); i++) + { + for (int j = 0; j < sprite.GetLength(1); j++) + { + sprite[i, j] = splits[i][j]; + } + } + return sprite; + } + + static void InitializeMapAndCounts(int rows, int columns) + { + map = new Tile[rows, columns]; + columnTents = new int[columns]; + rowTents = new int[rows]; + // generate random map + HashSet<(int Top, int Left)> unavailable = new(); + while (unavailable.Count < rows * columns) + { + Continue: + int next = Random.Shared.Next(0, rows * columns - unavailable.Count); + for (int i = 0, k = -1; i < rows; i++) + { + for (int j = 0; j < columns; j++) + { + if (!unavailable.Contains((i, j))) + { + k++; + } + if (k == next) + { + int availableTreeLocations = 0; + /* N */ + if (i > 0 && !unavailable.Contains((i - 1, j))) availableTreeLocations++; + /* S */ + if (i < rows - 1 && !unavailable.Contains((i + 1, j))) availableTreeLocations++; + /* E */ + if (j < columns - 1 && !unavailable.Contains((i, j + 1))) availableTreeLocations++; + /* W */ + if (j > 0 && !unavailable.Contains((i, j - 1))) availableTreeLocations++; + if (availableTreeLocations is 0) + { + unavailable.Add((i, j)); + } + else + { + map[i, j] = Tile.Tent; + unavailable.Add((i, j)); + Random.Shared.Next(availableTreeLocations); + /* N */ + if (i > 0 && !unavailable.Contains((i - 1, j)) && --availableTreeLocations is 0) { unavailable.Add((i - 1, j)); map[i - 1, j] = Tile.Tree; } + /* S */ + if (i < rows - 1 && !unavailable.Contains((i + 1, j)) && --availableTreeLocations is 0) { unavailable.Add((i + 1, j)); map[i + 1, j] = Tile.Tree; } + /* E */ + if (j < columns - 1 && !unavailable.Contains((i, j + 1)) && --availableTreeLocations is 0) { unavailable.Add((i, j + 1)); map[i, j + 1] = Tile.Tree; } + /* W */ + if (j > 0 && !unavailable.Contains((i, j - 1)) && --availableTreeLocations is 0) { unavailable.Add((i, j - 1)); map[i, j - 1] = Tile.Tree; } + if (i > 0 && j > 0) unavailable.Add((i - 1, j - 1)); + if (i > 0) unavailable.Add((i - 1, j)); + if (i < rows - 1) unavailable.Add((i + 1, j)); + if (i < rows - 1 && j < columns - 1) unavailable.Add((i + 1, j + 1)); + if (j > 0) unavailable.Add((i, j - 1)); + if (j < columns - 1) unavailable.Add((i, j + 1)); + if (i < rows - 1 && j > 0) unavailable.Add((i + 1, j - 1)); + if (i > 0 && j < columns - 1) unavailable.Add((i - 1, j + 1)); + } + goto Continue; + } + } + } + } + // count tents per column + columnTents = new int[columns]; + for (int i = 0; i < columns; i++) + { + int tentCount = 0; + for (int j = 0; j < rows; j++) + { + if (map[j, i] is Tile.Tent) + { + tentCount++; + } + } + columnTents[i] = tentCount; + } + // count tents per row + for (int i = 0; i < rows; i++) + { + int tentCount = 0; + for (int j = 0; j < columns; j++) + { + if (map[i, j] is Tile.Tent) + { + tentCount++; + } + } + rowTents[i] = tentCount; + } + // clear tents from map + for (int i = 0; i < rows; i++) + { + for (int j = 0; j < columns; j++) + { + if (map[i, j] is Tile.Tent) + { + map[i, j] = Tile.Empty; + } + } + } + } + + static void HandleInput() + { + switch (Console.ReadKey(true).Key) + { + case ConsoleKey.W or ConsoleKey.UpArrow: selection.Top = Math.Max(0, selection.Top - 1); break; + case ConsoleKey.S or ConsoleKey.DownArrow: selection.Top = Math.Min(map.GetLength(0) - 1, selection.Top + 1); break; + case ConsoleKey.A or ConsoleKey.LeftArrow: selection.Left = Math.Max(0, selection.Left - 1); break; + case ConsoleKey.D or ConsoleKey.RightArrow: selection.Left = Math.Min(map.GetLength(1) - 1, selection.Left + 1); break; + case ConsoleKey.Enter: + switch (map[selection.Top, selection.Left]) + { + case Tile.Tent: map[selection.Top, selection.Left] = Tile.Empty; break; + case Tile.Empty: map[selection.Top, selection.Left] = Tile.Tent; break; + } + break; + case ConsoleKey.Escape: escape = true; break; + } + } + + static void RenderBoard() + { + if (consoleHeight != Console.WindowHeight || consoleWidth != Console.WindowWidth) + { + Console.Clear(); + consoleHeight = Console.WindowHeight; + consoleWidth = Console.WindowWidth; + } + int boardIndexPixelHeight = OpenSprite.GetLength(0) + 1; + int boardIndexPixelWidth = OpenSprite.GetLength(1) + 1; + int boardPixelsTall = map.GetLength(0) * (OpenSprite.GetLength(0) + 1) + 1; + int boardPixelsWide = map.GetLength(1) * (OpenSprite.GetLength(1) + 1) + 1; + StringBuilder render = new(); + Console.CursorVisible = false; + Console.SetCursorPosition(0, 0); + render.AppendLine(); + render.AppendLine(" Tents"); + render.AppendLine(); + for (int i = 0, mapi = 0, tilei = 0; i < boardPixelsTall; i++, mapi = i / boardIndexPixelHeight, tilei = (i - 1) % boardIndexPixelHeight) + { + render.Append(" "); + for (int j = 0, mapj = 0, tilej = 0; j < boardPixelsWide; j++, mapj = j / boardIndexPixelWidth, tilej = (j - 1) % boardIndexPixelWidth) + { + if (i is 0 && j is 0) render.Append('╔'); + else if (i is 0 && j == boardPixelsWide - 1) render.Append('╗'); + else if (i == boardPixelsTall - 1 && j is 0) render.Append('╚'); + else if (i == boardPixelsTall - 1 && j == boardPixelsWide - 1) render.Append('╝'); + else if (j % boardIndexPixelWidth is 0 && i is 0) render.Append('╦'); + else if (j is 0 && i % boardIndexPixelHeight is 0) render.Append('╠'); + else if (j == boardPixelsWide - 1 && i % boardIndexPixelHeight is 0) render.Append('╣'); + else if (j % boardIndexPixelWidth is 0 && i == boardPixelsTall - 1) render.Append('╩'); + else if (j % boardIndexPixelWidth is 0 && i % boardIndexPixelHeight is 0) render.Append('╬'); + else if (i % boardIndexPixelHeight is 0) render.Append('═'); + else if (j % boardIndexPixelWidth is 0) render.Append('║'); + else + { + char c = GetSprite(map[mapi, mapj])[tilei, tilej]; + if (selection == (mapi, mapj)) + { + if (render.Length > 0) + { + Console.Write(render); + render.Clear(); + } + if (map[mapi, mapj] is Tile.Tent && !IsValidTent(mapi, mapj)) + { + Console.ForegroundColor = ConsoleColor.DarkRed; + } + else + { + Console.ForegroundColor = ConsoleColor.Black; + } + Console.BackgroundColor = ConsoleColor.White; + Console.Write(c); + Console.BackgroundColor = ConsoleColor.Black; + Console.ForegroundColor = ConsoleColor.White; + } + else if (map[mapi, mapj] is Tile.Tent && !IsValidTent(mapi, mapj)) + { + if (render.Length > 0) + { + Console.Write(render); + render.Clear(); + } + Console.BackgroundColor = ConsoleColor.DarkRed; + Console.ForegroundColor = ConsoleColor.White; + Console.Write(c); + Console.BackgroundColor = ConsoleColor.Black; + Console.ForegroundColor = ConsoleColor.White; + } + else + { + render.Append(c); + } + } + } + if (tilei is 1) + { + render.Append($" {rowTents[mapi]}"); + } + render.AppendLine(); + } + render.Append(" "); + for (int i = 0; i < map.GetLength(1); i++) + { + render.Append(" "); + string count = columnTents[i].ToString(CultureInfo.InvariantCulture); + render.Append(count); + render.Append(new string(' ', boardIndexPixelWidth - (3 + count.Length))); + } + render.AppendLine(); + Console.Write(render); + } + + static void RenderPlayingMessage() + { + StringBuilder render = new(); + render.AppendLine(); + render.AppendLine(" Place a tent above, below, left, or right of every tree."); + render.AppendLine(" Do not exceed the expected tent count per row or column."); + render.AppendLine(" Tents may not touch other tents even diagonally."); + render.AppendLine(" Press [WASD] or [arrow keys] to select tiles."); + render.AppendLine(" Press [enter] to place or remove tents."); + render.AppendLine(" Press [escape] to exit."); + Console.Write(render); + } + + static void RenderSolvedMessage() + { + StringBuilder render = new(); + render.AppendLine(); + render.AppendLine(" ******* You solved the puzzle! *******"); + render.AppendLine(" Press [enter] to play again."); + render.AppendLine(" Press [escape] to exit."); + Console.Write(render); + } + + static char[,] GetSprite(Tile tile) => tile switch + { + Tile.Empty => OpenSprite, + Tile.Tree => TreeSprite, + Tile.Tent => TentSprite, + _ => throw new NotImplementedException() + }; + + static bool IsValidTent(int top, int left) + { + // column and row counts + { + int tentCount = 0; + for (int i = 0; i < map.GetLength(0); i++) + { + if (map[i, left] is Tile.Tent) + { + tentCount++; + } + } + if (tentCount > columnTents[left]) return false; + } + { + int tentCount = 0; + for (int i = 0; i < map.GetLength(1); i++) + { + if (map[top, i] is Tile.Tent) + { + tentCount++; + } + } + if (tentCount > rowTents[top]) return false; + } + // touching another tent + if (top > 0 && left > 0 && map[top - 1, left - 1] is Tile.Tent) return false; + if (left > 0 && map[top, left - 1] is Tile.Tent) return false; + if (top > 0 && map[top - 1, left] is Tile.Tent) return false; + if (top < map.GetLength(0) - 1 && map[top + 1, left] is Tile.Tent) return false; + if (left < map.GetLength(1) - 1 && map[top, left + 1] is Tile.Tent) return false; + if (top < map.GetLength(0) - 1 && left < map.GetLength(1) - 1 && map[top + 1, left + 1] is Tile.Tent) return false; + if (top > 0 && left < map.GetLength(1) - 1 && map[top - 1, left + 1] is Tile.Tent) return false; + if (left > 0 && top < map.GetLength(0) - 1 && map[top + 1, left - 1] is Tile.Tent) return false; + // adjecent to a tree + if (top > 0 && map[top - 1, left] is Tile.Tree) return true; + if (left > 0 && map[top, left - 1] is Tile.Tree) return true; + if (top < map.GetLength(0) - 1 && map[top + 1, left] is Tile.Tree) return true; + if (left < map.GetLength(1) - 1 && map[top, left + 1] is Tile.Tree) return true; + return false; + } + + static bool IsSolved() + { + // tents per column + for (int i = 0; i < map.GetLength(1); i++) + { + int tentCount = 0; + for (int j = 0; j < map.GetLength(0); j++) + { + if (map[j, i] is Tile.Tent) + { + tentCount++; + } + } + if (columnTents[i] != tentCount) return false; + } + // tents per row + for (int i = 0; i < map.GetLength(0); i++) + { + int tentCount = 0; + for (int j = 0; j < map.GetLength(1); j++) + { + if (map[i, j] is Tile.Tent) + { + tentCount++; + } + } + if (rowTents[i] != tentCount) return false; + } + // validate tent placements + for (int i = 0; i < map.GetLength(0); i++) + { + for (int j = 0; j < map.GetLength(1); j++) + { + if (map[i, j] is Tile.Tent && !IsValidTent(i, j)) + { + return false; + } + } + } + return true; + } + + public enum Tile + { + Empty = 0, + Tree = 1, + Tent = 2, + } +} diff --git a/Projects/Console Monsters/Player.cs b/Projects/Console Monsters/Player.cs index 8af463b6..ab20d1c0 100644 --- a/Projects/Console Monsters/Player.cs +++ b/Projects/Console Monsters/Player.cs @@ -2,15 +2,22 @@ public class Player { + public List PlayerActiveQuests = new(); + public int Money { get; set; } = 100; + /// Horizontal position in pixel coordinates. public int I { get; set; } + /// Vertical position in pixel coordinates. public int J { get; set; } + /// Currently active animation. public string[] Animation { get; set; } = IdleDown; + /// The current frame of the active animation. public int AnimationFrame {get; set; } = 0; - /// The render state of the character based on the and . + + /// The render state of the player based on the and . public string Render => Animation[AnimationFrame % Animation.Length]; public bool IsIdle => diff --git a/Projects/Console Monsters/Program.cs b/Projects/Console Monsters/Program.cs index d2578cac..76c2e513 100644 --- a/Projects/Console Monsters/Program.cs +++ b/Projects/Console Monsters/Program.cs @@ -11,26 +11,26 @@ public static void Main() Console.CursorVisible = false; Console.OutputEncoding = Encoding.UTF8; - //// disabled because this breaks on Windows Terminal - //if (OperatingSystem.IsWindows()) - //{ - // const int screenWidth = 150; - // const int screenHeight = 50; - // try - // { - // Console.SetWindowSize(screenWidth, screenHeight); - // Console.SetBufferSize(screenWidth, screenHeight); - // } - // catch - // { - // // empty on purpose - // } - //} + // disabled because this breaks on Windows Terminal + if (OperatingSystem.IsWindows()) + { + const int screenWidth = 150; + const int screenHeight = 50; + try + { + Console.SetWindowSize(screenWidth, screenHeight); + Console.SetBufferSize(screenWidth, screenHeight); + } + catch + { + // empty on purpose + } + } StartScreen.Show(); while (GameRunning) { - UpdateCharacter(); + UpdatePlayer(); HandleMapUserInput(); if (GameRunning) { @@ -54,33 +54,33 @@ public static void Main() } } - static void UpdateCharacter() + static void UpdatePlayer() { - if (character.Animation == Player.RunUp) character.J--; - if (character.Animation == Player.RunDown) character.J++; - if (character.Animation == Player.RunLeft) character.I--; - if (character.Animation == Player.RunRight) character.I++; + if (player.Animation == Player.RunUp) player.J--; + if (player.Animation == Player.RunDown) player.J++; + if (player.Animation == Player.RunLeft) player.I--; + if (player.Animation == Player.RunRight) player.I++; - character.AnimationFrame++; + player.AnimationFrame++; - if ((character.Animation == Player.RunUp && character.AnimationFrame >= Sprites.Height) || - (character.Animation == Player.RunDown && character.AnimationFrame >= Sprites.Height) || - (character.Animation == Player.RunLeft && character.AnimationFrame >= Sprites.Width) || - (character.Animation == Player.RunRight && character.AnimationFrame >= Sprites.Width)) + if ((player.Animation == Player.RunUp && player.AnimationFrame >= Sprites.Height) || + (player.Animation == Player.RunDown && player.AnimationFrame >= Sprites.Height) || + (player.Animation == Player.RunLeft && player.AnimationFrame >= Sprites.Width) || + (player.Animation == Player.RunRight && player.AnimationFrame >= Sprites.Width)) { - var (i, j) = MapBase.WorldToTile(character.I, character.J); + var (i, j) = MapBase.WorldToTile(player.I, player.J); Map.PerformTileAction(i, j); - character.Animation = - character.Animation == Player.RunUp ? Player.IdleUp : - character.Animation == Player.RunDown ? Player.IdleDown : - character.Animation == Player.RunLeft ? Player.IdleLeft : - character.Animation == Player.RunRight ? Player.IdleRight : + player.Animation = + player.Animation == Player.RunUp ? Player.IdleUp : + player.Animation == Player.RunDown ? Player.IdleDown : + player.Animation == Player.RunLeft ? Player.IdleLeft : + player.Animation == Player.RunRight ? Player.IdleRight : throw new NotImplementedException(); - character.AnimationFrame = 0; + player.AnimationFrame = 0; } - else if (character.IsIdle && character.AnimationFrame >= character.Animation.Length) + else if (player.IsIdle && player.AnimationFrame >= player.Animation.Length) { - character.AnimationFrame = 0; + player.AnimationFrame = 0; } } @@ -101,9 +101,17 @@ UserKeyPress.Left or { break; } - if (character.IsIdle) + if (ShopText is not null) + { + break; + } + if (PromptShopText is not null) { - var (i, j) = MapBase.WorldToTile(character.I, character.J); + break; + } + if (player.IsIdle) + { + var (i, j) = MapBase.WorldToTile(player.I, player.J); (i, j) = input switch { UserKeyPress.Up => (i, j - 1), @@ -118,28 +126,28 @@ UserKeyPress.Left or { switch (input) { - case UserKeyPress.Up: character.J -= Sprites.Height; character.Animation = Player.IdleUp; break; - case UserKeyPress.Down: character.J += Sprites.Height; character.Animation = Player.IdleDown; break; - case UserKeyPress.Left: character.I -= Sprites.Width; character.Animation = Player.IdleLeft; break; - case UserKeyPress.Right: character.I += Sprites.Width; character.Animation = Player.IdleRight; break; + case UserKeyPress.Up: player.J -= Sprites.Height; player.Animation = Player.IdleUp; break; + case UserKeyPress.Down: player.J += Sprites.Height; player.Animation = Player.IdleDown; break; + case UserKeyPress.Left: player.I -= Sprites.Width; player.Animation = Player.IdleLeft; break; + case UserKeyPress.Right: player.I += Sprites.Width; player.Animation = Player.IdleRight; break; } - var (i2, j2) = MapBase.WorldToTile(character.I, character.J); + var (i2, j2) = MapBase.WorldToTile(player.I, player.J); Map.PerformTileAction(i2, j2); } else { switch (input) { - case UserKeyPress.Up: character.AnimationFrame = 0; character.Animation = Player.RunUp; break; - case UserKeyPress.Down: character.AnimationFrame = 0; character.Animation = Player.RunDown; break; - case UserKeyPress.Left: character.AnimationFrame = 0; character.Animation = Player.RunLeft; break; - case UserKeyPress.Right: character.AnimationFrame = 0; character.Animation = Player.RunRight; break; + case UserKeyPress.Up: player.AnimationFrame = 0; player.Animation = Player.RunUp; break; + case UserKeyPress.Down: player.AnimationFrame = 0; player.Animation = Player.RunDown; break; + case UserKeyPress.Left: player.AnimationFrame = 0; player.Animation = Player.RunLeft; break; + case UserKeyPress.Right: player.AnimationFrame = 0; player.Animation = Player.RunRight; break; } } } else { - character.Animation = input switch + player.Animation = input switch { UserKeyPress.Up => Player.IdleUp, UserKeyPress.Down => Player.IdleDown, @@ -155,39 +163,56 @@ UserKeyPress.Left or { break; } + if (ShopText is not null) + { + break; + } + if (PromptShopText is not null) + { + break; + } InInventory = true; while (InInventory) { InventoryScreen.Render(); - - switch (keyMappings.GetValueOrDefault(Console.ReadKey(true).Key)) + + if (Console.KeyAvailable) { - case UserKeyPress.Up: - if (SelectedPlayerInventoryItem > 0) - { - SelectedPlayerInventoryItem--; - } - else - { - SelectedPlayerInventoryItem = PlayerInventory.Distinct().Count() - 1; - } - break; - case UserKeyPress.Down: - if (SelectedPlayerInventoryItem < PlayerInventory.Distinct().Count() - 1) - { - SelectedPlayerInventoryItem++; - } - else - { - SelectedPlayerInventoryItem = 0; - } - break; - case UserKeyPress.Escape: InInventory = false; break; + switch (keyMappings.GetValueOrDefault(Console.ReadKey(true).Key)) + { + case UserKeyPress.Up: + ItemDescriptionScrollFrame = 0; + if (SelectedPlayerInventoryItem > 0) + { + SelectedPlayerInventoryItem--; + } + else + { + SelectedPlayerInventoryItem = PlayerInventory.Distinct().Count() - 1; + } + break; + case UserKeyPress.Down: + ItemDescriptionScrollFrame = 0; + if (SelectedPlayerInventoryItem < PlayerInventory.Distinct().Count() - 1) + { + SelectedPlayerInventoryItem++; + } + else + { + SelectedPlayerInventoryItem = 0; + } + break; + case UserKeyPress.Escape: InInventory = false; break; + } } + ItemDescriptionScrollFrame++; } break; case UserKeyPress.Confirm: PromptText = null; + ShopText = null; + PromptBattleText = null; + break; case UserKeyPress.Action: if (PromptText is not null) @@ -195,9 +220,19 @@ UserKeyPress.Left or PromptText = null; break; } - if(character.IsIdle) + if (ShopText is not null) + { + ShopText = null; + break; + } + if (PromptShopText is not null) + { + PromptShopText = null; + break; + } + if (player.IsIdle) { - var (i, j) = character.InteractTile; + var (i, j) = player.InteractTile; Map.InteractWithMapTile(i, j); } break; diff --git a/Projects/Console Monsters/Quests/StartQuest.cs b/Projects/Console Monsters/Quests/StartQuest.cs new file mode 100644 index 00000000..497e7a6b --- /dev/null +++ b/Projects/Console Monsters/Quests/StartQuest.cs @@ -0,0 +1,37 @@ +namespace Console_Monsters.Quests; + +public class StartQuest : QuestBase +{ + public StartQuest() + { + QuestName = "Start Quest"; + QuestDescription = "The first quest"; + QuestId = 1; + } + + public override void TriggerQuestStart() + { + var firstNPC = QuestNPCs[0]; + + firstNPC.QuestDialogue = new string[] + { + "Could you go and talk to the scientist", + "and pick up the key for my house?", + "I seem to have locked myself out" + }; + } + + public override void TriggerQuestComplete() + { + var lastNPC = QuestNPCs[QuestNPCs.Count]; + + lastNPC.QuestDialogue = new string[] + { + "Congrats on clearing this quest", + "Here is your reward:", + "[1x Candle]" + }; + + PlayerInventory.TryAdd(Candle.Instance); + } +} diff --git a/Projects/Console Monsters/Screens/BattleScreen.cs b/Projects/Console Monsters/Screens/BattleScreen.cs index 30db7e03..160f59b2 100644 --- a/Projects/Console Monsters/Screens/BattleScreen.cs +++ b/Projects/Console Monsters/Screens/BattleScreen.cs @@ -40,7 +40,7 @@ public static void Render(MonsterBase monsterA, MonsterBase monsterB) continue; } - // map outline + // battle screen outline if (i == midWidth - Sprites.BattleSpriteWidth && j == midHeight - spriteheight) { sb.Append('╔'); @@ -72,13 +72,73 @@ public static void Render(MonsterBase monsterA, MonsterBase monsterB) continue; } + // message prompt if there is one + if (PromptBattleText is not null) + { + int leftBattleMenuBox = (midWidth - Sprites.BattleSpriteWidth) + 4; // Dependant on outer border + int rightBattleMenuBox = (midWidth + Sprites.BattleSpriteWidth) - 4; + + int centerBattleMenuBoxOffset = (midWidth + Sprites.BattleSpriteWidth) - 60; + + int topBattleMenuBox = midHeight + 6; // Dependant on screen height + int bottomBattleMenuBox = heightCutOff - 3; + + if ((i == leftBattleMenuBox && j == topBattleMenuBox) || i == centerBattleMenuBoxOffset && j == topBattleMenuBox) + { + sb.Append('╔'); + continue; + } + if ((i == leftBattleMenuBox && j == bottomBattleMenuBox) || i == centerBattleMenuBoxOffset && j == bottomBattleMenuBox) + { + sb.Append('╚'); + continue; + } + if (i == rightBattleMenuBox && j == topBattleMenuBox) + { + sb.Append('╗'); + continue; + } + if (i == rightBattleMenuBox && j == bottomBattleMenuBox) + { + sb.Append('╝'); + continue; + } + if ((i == leftBattleMenuBox || i == rightBattleMenuBox || i == centerBattleMenuBoxOffset) && j > topBattleMenuBox && j < bottomBattleMenuBox) + { + sb.Append('║'); + continue; + } + if ((j == bottomBattleMenuBox || j == topBattleMenuBox) && i > leftBattleMenuBox && i < rightBattleMenuBox) + { + sb.Append('═'); + continue; + } +#warning TODO: MAJOR REWORK + if (i > leftBattleMenuBox && i < rightBattleMenuBox && j > topBattleMenuBox && j < bottomBattleMenuBox) //Are we at the box? + { + int leftBattleMenuTextOffset = leftBattleMenuBox + 2; // For now has to be 2, NEEDS REWORK + int topBattleMenuTextOffset = topBattleMenuBox + 1; + if (j - (topBattleMenuTextOffset) < PromptBattleText.Length) //Are we inside the box? + { + string line = PromptBattleText[j - (topBattleMenuTextOffset)]; + if (i - leftBattleMenuTextOffset < line.Length - 1) + { + sb.Append(line[i - 10]); + continue; + } + } + sb.Append(' '); + continue; + } + } + //Opponent Monster (MONSTER B) if (i > midWidth - (Sprites.BattleSpriteWidth / 4) * 1 && i < midWidth + (Sprites.BattleSpriteWidth / 4) * 3 + 3 && - j < midHeight && + j < midHeight - 7 && j > midHeight - spriteheight) { - int spriteJ = j - (midHeight - spriteheight) - 1 - (Sprites.BattleSpriteHeight - monsterB.Sprite.Length) / 2; + int spriteJ = j - (midHeight - spriteheight) + 1 - (Sprites.BattleSpriteHeight - monsterB.Sprite.Length) / 2; char c; if (spriteJ < 0 || spriteJ >= monsterB.Sprite.Length) { @@ -103,10 +163,10 @@ public static void Render(MonsterBase monsterA, MonsterBase monsterB) //Player Monster (MONSTER A) if (i > midWidth - (Sprites.BattleSpriteWidth / 4) * 3 - 3 && i < midWidth + (Sprites.BattleSpriteWidth / 4) * 1 && - j < midHeight + spriteheight && - j > midHeight) + j < midHeight + spriteheight - 15 && + j > midHeight - 8) { - int spriteJ = j - midHeight - 1 - (Sprites.BattleSpriteHeight - monsterB.Sprite.Length) / 2; + int spriteJ = j - midHeight + 8 - (Sprites.BattleSpriteHeight - monsterB.Sprite.Length) / 2; char c; if (spriteJ < 0 || spriteJ >= monsterA.Sprite.Length) { @@ -138,4 +198,70 @@ public static void Render(MonsterBase monsterA, MonsterBase monsterB) Console.SetCursorPosition(0, 0); Console.Write(sb); } + + // For giving more offest to the battle text +#warning TODO: FIX + private static string[] NewBattleText(string[] oldBattleText) + { + int offset = 4; + string BattleTextOffset = string.Empty; + + for (int i = 0; i < offset; i++) + { + BattleTextOffset.Concat(" "); + } + + for (int i = 0; i < oldBattleText.Length; i++) + { + oldBattleText[i] = BattleTextOffset + oldBattleText[i]; + } + + return oldBattleText; + } + + public static void DrawStats(MonsterBase PlayerMonster, MonsterBase OpponentMonster) + { + Console.SetCursorPosition(66, 23); + Console.WriteLine($"{PlayerMonster.Name}"); + Console.SetCursorPosition(77, 23); + Console.WriteLine($"LVL:{PlayerMonster.Level}"); + Console.SetCursorPosition(66, 24); + Console.WriteLine($"HP: {DrawBar(PlayerMonster.CurrentHP, PlayerMonster.MaximumHP)} {(int)PlayerMonster.CurrentHP}/{(int)PlayerMonster.MaximumHP}"); + Console.SetCursorPosition(66, 25); + Console.WriteLine($"Energy: {DrawBar(PlayerMonster.CurrentEnergy, PlayerMonster.MaximumEnergy)} {PlayerMonster.CurrentEnergy}/{PlayerMonster.MaximumEnergy}"); + + Console.SetCursorPosition(49, 10); + Console.WriteLine($"{OpponentMonster.Name}"); + Console.SetCursorPosition(59, 10); + Console.WriteLine($"LVL:{OpponentMonster.Level}"); + Console.SetCursorPosition(49, 11); + Console.WriteLine($"HP: {DrawBar(OpponentMonster.CurrentHP, OpponentMonster.MaximumHP)}"); + Console.SetCursorPosition(49, 12); + Console.WriteLine($"Energy:{DrawBar(OpponentMonster.CurrentEnergy, OpponentMonster.MaximumEnergy)}"); + } + + public static string DrawBar(double current, double max) + { + const char block = '■'; + const char empty = ' '; + string final = string.Empty; + + int barLength = 20; + //double tenpercent = (int)max / 10; + current += 0.0001; // Float point issue fix, was missing 1 block + double fivepercent = max / 10 / 2; + + final += "["; + for (int i = 0; i < barLength; i++) + { + if (current >= fivepercent) + final += block; + else + final += empty; + current -= fivepercent; + } + final += "]"; + + return final; + } } diff --git a/Projects/Console Monsters/Screens/InventoryScreen.cs b/Projects/Console Monsters/Screens/InventoryScreen.cs index 4583591f..8185974d 100644 --- a/Projects/Console Monsters/Screens/InventoryScreen.cs +++ b/Projects/Console Monsters/Screens/InventoryScreen.cs @@ -8,321 +8,322 @@ public static void Render() var (width, height) = ConsoleHelpers.GetWidthAndHeight(); - string monsterDetails; - bool nextDone = false; - bool currentDone = false; - int minWidth = 4; int minHeight = 2; int maxHeight = height - MapText.Length - 3; + int inventoryWidth = (width / 2) + minWidth; + int inventorySpacing = Sprites.Height + 1; - int nextMonster = 1; - int nextMonsterWidth; - int nextMonsterHeight = 0; - int currentMonster = 0; - int currentMonsterWidth; - int currentMonsterHeight; - int monsterWidthSpacing = 35; - int monsterHeightSpacing = 1; + int relativeVisualPosition = 0; + string monsterDetails = string.Empty; int[] monsterSpriteIndex = new int[6]; + (int Width, int Height) monsterSpacing = (35, 1); + (int Index, int Width, int Height) leftMonster = (0, 0, 0); + (int Index, int Width, int Height) rightMonster = (1, 0, 0); + (bool LeftMonster, bool RightMonster) rendered = (false, false); + (int ID, int Index, string[] Sprite, string Description, string Count) item = (0, 0, Array.Empty(), string.Empty, string.Empty); - int itemBorderGap = 4; - int scrollBorder = 2; - int startIndex = 0; - string itemInfo; - string itemCount; - string[] itemSprite; - List items; - int inventoryWidth = (width / 2) + minWidth; - int inventoryHeight = minHeight; - int inventoryHeightSpacing = Sprites.Height + 1; - int spriteIndex = 0; - int itemIndex = 0; +#warning TODO: optimize + List allItems = PlayerInventory.Distinct().ToList(); if (partyMonsters.Count < 1) { - currentMonster = -1; + leftMonster.Index = -1; } -#warning TODO: optimize - items = PlayerInventory.Distinct().ToList(); - - if (SelectedPlayerInventoryItem >= maxHeight / inventoryHeightSpacing) + if (SelectedPlayerInventoryItem >= maxHeight / inventorySpacing) { - startIndex = SelectedPlayerInventoryItem - (maxHeight / inventoryHeightSpacing) + 1; + relativeVisualPosition = SelectedPlayerInventoryItem - (maxHeight / inventorySpacing) + 1; } + StringBuilder sb = new(width * height); for (int j = 0; j < maxHeight; j++) { for (int i = 0; i < width; i++) { + #region Monsters // rendering monsters - if (currentMonster < partyMonsters.Count) + if (leftMonster.Index < partyMonsters.Count) { - currentMonsterWidth = partyMonsters[currentMonster].Sprite[0].Length; - currentMonsterHeight = partyMonsters[currentMonster].Sprite.GetLength(0); + leftMonster.Width = partyMonsters[leftMonster.Index].Sprite[0].Length; + leftMonster.Height = partyMonsters[leftMonster.Index].Sprite.GetLength(0); - if (i >= minWidth && i <= minWidth + currentMonsterWidth && - j >= minHeight + monsterHeightSpacing && j < minHeight + currentMonsterHeight + monsterHeightSpacing && j < maxHeight - 1) + if (i >= minWidth && i <= minWidth + leftMonster.Width && + j >= minHeight + monsterSpacing.Height && j < minHeight + leftMonster.Height + monsterSpacing.Height && j < maxHeight - 1) { - if (j == minHeight + monsterHeightSpacing + currentMonsterHeight - 1 && monsterSpriteIndex[currentMonster] == currentMonsterWidth) + if (j == minHeight + monsterSpacing.Height + leftMonster.Height - 1 && monsterSpriteIndex[leftMonster.Index] == leftMonster.Width) { sb.Append(' '); continue; } - if (monsterSpriteIndex[currentMonster] == currentMonsterWidth) + if (monsterSpriteIndex[leftMonster.Index] == leftMonster.Width) { - monsterSpriteIndex[currentMonster] = 0; + monsterSpriteIndex[leftMonster.Index] = 0; sb.Append(' '); continue; } - sb.Append(partyMonsters[currentMonster].Sprite[j - minHeight - monsterHeightSpacing][monsterSpriteIndex[currentMonster]]); - monsterSpriteIndex[currentMonster]++; + sb.Append(partyMonsters[leftMonster.Index].Sprite[j - minHeight - monsterSpacing.Height][monsterSpriteIndex[leftMonster.Index]]); + monsterSpriteIndex[leftMonster.Index]++; continue; } - if (i == minWidth && j == minHeight + currentMonsterHeight + monsterHeightSpacing && j < maxHeight - 1) + if (i == minWidth && j == minHeight + leftMonster.Height + monsterSpacing.Height && j < maxHeight - 1) { - monsterDetails = $"{partyMonsters[currentMonster].Name} HP:{partyMonsters[currentMonster].CurrentHP} Level:{partyMonsters[currentMonster].Level}"; + monsterDetails = $"{partyMonsters[leftMonster.Index].Name} HP:{(int)partyMonsters[leftMonster.Index].CurrentHP} Level:{partyMonsters[leftMonster.Index].Level}"; + sb.Append(monsterDetails); i += monsterDetails.Length - 1; - currentDone = true; + rendered.LeftMonster = true; continue; } - if (nextMonster < partyMonsters.Count) + if (rightMonster.Index < partyMonsters.Count) { - nextMonsterWidth = partyMonsters[nextMonster].Sprite[0].Length; - nextMonsterHeight = partyMonsters[nextMonster].Sprite.GetLength(0); + rightMonster.Width = partyMonsters[rightMonster.Index].Sprite[0].Length; + rightMonster.Height = partyMonsters[rightMonster.Index].Sprite.GetLength(0); - if (i >= minWidth + monsterWidthSpacing && i <= minWidth + nextMonsterWidth + monsterWidthSpacing && - j >= minHeight + monsterHeightSpacing && j < minHeight + nextMonsterHeight + monsterHeightSpacing && j < maxHeight - 1) + if (i >= minWidth + monsterSpacing.Width && i <= minWidth + rightMonster.Width + monsterSpacing.Width && + j >= minHeight + monsterSpacing.Height && j < minHeight + rightMonster.Height + monsterSpacing.Height && j < maxHeight - 1) { - if (j == minHeight + monsterHeightSpacing + nextMonsterHeight - 1 && monsterSpriteIndex[nextMonster] == nextMonsterWidth) + if (j == minHeight + monsterSpacing.Height + rightMonster.Height - 1 && monsterSpriteIndex[rightMonster.Index] == rightMonster.Width) { sb.Append(' '); continue; } - if (monsterSpriteIndex[nextMonster] == nextMonsterWidth) + if (monsterSpriteIndex[rightMonster.Index] == rightMonster.Width) { - monsterSpriteIndex[nextMonster] = 0; + monsterSpriteIndex[rightMonster.Index] = 0; sb.Append(' '); continue; } - sb.Append(partyMonsters[nextMonster].Sprite[j - minHeight - monsterHeightSpacing][monsterSpriteIndex[nextMonster]]); - monsterSpriteIndex[nextMonster]++; + sb.Append(partyMonsters[rightMonster.Index].Sprite[j - minHeight - monsterSpacing.Height][monsterSpriteIndex[rightMonster.Index]]); + monsterSpriteIndex[rightMonster.Index]++; continue; } - if (i == minWidth + monsterWidthSpacing && - j == minHeight + nextMonsterHeight + monsterHeightSpacing && j < maxHeight - 1) + if (i == minWidth + monsterSpacing.Width && + j == minHeight + rightMonster.Height + monsterSpacing.Height && j < maxHeight - 1) { - monsterDetails = $"{partyMonsters[nextMonster].Name} HP:{partyMonsters[nextMonster].CurrentHP}"; + monsterDetails = $"{partyMonsters[rightMonster.Index].Name} HP:{partyMonsters[rightMonster.Index].CurrentHP}"; sb.Append(monsterDetails); i += monsterDetails.Length - 1; - nextDone = true; + rendered.RightMonster = true; continue; } } - if (currentDone && nextDone) + if (rendered.LeftMonster && rendered.RightMonster) { - monsterHeightSpacing += currentMonsterHeight > nextMonsterHeight ? currentMonsterHeight : nextMonsterHeight; - monsterHeightSpacing += Sprites.Height; - currentMonster += 2; - nextMonster += 2; - currentDone = false; - nextDone = false; + monsterSpacing.Height += leftMonster.Height > rightMonster.Height ? leftMonster.Height : rightMonster.Height; + monsterSpacing.Height += Sprites.Height; + rightMonster.Index += 2; + leftMonster.Index += 2; + rendered = (false, false); } } - { // border for selected item - if (i == inventoryWidth - 1) + if (leftMonster.Index < partyMonsters.Count) + { + monsterSpriteIndex[leftMonster.Index] = 0; + } + #endregion + + #region Items + { + // rendering items + int itemAbsoluteIndex = item.ID + relativeVisualPosition; + if (allItems.Count > 0 && itemAbsoluteIndex < allItems.Count) { - if (j == inventoryHeight + ((SelectedPlayerInventoryItem - startIndex) * inventoryHeightSpacing) - 1) - { - sb.Append('╔'); // ┌╔ - continue; - } - if (j > inventoryHeight + ((SelectedPlayerInventoryItem - startIndex) * inventoryHeightSpacing) - 1 && - j < inventoryHeight + ((SelectedPlayerInventoryItem - startIndex) * inventoryHeightSpacing) + Sprites.Height) + if (i >= inventoryWidth && i < inventoryWidth + Sprites.Width && + j >= minHeight + (item.ID * inventorySpacing) && j < minHeight + (item.ID * inventorySpacing) + Sprites.Height && j < maxHeight - 1) { - sb.Append('║'); // │║ + item.Sprite = allItems[itemAbsoluteIndex].Sprite.Split('\n'); + + sb.Append(item.Sprite[item.Index]); + i += item.Sprite[item.Index].Length - 1; + item.Index++; + + if (item.Index == Sprites.Height) + { + item.Count = $"x{PlayerInventory[allItems[itemAbsoluteIndex]]}"; + sb.Append(item.Count); + i += item.Count.Length; + + item.Index = 0; + item.ID++; + } continue; } - if (j == inventoryHeight + ((SelectedPlayerInventoryItem - startIndex) * inventoryHeightSpacing) + Sprites.Height) + + if (i == inventoryWidth + Sprites.Width + 1 && j == minHeight + (item.ID * inventorySpacing) + Sprites.Height / 2 && j < maxHeight - 1) { - sb.Append('╚'); // └╚ + string ellipsis = "..."; + string itemName = allItems[itemAbsoluteIndex].Name; + string itemInfo = allItems[itemAbsoluteIndex].Description; + int currentDescriptionIndex = ItemDescriptionScrollFrame / 100; + + item.Description = $"{itemName} | {itemInfo}"; + + if (i + item.Description.Length > width - 4) + { + if (j == minHeight + ((SelectedPlayerInventoryItem - relativeVisualPosition) * inventorySpacing) + Sprites.Height / 2) + { + if (currentDescriptionIndex >= itemInfo.Length) + { + ItemDescriptionScrollFrame = 0; + } + + item.Description = $"{itemName} | {itemInfo[currentDescriptionIndex..]} {itemInfo[..currentDescriptionIndex]}"; + } + item.Description = $"{item.Description[..(width - i - 4 - ellipsis.Length)]}{ellipsis}"; + } + + sb.Append(item.Description); + i += item.Description.Length - 1; continue; } } - if (i >= inventoryWidth && i < width - itemBorderGap) + + // rendering scroll bar + if (allItems.Count * Sprites.Height > maxHeight - 2) { - if (j == inventoryHeight + ((SelectedPlayerInventoryItem - startIndex) * inventoryHeightSpacing) - 1 || - j == inventoryHeight + ((SelectedPlayerInventoryItem - startIndex) * inventoryHeightSpacing) + Sprites.Height) + if (i == width - 2) { - sb.Append('═'); // ─═ - continue; + if (j == 1) + { + sb.Append('▲'); + continue; + } + if (j > 1 && j < maxHeight - 2) + { + if (j >= 1 + (SelectedPlayerInventoryItem * inventorySpacing) && j <= 1 + ((SelectedPlayerInventoryItem + 1) * inventorySpacing) || + j > maxHeight - inventorySpacing - 2 && SelectedPlayerInventoryItem >= maxHeight / inventorySpacing) + { + sb.Append('█'); + continue; + } + + sb.Append('│'); + continue; + } + if (j == maxHeight - 2) + { + sb.Append('▼'); + continue; + } } } - if (i == width - itemBorderGap) + } + #endregion + + #region Borders + // border for selected item + { + bool left = i == inventoryWidth - 1; + if (left || i == width - 4) { - if (j == inventoryHeight + ((SelectedPlayerInventoryItem - startIndex) * inventoryHeightSpacing) - 1) + if (j == minHeight + ((SelectedPlayerInventoryItem - relativeVisualPosition) * inventorySpacing) - 1) { - sb.Append('╗'); // ┐╗ + sb.Append(left ? '╔' : '╗'); continue; } - if (j > inventoryHeight + ((SelectedPlayerInventoryItem - startIndex) * inventoryHeightSpacing) - 1 && - j < inventoryHeight + ((SelectedPlayerInventoryItem - startIndex) * inventoryHeightSpacing) + Sprites.Height) + if (j == minHeight + ((SelectedPlayerInventoryItem - relativeVisualPosition) * inventorySpacing) + Sprites.Height) { - sb.Append('║'); // │║ - continue; + if (j < maxHeight - 1) + { + sb.Append(left ? '╚' : '╝'); + continue; + } + if (j == maxHeight - 1) + { + sb.Append('╩'); + continue; + } } - if (j == inventoryHeight + ((SelectedPlayerInventoryItem - startIndex) * inventoryHeightSpacing) + Sprites.Height) + if (j > minHeight + ((SelectedPlayerInventoryItem - relativeVisualPosition) * inventorySpacing) - 1 && + j < minHeight + ((SelectedPlayerInventoryItem - relativeVisualPosition) * inventorySpacing) + Sprites.Height) { - sb.Append('╝'); // ┘╝ + sb.Append('║'); continue; } } - } - // rendering items - if (items.Count > 0 && (itemIndex + startIndex) < items.Count) - { - if (i >= inventoryWidth && i < inventoryWidth + Sprites.Width && - j >= inventoryHeight + (itemIndex * inventoryHeightSpacing) && j < inventoryHeight + (itemIndex * inventoryHeightSpacing) + Sprites.Height && j < maxHeight - 1) + if (i >= inventoryWidth && i < width - 4 && + (j == minHeight + ((SelectedPlayerInventoryItem - relativeVisualPosition) * inventorySpacing) - 1 || + j == minHeight + ((SelectedPlayerInventoryItem - relativeVisualPosition) * inventorySpacing) + Sprites.Height)) { - itemSprite = items[itemIndex + startIndex].Sprite.Split('\n'); - - sb.Append(itemSprite[spriteIndex]); - i += itemSprite[spriteIndex].Length - 1; - spriteIndex++; - - if (spriteIndex == Sprites.Height) - { - itemCount = $"x{PlayerInventory[items[itemIndex + startIndex]]}"; - sb.Append(itemCount); - i += itemCount.Length; - - spriteIndex = 0; - itemIndex++; - } - continue; - } - - if (i == inventoryWidth + Sprites.Width + 1 && j == inventoryHeight + (itemIndex * inventoryHeightSpacing) + Sprites.Height / 2 && j < maxHeight - 1) - { - string ellipsis = "..."; - itemInfo = $"{items[itemIndex + startIndex].Name} | {items[itemIndex + startIndex].Description}"; - if (i + itemInfo.Length > width - itemBorderGap) - { - //shorten info if too long - itemInfo = $"{itemInfo[..(width - i - itemBorderGap - ellipsis.Length)]}{ellipsis}"; - } - sb.Append(itemInfo); - i += itemInfo.Length - 1; + sb.Append('═'); continue; } } - // rendering scroll bar - if (items.Count * Sprites.Height > maxHeight - scrollBorder) + // border { - if (i == width - 2) + if (i == width / 2) { - if (j == 1) + if (j > 0 && j < maxHeight - 1) { - sb.Append('▲'); + sb.Append('│'); continue; } - if (j > 1 && j < maxHeight - scrollBorder) + if (j is 0) { - if (j >= 1 + (SelectedPlayerInventoryItem * inventoryHeightSpacing) && j <= 1 + ((SelectedPlayerInventoryItem + 1) * inventoryHeightSpacing)) - { - sb.Append('█'); - continue; - } - if (SelectedPlayerInventoryItem >= maxHeight / inventoryHeightSpacing && j > maxHeight - inventoryHeightSpacing - (scrollBorder * 2)) - { - sb.Append('█'); - continue; - } - - sb.Append('│'); + sb.Append('╤'); continue; } - if (j == maxHeight - scrollBorder) + if (j == maxHeight - 1) { - sb.Append('▼'); + sb.Append('╧'); continue; } } - } - - // border - if (i == width / 2) - { - if (j > 0 && j < maxHeight - 1) + if (j > 0 && i > 0 && j < maxHeight - 1 && i < width - 1) { - sb.Append('│'); // ║ + sb.Append(' '); continue; } - if (j == 0) + if (i is 0 && j is 0) { - sb.Append('╤'); // ╦ + sb.Append('╔'); continue; } - if (j == maxHeight - 1) + if (i is 0 && j == maxHeight - 1) { - sb.Append('╧'); // ╩ + sb.Append('╚'); + continue; + } + if (i == width - 1 && j is 0) + { + sb.Append('╗'); + continue; + } + if (i == width - 1 && j == maxHeight - 1) + { + sb.Append('╝'); + continue; + } + if (i is 0 || i == width - 1) + { + sb.Append('║'); + continue; + } + if (j is 0 || j == maxHeight - 1) + { + sb.Append('═'); continue; } } - if (j > 0 && i > 0 && j < maxHeight - 1 && i < width - 1) - { - sb.Append(' '); - continue; - } - if (i is 0 && j is 0) - { - sb.Append('╔'); - continue; - } - if (i is 0 && j == maxHeight - 1) - { - sb.Append('╚'); - continue; - } - if (i == width - 1 && j is 0) - { - sb.Append('╗'); - continue; - } - if (i == width - 1 && j == maxHeight - 1) - { - sb.Append('╝'); - continue; - } - if (i is 0 || i == width - 1) - { - sb.Append('║'); - continue; - } - if (j is 0 || j == maxHeight - 1) - { - sb.Append('═'); - continue; - } + #endregion - sb.AppendLine(); - if (currentMonster < partyMonsters.Count) + if (!OperatingSystem.IsWindows() && j < height - 1) { - monsterSpriteIndex[currentMonster] = 0; + sb.AppendLine(); } } } + Console.SetCursorPosition(0, 0); Console.Write(sb); } diff --git a/Projects/Console Monsters/Screens/MapScreen.cs b/Projects/Console Monsters/Screens/MapScreen.cs index 150bd590..b0cc83be 100644 --- a/Projects/Console Monsters/Screens/MapScreen.cs +++ b/Projects/Console Monsters/Screens/MapScreen.cs @@ -119,20 +119,118 @@ public static void Render() } } + // shop middle prompt if there is one + if (PromptShopText is not null) + { + if (i is 20 && j == 20) + { + sb.Append('╔'); + continue; + } + if (i is 20 && j == heightCutOff - 20) + { + sb.Append('╚'); + continue; + } + if (i == midWidth - 40 && j == 20) + { + sb.Append('╗'); + continue; + } + if (i == midWidth - 40 && j == heightCutOff - 20) + { + sb.Append('╝'); + continue; + } + if ((i is 20 || i == midWidth - 40) && j > 20 && j < heightCutOff - 20) + { + sb.Append('║'); + continue; + } + if ((j == heightCutOff - 20 || j == 20) && i > 20 && i < midWidth - 40) + { + sb.Append('═'); + continue; + } + if (i > 20 && i < midWidth - 40 && j > 20 && j < heightCutOff - 20) + { + if (j - (21) < PromptShopText.Length) + { + string line = PromptShopText[j - (21)]; + if (i - 21 < line.Length) + { + sb.Append(line[i - 21]); + continue; + } + } + sb.Append(' '); + continue; + } + } + + // shop prompt if there is one + if (ShopText is not null) + { + if (i is 5 && j == 4) + { + sb.Append('╔'); + continue; + } + if (i is 5 && j == heightCutOff - 6) + { + sb.Append('╚'); + continue; + } + if (i == midWidth - 20 && j == 4) + { + sb.Append('╗'); + continue; + } + if (i == midWidth - 20 && j == heightCutOff - 6) + { + sb.Append('╝'); + continue; + } + if ((i is 5 || i == midWidth - 20) && j > 4 && j < heightCutOff - 5) + { + sb.Append('║'); + continue; + } + if ((j == heightCutOff - 6 || j == 4) && i > 5 && i < midWidth - 20) + { + sb.Append('═'); + continue; + } + if (i > 5 && i < midWidth - 20 && j > 4 && j < heightCutOff - 6) + { + if (j - (5) < ShopText.Length) + { + string line = ShopText[j - (5)]; + if (i - 6 < line.Length) + { + sb.Append(line[i - 6]); + continue; + } + } + sb.Append(' '); + continue; + } + } + // character if (i > midWidth - 4 && i < midWidth + 4 && j > midHeight - 3 && j < midHeight + 3) { int ci = i - (midWidth - 3); int cj = j - (midHeight - 2); - string characterMapRender = character.Render; + string characterMapRender = player.Render; sb.Append(characterMapRender[cj * (Sprites.Width + 1) + ci]); continue; } // tiles // compute the map location that this screen pixel represents - int mapI = i - midWidth + character.I + 3; - int mapJ = j - midHeight + character.J + 2; + int mapI = i - midWidth + player.I + 3; + int mapJ = j - midHeight + player.J + 2; // compute the coordinates of the tile int tileI = mapI < 0 ? (mapI - (Sprites.Width - 1)) / Sprites.Width : mapI / Sprites.Width; diff --git a/Projects/Console Monsters/Screens/Menus/ControlsScreen.cs b/Projects/Console Monsters/Screens/Menus/ControlsScreen.cs index c3e79090..86916927 100644 --- a/Projects/Console Monsters/Screens/Menus/ControlsScreen.cs +++ b/Projects/Console Monsters/Screens/Menus/ControlsScreen.cs @@ -147,9 +147,9 @@ private static void PerformKeyMap(UserKeyPress userInput) { alternate = null; } - bool valid_main = !keyMappings.ContainsKey(main) || keyMappings[main] == userInput; - bool valid_alternate = alternate is null || !keyMappings.ContainsKey(alternate.Value) || keyMappings[alternate.Value] == userInput; - if (valid_main && valid_alternate) + bool validMain = !keyMappings.ContainsKey(main) || keyMappings[main] == userInput; + bool validAlternate = alternate is null || !keyMappings.ContainsKey(alternate.Value) || keyMappings[alternate.Value] == userInput; + if (validMain && validAlternate) { reverseKeyMappings[userInput] = (main, alternate); ApplyKeyMappings(); diff --git a/Projects/Console Monsters/Screens/Menus/PCGamesScreen.cs b/Projects/Console Monsters/Screens/Menus/PCGamesScreen.cs new file mode 100644 index 00000000..a3865e2c --- /dev/null +++ b/Projects/Console Monsters/Screens/Menus/PCGamesScreen.cs @@ -0,0 +1,120 @@ +namespace Console_Monsters.Screens.Menus; +public class PCGamesScreen +{ + public static void Render() + { + Console.CursorVisible = false; + + string[] bigHeader = new[] + { + "██████╗ ██████╗ ██████╗ █████╗ ███╗ ███╗███████╗███████╗", + "██╔══██╗██╔════╝ ██╔════╝ ██╔══██╗████╗ ████║██╔════╝██╔════╝", + "██████╔╝██║ ██║ ███╗███████║██╔████╔██║█████╗ ███████╗", + "██╔═══╝ ██║ ██║ ██║██╔══██║██║╚██╔╝██║██╔══╝ ╚════██║", + "██║ ╚██████╗ ╚██████╔╝██║ ██║██║ ╚═╝ ██║███████╗███████║", + "╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚══════╝", + }; + int bigHeaderWidth = bigHeader.Max(line => line.Length); + const int bigHeaderPadding = 2; + const int optionPadding = 1; + var (consoleWidth, consoleHeight) = ConsoleHelpers.GetWidthAndHeight(); + Console.Clear(); + int selectedOption = 0; + bool needToRender = true; + + int heightCutOff = consoleHeight - MapText.Length - 3; + int midWidth = consoleWidth / 2; + int midHeight = heightCutOff / 2; + + while (true) + { + if (ConsoleHelpers.ClearIfConsoleResized(ref consoleWidth, ref consoleHeight)) + { + needToRender = true; + Console.CursorVisible = false; + } + if (needToRender) + { + StringBuilder? buffer = null; + if (consoleWidth - 1 >= bigHeaderWidth) + { + string[][] options = new[] + { + AsciiGenerator.Concat(AsciiGenerator.ToAscii((selectedOption is 0 ? "■" : "□") + " 2048")), + AsciiGenerator.Concat(AsciiGenerator.ToAscii((selectedOption is 1 ? "■" : "□") + " Tents")), + AsciiGenerator.Concat(AsciiGenerator.ToAscii((selectedOption is 2 ? "■" : "□") + " Game3")), + AsciiGenerator.Concat(AsciiGenerator.ToAscii((selectedOption is 3 ? "■" : "□") + " Game4")), + AsciiGenerator.Concat(AsciiGenerator.ToAscii((selectedOption is 4 ? "■" : "□") + " Game5")), + AsciiGenerator.Concat(AsciiGenerator.ToAscii((selectedOption is 5 ? "■" : "□") + " Game6")), + AsciiGenerator.Concat(AsciiGenerator.ToAscii((selectedOption is 6 ? "■" : "□") + " Game7")), + }; + int optionsWidth = options.Max(o => o.Max(l => l.Length)); + int bigRenderHeight = bigHeader.Length + options.Sum(o => o.Length) + bigHeaderPadding + optionPadding * options.Length; + if (consoleHeight - 1 >= bigRenderHeight && consoleWidth - 1 >= optionsWidth) + { + int indentSize = Math.Max(0, (bigHeaderWidth - optionsWidth) / 2); + string indent = new(' ', indentSize); + string[] render = new string[bigRenderHeight]; + int i = 0; + foreach (string line in bigHeader) + { + render[i++] = line; + } + i += bigHeaderPadding; + foreach (string[] option in options) + { + i += optionPadding; + foreach (string line in option) + { + render[i++] = indent + line; + } + } + buffer = ScreenHelpers.Center(render, (consoleHeight - 1, consoleWidth - 1)); + } + } + if (buffer is null) + { + string[] render = new[] + { + $@"PC Games", + $@"{(selectedOption is 0 ? ">" : " ")} 2048", + $@"{(selectedOption is 1 ? ">" : " ")} Tents", + $@"{(selectedOption is 2 ? ">" : " ")} Game 3", + $@"{(selectedOption is 3 ? ">" : " ")} Game 4", + $@"{(selectedOption is 4 ? ">" : " ")} Game 5", + $@"{(selectedOption is 5 ? ">" : " ")} Game 6", + $@"{(selectedOption is 6 ? ">" : " ")} Game 7", + }; + buffer = ScreenHelpers.Center(render, (consoleHeight - 1, consoleWidth - 1)); + } + Console.SetCursorPosition(0, 0); + Console.Write(buffer); + needToRender = false; + } + while (Console.KeyAvailable) + { + switch (keyMappings.GetValueOrDefault(Console.ReadKey(true).Key)) + { + case UserKeyPress.Escape: return; + case UserKeyPress.Up: selectedOption = Math.Max(0, selectedOption - 1); needToRender = true; break; + case UserKeyPress.Down: selectedOption = Math.Min(6, selectedOption + 1); needToRender = true; break; + case UserKeyPress.Confirm: + switch (selectedOption) + { + case 0: _2048.Run(); break; + case 1: Tents.Run(); break; + case 2: break; + case 3: break; + case 4: break; + case 5: break; + case 6: break; + default: throw new NotImplementedException(); + } + break; + } + } + // prevent CPU spiking + Thread.Sleep(TimeSpan.FromMilliseconds(1)); + } + } +} diff --git a/Projects/Console Monsters/Screens/Menus/ShopScreen.cs b/Projects/Console Monsters/Screens/Menus/ShopScreen.cs new file mode 100644 index 00000000..298eb590 --- /dev/null +++ b/Projects/Console Monsters/Screens/Menus/ShopScreen.cs @@ -0,0 +1,153 @@ +namespace Console_Monsters.Screens.Menus; + +public class ShopScreen +{ + public static void Render() + { + if (Shop is null) throw new Exception("attempting to render a null shop"); + if (PromptText is not null) throw new Exception("attempting to render shop when prompt is active"); + + ItemBase.ItemCategory[] categories = Shop.Inventory.Select(row => row.Item.Category).Distinct().ToArray(); + int selection = 0; + int category = 0; + string[] TomsAsciiText = AsciiGenerator.ToAscii(Shop?.Name ?? "Shop"); + ShopBase.Row[] itemsInCategory = Shop.Inventory.Where(row => row.Item.Category == categories[category]).ToArray(); + + while (Shop is not null) + { + List shopText = new(); + + // header + string[]? characterSprite = Shop.Character?.Sprite.Split('\n'); + shopText.Add($"{characterSprite?[0]}"); + shopText.Add($"{characterSprite?[1]} {TomsAsciiText[0]}"); + shopText.Add($"{characterSprite?[2]} {TomsAsciiText[1]}"); + shopText.Add($"{characterSprite?[3]} {TomsAsciiText[2]}"); + shopText.Add($"{characterSprite?[4]}"); + + // tabs + shopText.Add($"{new string('═', 100)}"); + shopText.Add(string.Join(" ", categories.Select(c => c == categories[category] ? (selection is 0 ? $">[{c}]<" : $"[{c}]") : c.ToString()))); + shopText.Add($"{new string('═', 100)}"); + + // items + int r = 0; + foreach (ShopBase.Row row in itemsInCategory) + { + string[] sprite = row.Item.Sprite.Split('\n'); + + shopText.Add($"{(r == selection - 1 ? ">" : " ")}{sprite[0]} {row.Item.Name}"); + shopText.Add($"{(r == selection - 1 ? ">" : " ")}{sprite[1]}"); + shopText.Add($"{(r == selection - 1 ? ">" : " ")}{sprite[2]} ${row.Price}"); + shopText.Add($"{(r == selection - 1 ? ">" : " ")}{sprite[3]} Stock Left: {row.Quantity}"); + shopText.Add($"{(r == selection - 1 ? ">" : " ")}{sprite[4]} {row.Item.Description}"); + shopText.Add(""); + r++; + } + + ShopText = shopText.ToArray(); + MapScreen.Render(); + + SleepAfterRender(); + + while (Console.KeyAvailable) + { + ConsoleKey key = Console.ReadKey(true).Key; + switch (keyMappings.GetValueOrDefault(key)) + { + case UserKeyPress.Left: + if (PromptShopText is not null) + { + break; + } + if (selection is 0) + { + category = Math.Max(0, category - 1); + itemsInCategory = Shop.Inventory.Where(row => row.Item.Category == categories[category]).ToArray(); + } + break; + case UserKeyPress.Right: + if (PromptShopText is not null) + { + break; + } + if (selection is 0) + { + category = Math.Min(categories.Length - 1, category + 1); + itemsInCategory = Shop.Inventory.Where(row => row.Item.Category == categories[category]).ToArray(); + } + break; + case UserKeyPress.Up: + if (PromptShopText is not null) + { + break; + } + selection = Math.Max(0, selection - 1); + break; + case UserKeyPress.Down: + if (PromptShopText is not null) + { + break; + } + selection = Math.Min(itemsInCategory.Length, selection + 1); + break; + case UserKeyPress.Confirm: + if (PromptShopText is not null) + { + PromptShopText = null; + break; + } + if (selection > 0) + { + if (itemsInCategory[selection - 1].Quantity <= 0) + { + PromptShopText = new[] + { + "Item is out of stock." + }; + break; + } + if (itemsInCategory[selection - 1].Price > player.Money) + { + PromptShopText = new[] + { + "Not enough money." + }; + break; + } + player.Money -= itemsInCategory[selection - 1].Price; + PlayerInventory.TryAdd(itemsInCategory[selection - 1].Item); + itemsInCategory[selection - 1].Quantity--; + PromptShopText = new[] + { + $"You purchased a {itemsInCategory[selection - 1].Item.Name}", + }; + break; + } + break; + case UserKeyPress.Escape: + if (PromptShopText is not null) + { + PromptShopText = null; + break; + } + Shop = null; + ShopText = null; + break; + } + } + } + } + + public static void SleepAfterRender() + { + // frame rate control targeting 30 frames per second + DateTime now = DateTime.Now; + TimeSpan sleep = TimeSpan.FromMilliseconds(33) - (now - PrevioiusRender); + if (sleep > TimeSpan.Zero) + { + Thread.Sleep(sleep); + } + PrevioiusRender = DateTime.Now; + } +} diff --git a/Projects/Console Monsters/Screens/Menus/StartScreen.cs b/Projects/Console Monsters/Screens/Menus/StartScreen.cs index 8703bc84..5c343813 100644 --- a/Projects/Console Monsters/Screens/Menus/StartScreen.cs +++ b/Projects/Console Monsters/Screens/Menus/StartScreen.cs @@ -97,7 +97,7 @@ public static void Show() if (FirstTimeLaunching) { Map = new PaletTown(); - Map.SpawnCharacterOn('X'); + Map.SpawnPlayerOn('X'); } FirstTimeLaunching = false; return; diff --git a/Projects/Console Monsters/Shops/MonsterCenterShop.cs b/Projects/Console Monsters/Shops/MonsterCenterShop.cs new file mode 100644 index 00000000..5c203eda --- /dev/null +++ b/Projects/Console Monsters/Shops/MonsterCenterShop.cs @@ -0,0 +1,20 @@ +namespace Console_Monsters.Shops; + +internal class MonsterCenterShop : ShopBase +{ + public override string Name => "Monster Center Shop"; + + private List InstanceInventory = new() + { + new(HealthPotionSmall.Instance, 25, 1), + new(HealthPotionMedium.Instance, 50, 1), + new(HealthPotionLarge.Instance, 75, 1), + new(MonsterBox.Instance, 50, 1), + }; + + public override List Inventory => InstanceInventory; + + public override CharacterBase? Character => Scientist.Instance; + + public static readonly MonsterCenterShop Instance = new(); +} diff --git a/Projects/Console Monsters/Shops/TomsShop.cs b/Projects/Console Monsters/Shops/TomsShop.cs new file mode 100644 index 00000000..36e33c52 --- /dev/null +++ b/Projects/Console Monsters/Shops/TomsShop.cs @@ -0,0 +1,19 @@ +namespace Console_Monsters.Shops; + +internal class TomsShop : ShopBase +{ + public override string Name => "Tom's Shop"; + + private List InstanceInventory = new() + { + new(Mushroom.Instance, 25, 3), + new(Leaf.Instance, 50, 1), + new(Candle.Instance, 20, 20), + }; + + public override List Inventory => InstanceInventory; + + public override CharacterBase? Character => OldMan.Instance; + + public static readonly TomsShop Instance = new(); +} diff --git a/Projects/Console Monsters/Sprites.cs b/Projects/Console Monsters/Sprites.cs index b73385ac..9bc4fabe 100644 --- a/Projects/Console Monsters/Sprites.cs +++ b/Projects/Console Monsters/Sprites.cs @@ -233,6 +233,26 @@ public static class Sprites #endregion #region Objects + + public const string BeachUbrella = + @"╭──┴──╮" + "\n" + + @"╯╯╯╷╰╰╰" + "\n" + + @" │ " + "\n" + + @" │ " + "\n" + + @" │ "; + public const string BeachChair = + @" " + "\n" + + @"_ " + "\n" + + @"╲╲ " + "\n" + + @" ╲╲____" + "\n" + + @" ╱‾\/‾╲"; + public static readonly string[,] BeachChairAndUbrella1x2 = Split( + //------1------2 + @"╭───┴───╮ ", // + @"╯╯╯╯╷╰╰╰╰ ", // + @" │ ╲╲ ", // + @" │ └╲╲_____", // + @" │ /‾\‾/‾\");//1 public const string SignALeft = @" ┬──┬─┐" + "\n" + @"╭┴──┴╮│" + "\n" + @@ -456,6 +476,12 @@ public static class Sprites @"│ " + "\n" + @"│ " + "\n" + @"│ "; + public const string Gate = + @"▀▄▀▄▀▄▀" + "\n" + + @"▀▄▀▄▀▄▀" + "\n" + + @"▀▄▀▄▀▄▀" + "\n" + + @"▀▄▀▄▀▄▀" + "\n" + + @"▀▄▀▄▀▄▀"; public readonly static string[,] DiningSet1x4 = Split( //------1------2------3------4 @" ", // @@ -584,18 +610,7 @@ public static class Sprites #endregion #region Nature - public const string Water = - @"~~~~~~~" + "\n" + - @"~~~~~~~" + "\n" + - @"~~~~~~~" + "\n" + - @"~~~~~~~" + "\n" + - @"~~~~~~~"; - public const string Gate = - @"▀▄▀▄▀▄▀" + "\n" + - @"▀▄▀▄▀▄▀" + "\n" + - @"▀▄▀▄▀▄▀" + "\n" + - @"▀▄▀▄▀▄▀" + "\n" + - @"▀▄▀▄▀▄▀"; + #region Trees public const string Tree = @" /‾‾‾\ " + "\n" + @"/‾\ /‾\" + "\n" + @@ -608,6 +623,55 @@ public static class Sprites @" || " + "\n" + @" || " + "\n" + @" || "; + public const string PalmTreeA = + @" ^^ ^^ " + "\n" + + @"//∞║∞\\" + "\n" + + @" ║ " + "\n" + + @" ║ " + "\n" + + @" ₀║ ₀ "; + public const string PalmTreeB = + @" MM MM " + "\n" + + @"││∞║∞││" + "\n" + + @" ║ " + "\n" + + @" ║ " + "\n" + + @" ₀║ ₀ "; + public const string PalmTreeC = + @" ╮╮v╭╭ " + "\n" + + @"╯╯∞║∞╰╰" + "\n" + + @" ║ " + "\n" + + @" ║ " + "\n" + + @" ₀║ ₀ "; + public const string PalmTreeD = + @" <<^>> " + "\n" + + @"<<∞║∞>>" + "\n" + + @" ║ " + "\n" + + @" ║ " + "\n" + + @" ₀║ ₀ "; + public const string PalmTreeE = + @" ∆∆∆∆∆ " + "\n" + + @"<<∞║∞>>" + "\n" + + @" ║ " + "\n" + + @" ║ " + "\n" + + @" ₀║ ₀ "; + public const string PalmTreeF = + @" ⱽⱽⱽⱽⱽ " + "\n" + + @"ⱽⱽ∞║∞ⱽⱽ" + "\n" + + @" ║ " + "\n" + + @" ║ " + "\n" + + @" ₀║ ₀ "; + public const string PalmTreeG = + @" ˅˅˅˅˅ " + "\n" + + @"˅˅∞║∞˅˅" + "\n" + + @" ║ " + "\n" + + @" ║ " + "\n" + + @" ₀║ ₀ "; + #endregion + public const string Water = + @"~~~~~~~" + "\n" + + @"~~~~~~~" + "\n" + + @"~~~~~~~" + "\n" + + @"~~~~~~~" + "\n" + + @"~~~~~~~"; public const string GrassDec = @" . . " + "\n" + @". . . " + "\n" + @@ -774,8 +838,8 @@ public static class Sprites @"├───┤ " + '\n' + @"│_|_│ "; public static readonly string NPC16 = - @" ╭───○ " + '\n' + - @"╰╯^_^╰╯" + '\n' + + @" ╭╭─╮╮ " + '\n' + + @"╯╯^_^╰╰" + '\n' + @"╭┴───┴╮" + '\n' + @"│├───┤│" + '\n' + @" │_|_│ "; @@ -785,6 +849,12 @@ public static class Sprites @"│L_(L_ " + '\n' + @"╭─╮┐╷╷╮" + '\n' + @"╰─╯└┘┘╯"; + public static readonly string NPC18 = + @" ╭───○ " + '\n' + + @"╰╯^_^╰╯" + '\n' + + @"╭┴───┴╮" + '\n' + + @"┘╰┬┴┬╯└" + '\n' + + @" ╱___╲ "; public static readonly string TrainConductorLeft = @" ____ " + '\n' + @" ═│══│ " + '\n' + diff --git a/Projects/Console Monsters/Statics.cs b/Projects/Console Monsters/Statics.cs index 0745d45f..e81ec0a6 100644 --- a/Projects/Console Monsters/Statics.cs +++ b/Projects/Console Monsters/Statics.cs @@ -8,18 +8,20 @@ public static class Statics public static bool DisableBattle { get; set; } = false; public static bool DisableBattleTransition { get; set; } = false; public static bool FirstTimeLaunching { get; set; } = true; - public static bool AudioEnabled { get; set; } = true; + public static bool AudioEnabled { get; set; } = false; + public static bool FastText { get; set; } = false; #endregion - public readonly static Random BattleTransitionRandom = new(); - public readonly static Random GameRandom = new(7); - public readonly static Random BattleRandom = new(7); - public readonly static Player character = new(); - public readonly static List ownedMonsters = new(); - public readonly static List partyMonsters = new(); - public readonly static Dictionary keyMappings = new(); - public readonly static Dictionary reverseKeyMappings = new(); + public static readonly Random BattleTransitionRandom = new(); + public static readonly Random GameRandom = new(7); + public static readonly Random BattleRandom = new(); + public static readonly Player player = new(); + public static readonly List ownedMonsters = new(); + public static readonly List partyMonsters = new(); + public static readonly List trainerMonsters = new(); + public static readonly Dictionary keyMappings = new(); + public static readonly Dictionary reverseKeyMappings = new(); private static MapBase map = null!; @@ -45,6 +47,8 @@ public static MapBase Map public static bool StartMenu { get; set; } = true; public static bool InInventory { get; set; } = false; + public static ShopBase? Shop { get; set; } = null; + public static string[] DefaultMaptext => new[] { $" [{reverseKeyMappings[UserKeyPress.Up].ToDisplayString()}]: Up" + @@ -73,6 +77,11 @@ public static MapBase Map $" [{reverseKeyMappings[UserKeyPress.Escape].ToDisplayString()}]: Menu", }; + public static readonly string[] ShopTextPressEnter = new string[] + { + "[Escape]: Exit Shop, [Enter]: Buy Item", + }; + public static string[] MapText { get @@ -81,9 +90,17 @@ public static string[] MapText { return MapTextPressEnter; } - if (character.IsIdle) + if (ShopText is not null) + { + return ShopTextPressEnter; + } + if (PromptShopText is not null) { - var interactTile = character.InteractTile; + return ShopTextPressEnter; + } + if (player.IsIdle) + { + var interactTile = player.InteractTile; if (Map.CanInteractWithMapTile(interactTile.I, interactTile.J)) { return DefaultMaptextWithInteract; @@ -96,20 +113,24 @@ public static string[] MapText public static string[] BattleText => new[] { $"Battles are still in development.", - $"Let's just pretend you won this battle. :D", - $"[{reverseKeyMappings[UserKeyPress.Confirm].ToDisplayString()}]: exit battle" }; public static string[]? PromptText { get; set; } = null; + public static string[]? PromptBattleText { get; set; } = null; + public static string[]? ShopText { get; set; } = null; + public static string[]? PromptShopText { get; set; } = null; + + public static int ItemDescriptionScrollFrame { get; set; } = 0; public static int SelectedPlayerInventoryItem { get; set; } = 0; public static readonly Towel.DataStructures.IBag PlayerInventory = Towel.DataStructures.BagMap.New(); static Statics() { - character = new() + player = new() { Animation = Player.IdleDown, + Money = 100, }; PlayerInventory.TryAdd(ExperienceBerries.Instance); PlayerInventory.TryAdd(HealthPotionLarge.Instance); @@ -122,7 +143,9 @@ static Statics() PlayerInventory.TryAdd(Candle.Instance); DefaultKeyMappings(); partyMonsters.Clear(); - partyMonsters.Add(new Turtle()); + partyMonsters.Add(new Turtle() { Level = 5 }); + partyMonsters.Add(new FireLizard() { Level = 5 }); + partyMonsters.Add(new ToadBud() { Level = 5 }); } [System.Diagnostics.DebuggerHidden] @@ -131,6 +154,31 @@ static Statics() [System.Diagnostics.DebuggerHidden] public static (int, int) Modulus((int, int) a, (int?, int?) b) => (b.Item1 is null ? a.Item1 : a.Item1 % b.Item1.Value, b.Item2 is null ? a.Item2 : a.Item2 % b.Item2.Value); + public static MonsterBase GetFirstAvailableMonster() + { + for(int i = 0; i < partyMonsters.Count; i++) + { + if(partyMonsters[i].CurrentHP > 0) + { + return partyMonsters[i]; + } + } + return new _ErrorMonster(); //TEMP: returns the error monster in case all party monsters are dead + } + + public static bool IsAnyAvailableMonster() + { + for (int i = 0; i < partyMonsters.Count; i++) + { + if (partyMonsters[i].CurrentHP > 0) + { + return true; + } + } + + return false; + } + public static void DefaultKeyMappings() { reverseKeyMappings.Clear(); diff --git a/Projects/Console Monsters/Utilities/AsciiGenerator.cs b/Projects/Console Monsters/Utilities/AsciiGenerator.cs index cda8fdb0..22685ef5 100644 --- a/Projects/Console Monsters/Utilities/AsciiGenerator.cs +++ b/Projects/Console Monsters/Utilities/AsciiGenerator.cs @@ -28,50 +28,54 @@ public static string[] ToAscii(string @string) return new[] { a.ToString(), b.ToString(), c.ToString() }; } - /// Generates medium sized uppercase ascii text art from a char. + /// + /// Generates medium sized uppercase ascii text art from a char. + /// + /// All characters must be 5 in length and 3 in height, priotizing space on right, centering any single liners + /// An array of strings forming an ASCII character public static string[] ToAscii(char @char) => char.ToLower(@char) switch { ' ' => new[] { - " ", - " ", - " " + " ", + " ", + " " }, 'a' => new[] { - " ▄▄ ", - "█▄▄█", - "█ █" + " ▄▄ ", + "█▄▄█ ", + "█ █ " }, 'b' => new[] { - "▄▄▄ ", - "█▄▄█", - "█▄▄█" + "▄▄▄ ", + "█▄▄█ ", + "█▄▄█ " }, 'c' => new[] { - " ▄▄▄", - "█ ", - "▀▄▄▄" + " ▄▄▄ ", + "█ ", + "▀▄▄▄ " }, 'd' => new[] { - "▄▄▄ ", - "█ █", - "█▄▄▀" + "▄▄▄ ", + "█ █ ", + "█▄▄▀ " }, 'e' => new[] { - "▄▄▄▄", - "█▄▄ ", - "█▄▄▄" + "▄▄▄▄ ", + "█▄▄ ", + "█▄▄▄ " }, 'f' => new[] { - "▄▄▄▄", - "█▄▄ ", - "█ " + "▄▄▄▄ ", + "█▄▄ ", + "█ " }, 'g' => new[] { @@ -81,33 +85,33 @@ public static string[] ToAscii(string @string) }, 'h' => new[] { - "▄ ▄", - "█▄▄█", - "█ █" + "▄ ▄", + "█▄▄▄█", + "█ █" }, 'i' => new[] { - "▄", - "█", - "█" + " ▄ ", + " █ ", + " █ " }, 'j' => new[] { - " ▄", - " █", - "▀▄▄▀" + " ▄ ", + " █ ", + "▀▄▄▀ " }, 'k' => new[] { - "▄ ▄", - "█▄▀ ", - "█ ▀▄" + "▄ ▄ ", + "█▄▀ ", + "█ ▀▄ " }, 'l' => new[] { - "▄ ", - "█ ", - "█▄▄" + " ▄ ", + " █ ", + " █▄▄ " }, 'm' => new[] { @@ -129,27 +133,27 @@ public static string[] ToAscii(string @string) }, 'p' => new[] { - "▄▄▄ ", - "█▄▄▀", - "█ " + "▄▄▄ ", + "█▄▄▀ ", + "█ " }, 'q' => new[] { - " ▄▄▄ ", - "█ █ ", - "▀▄▄▄▀▄" + " ▄▄ ", + "█ █ ", + "▀▄▄▀▄" }, 'r' => new[] { - "▄▄▄ ", - "█▄▄▀", - "█ █" + "▄▄▄ ", + "█▄▄▀ ", + "█ █ " }, 's' => new[] { - "▄▄▄▄", - "█▄▄▄", - "▄▄▄█" + "▄▄▄▄ ", + "█▄▄▄ ", + "▄▄▄█ " }, 't' => new[] { @@ -189,9 +193,81 @@ public static string[] ToAscii(string @string) }, 'z' => new[] { - "▄▄▄▄", - " ▄▄▀", - "█▄▄▄" + "▄▄▄▄ ", + " ▄▄▀ ", + "█▄▄▄ " + }, + '0' => new[] + { + " ▄▄▄ ", + "█▄▀ █", + "▀▄▄▄▀" + }, + '1' => new[] + { + " ▄▄ ", + " █ ", + " ▄█▄ " + }, + '2' => new[] + { + "▄▄▄▄ ", + "▄▄▄▀ ", + "█▄▄▄ " + }, + '3' => new[] + { + "▄▄▄ ", + " ▄▄█ ", + "▄▄▄▀ " + }, + '4' => new[] + { + "▄ ▄ ", + "█▄▄█▄", + " █ " + }, + '5' => new[] + { + "▄▄▄▄ ", + "█▄▄▄ ", + "▄▄▄▀ " + }, + '6' => new[] + { + "▄▄▄▄ ", + "█▄▄▄ ", + "█▄▄█ " + }, + '7' => new[] + { + "▄▄▄▄ ", + " ▄▀ ", + " █ " + }, + '8' => new[] + { + "▄▄▄▄ ", + "█▄▄█ ", + "█▄▄█ " + }, + '9' => new[] + { + "▄▄▄▄ ", + "█▄▄█ ", + " █ " + }, + ':' => new[] + { + " ▄ ", + " ", + " ▀ " + }, + '\'' => new[] + { + " █ ", + " ", + " " }, // ← ↑ → ↓ @@ -219,13 +295,6 @@ public static string[] ToAscii(string @string) "■■■█■", " ▀ " }, - ':' => new[] - { - "▄", - " ", - "▀" - }, - // the '■' and '□' sprites must be the same size '■' => new[] { diff --git a/Projects/Console Monsters/_using.cs b/Projects/Console Monsters/_using.cs index b844b350..e6f9bc25 100644 --- a/Projects/Console Monsters/_using.cs +++ b/Projects/Console Monsters/_using.cs @@ -11,7 +11,10 @@ global using Console_Monsters.Characters; global using Console_Monsters.Screens; global using Console_Monsters.Screens.Menus; +global using Console_Monsters.Shops; global using Console_Monsters.Enums; +global using Console_Monsters.Quests; +global using Console_Monsters.PCGames; global using Console_Monsters.Utilities; global using System.Collections.Generic; global using Towel;