I'm back with a hopefully revised and improved version of my RPG pokemon console game! Well, it's more like a "randomized" pokemon simulation as there isn't really any kind of strategy, it's only about getting lucky lol.
I have added more functionalities and made lots of changes and corrections as suggested, but I'm sure there's a lot more room for improvement so here I am.
Could anyone please take a look and let me know what they think? I won't leave this project alone until it is (near) perfect. Warning: It's LONG. (sorry)
Full code on pastebin: https://pastebin.com/iDZDCgZD
ConsoleUI.Progam.cs
using System;
using System.Collections.Generic;
using System.Linq;
using GameLogic;
namespace ConsoleUI
{
public static class Program
{
private static readonly Dictionary<string, string> Choices =
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{"CatchWildPokemon", "1"},
{"TrainPokemon", "2"},
{"FightRival", "3"},
{"Exit", "4"}
};
private static readonly Dictionary<string, string> YesOrNo =
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{"Yes", "Y"},
{"No", "N"}
};
private static readonly string Y = YesOrNo["Yes"];
private static readonly string N = YesOrNo["No"];
private static readonly string CatchWildPokemon = Choices["CatchWildPokemon"];
private static readonly string TrainPokemon = Choices["TrainPokemon"];
private static readonly string FightRival = Choices["FightRival"];
private static readonly string Exit = Choices["Exit"];
private static readonly IPokemonGenerator PokemonGenerator = new PokemonGenerator();
private static readonly PokemonLevelSystem LevelSystem = new PokemonLevelSystem();
private static readonly IPokemonWorld PokemonWorld = new PokemonWorld();
private static readonly IGameState GameState = new GameState();
private static IRandomPokemonPicker _pokemonPicker;
private static IPlayersCollection _playersCollection;
private static IRivalsCollection _rivalsCollection;
private static readonly ICollection<Pokemon> GymTeam = new List<Pokemon>();
private static readonly ICollection<Pokemon> FightingTeam = new List<Pokemon>();
private static readonly IList<Pokemon> RivalsTeam = new List<Pokemon>();
private static bool _isGameOn;
private static bool _trainPokemon;
private static bool _fightRival;
private static int _wins;
private static int _ties;
private static int _losses;
private static void Main()
{
PokemonWorld.Populate(PokemonGenerator, PokemonGenerator.Generate().Count());
_pokemonPicker = new RandomPokemonPicker(PokemonWorld);
_playersCollection = new PlayersCollection(_pokemonPicker, PokemonWorld);
_rivalsCollection = new RivalsCollection(PokemonWorld);
GameState.LoadGame(_playersCollection, _pokemonPicker);
_isGameOn = true;
Menu();
}
// *** MENU ***
private static void DisplayMenu()
{
Console.WriteLine("\nWhat do you want to do?\n");
Console.WriteLine($"{CatchWildPokemon}. Catch wild pokémon");
Console.WriteLine($"{TrainPokemon}. Train your pokémon in gym");
Console.WriteLine($"{FightRival}. Fight rival [Min level: {_rivalsCollection.MinLevel}]");
Console.WriteLine($"{Exit}. Exit");
Console.WriteLine("");
}
public static void Menu()
{
while (_isGameOn)
{
DisplayMenu();
var choice = Console.ReadLine();
while (Choices.All(n => n.Value != choice))
{
Console.WriteLine(
$"\nPlease type '{CatchWildPokemon}', '{TrainPokemon}' or '{FightRival}', or exit typing '{Exit}'.\n");
choice = Console.ReadLine();
}
if (choice == Exit)
{
GameState.SaveGame(_playersCollection.GetCollection(), _pokemonPicker.GetCurrentPopulation());
_isGameOn = false;
break;
}
PlayerChoice(choice);
}
Console.WriteLine("");
}
private static void PlayerChoice(string choice)
{
if (choice == CatchWildPokemon)
{
if (AreRequirementsMetToCatchPokemon())
ChoiceCatchWildPokemon();
}
else if (choice == TrainPokemon)
{
if (AreRequirementsMetToTrainPokemon())
ChoiceTrainPokemon();
}
else if (choice == FightRival)
{
if (AreRequirementsMetToFightRival())
ChoiceFightRival();
}
else
{
throw new Exception("Unexpected error occurred. Player's choice is invalid.");
}
}
// *** CHECK REQUIREMENTS FOR EACH CHOICE ***
private static bool AreRequirementsMetToCatchPokemon()
{
if (!_playersCollection.IsCompleted) return true;
Console.WriteLine("\nYou've caught all wild pokémon!");
return false;
}
private static bool AreRequirementsMetToTrainPokemon()
{
if (_playersCollection.IsEmpty)
{
Console.WriteLine("\nYou haven't caught any pokémon yet!");
return false;
}
if (_playersCollection.GetCollection().Any(p => p.Level < LevelSystem.MaxLevel)) return true;
Console.WriteLine("\nAll your pokémon have reached max level!");
return false;
}
private static bool AreRequirementsMetToFightRival()
{
if (_playersCollection.IsEmpty)
{
Console.WriteLine("\nYou haven't caught any pokémon yet!");
return false;
}
if (_playersCollection.GetCollection().Any(p => p.Level >= _rivalsCollection.MinLevel)) return true;
Console.WriteLine("\nAt least one of your pokémon must meet this rival's minimum level requirement.");
Console.WriteLine("Try leveling up some pokémon at the gym first!");
return false;
}
// *** CATCH WILD POKEMON ***
private static void CatchWildPokemonTextIntro()
{
Console.WriteLine("\nTime to catch some pokémon!");
Console.WriteLine("Let's explore this area.");
}
private static void ChoiceCatchWildPokemon()
{
CatchWildPokemonTextIntro();
Console.ReadKey();
while (true)
{
var wildPokemon = _playersCollection.GetRandomWildPokemon();
Console.WriteLine($"\nYou find a wild pokémon. It's a {wildPokemon.Name}. Let's catch it!");
Console.ReadKey();
Console.WriteLine($"\nFighting {wildPokemon.Name}...");
Console.ReadKey();
if (IsCatchSuccessful())
{
_playersCollection.AddPokemonToCollection(wildPokemon);
_pokemonPicker.RemoveFromCurrentPopulation();
Console.WriteLine($"\nAwesome! You caught {PokemonInfo(wildPokemon)}");
}
else
{
Console.WriteLine($"\nOh no! {wildPokemon.Name} escaped!");
}
if (_playersCollection.GetCollection().Count > 0)
Console.WriteLine($"\nPokémon in your collection:\n\n{DisplayOwnedPokemon()}");
if (!Confirm("\nDo you want to keep catching pokémons?"))
break;
if (!_playersCollection.IsCompleted) continue;
Console.WriteLine("\nYou've caught all wild pokémon!");
break;
}
}
private static bool IsCatchSuccessful()
{
return new Random().Next(100) >= 50;
}
// *** TRAIN POKEMON ***
private static void TrainPokemonTextIntro()
{
Console.WriteLine("\nTime to head to pokémon gym!");
Console.WriteLine("Let's level up some pokémon.");
}
private static void ChoiceTrainPokemon()
{
TrainPokemonTextIntro();
_trainPokemon = true;
while (_trainPokemon)
{
Console.WriteLine($"\nPokemon in your collection:\n\n{DisplayOwnedPokemon()}");
if (_playersCollection.GetCollection().Count == 1)
{
if (!GymTeam.Any()) AddSingleDefaultPokemonToTeam(GymTeam);
}
else
{
SetTeam(GymTeam, 6);
}
TrainChosenTeam();
}
GymTeam.Clear();
}
private static void TrainChosenTeam()
{
do
{
TrainedTeamText();
if (TrainAgain())
{
if (GymTeam.Count == 1 && _playersCollection.GetCollection().Count == 1)
break;
continue;
}
_trainPokemon = false;
break;
} while (TrainSameTeam() && _playersCollection.GetCollection().Count > 1);
}
private static void TrainedTeamText()
{
Console.WriteLine("\nTraining...\n");
Console.ReadKey();
foreach (var pokemon in GymTeam)
{
LevelSystem.IncreasePokemonExp(pokemon);
if (LevelSystem.HasPokemonReachedMaxLevel(pokemon))
Console.WriteLine($"{pokemon.Name} has reached max level! ");
else
Console.WriteLine(LevelSystem.HasPokemonLeveledUp(pokemon)
? $"{pokemon.Name} has leveled up!"
: $"{pokemon.Name} has gained experience!");
}
Console.WriteLine($"\n{DisplayTeam(GymTeam)}");
}
private static bool TrainAgain()
{
return Confirm("\nDo you want to train again?");
}
private static bool TrainSameTeam()
{
return Confirm("\nDo you want to train the same pokémon?");
}
// *** FIGHT RIVAL ***
private static void FightRivalTextIntro()
{
Console.WriteLine("\nTime to battle!");
Console.WriteLine("Let's become a Pokémon Master.");
}
private static void ChoiceFightRival()
{
FightRivalTextIntro();
_fightRival = true;
while (_fightRival)
{
Console.WriteLine($"\nPokémon in your collection:\n\n{DisplayOwnedPokemon()}");
if (_playersCollection.GetCollection().Count == 1)
{
if (!FightingTeam.Any())
AddSingleDefaultPokemonToTeam(FightingTeam);
}
else
{
SetTeam(FightingTeam, 4);
}
FightRivalWithChosenTeam();
}
ResetFightRivalVariables();
_fightRival = false;
}
private static void AssignOpponents()
{
foreach (var pokemon in _rivalsCollection.GetTeam())
RivalsTeam.Add(pokemon);
var random = new Random();
foreach (var pokemon in FightingTeam)
{
var opponentId = random.Next(RivalsTeam.Count);
pokemon.Opponent = RivalsTeam[opponentId];
RivalsTeam.RemoveAt(opponentId);
}
}
private static void SetTeamChanceAgainstTheirOpponents()
{
if (FightingTeam == null)
throw new NullReferenceException("Unexpected error occurred. Fighting team is null.");
var chanceByType = new SuccessChanceByPokemonTypes();
foreach (var pokemon in FightingTeam)
pokemon.SuccessChance = chanceByType.GetChance(pokemon.Type, pokemon.Opponent.Type);
}
private static void FightRivalWithChosenTeam()
{
do
{
AssignOpponents();
SetTeamChanceAgainstTheirOpponents();
BattleStartText();
BattleResults();
if (FightRivalAgain())
{
if (FightingTeam.Count == 1 && _playersCollection.GetCollection().Count == 1)
{
ResetFightRivalVariables(true);
break;
}
if (FightingTeam.Count == 1 && !ArePokemonWithValidLevelLeftInCollection())
{
ResetFightRivalVariables(true);
break;
}
if (FightRivalWithSameTeam())
{
ResetFightRivalVariables(true);
}
else
{
ResetFightRivalVariables();
break;
}
}
else
{
_fightRival = false;
break;
}
} while (true);
}
private static bool ArePokemonWithValidLevelLeftInCollection()
{
var pokemonLeftInCollection = _playersCollection.GetCollection().Select(p => p)
.Except(FightingTeam.Select(p => p));
return pokemonLeftInCollection.Any(p => p.Level >= _rivalsCollection.MinLevel);
}
private static void BattleStartText()
{
Console.WriteLine("\nLet's battle!");
Console.ReadKey();
if (FightingTeam == null)
throw new NullReferenceException("Unexpected error occurred. Fighting team is null.");
foreach (var pokemon in FightingTeam)
{
Console.WriteLine($"\n{pokemon.Name} was matched against {pokemon.Opponent.Name}.");
Console.WriteLine($"{pokemon.Name} is type {GetFormattedTypes(pokemon)}, " +
$"while {pokemon.Opponent.Name} is type {GetFormattedTypes(pokemon.Opponent)}.");
Console.ReadKey();
DisplaySuccessChanceMessage(pokemon, pokemon.SuccessChance);
Console.ReadKey();
}
}
private static void DisplaySuccessChanceMessage(Pokemon pokemon, int chance)
{
switch (chance)
{
case 50:
Console.WriteLine($"{pokemon.Name} will do average damage to {pokemon.Opponent.Name}.");
Console.WriteLine("It's a 50/50 match!");
break;
case -1:
Console.WriteLine(
$"{pokemon.Name} and {pokemon.Opponent.Name} cannot do any damage to each other.");
Console.WriteLine("It's a tie!");
break;
case 0:
Console.WriteLine($"{pokemon.Name} cannot do any damage to {pokemon.Opponent.Name}.");
Console.WriteLine($"{pokemon.Name} loses!");
break;
case 20:
Console.WriteLine($"{pokemon.Name} is weak against {pokemon.Opponent.Name}.");
Console.WriteLine($"{pokemon.Name} has a small chance of winning.");
break;
case 80:
Console.WriteLine($"{pokemon.Name} is super effective against {pokemon.Opponent.Name}.");
Console.WriteLine($"{pokemon.Name} has a big chance of winning.");
break;
default:
throw new Exception("Unexpected error occurred. Pokémon's success chance is an invalid integer.");
}
}
private static void BattleResults()
{
if (IsMatchAutomaticallyOver())
{
DisplayAutomaticMatchResultMessage();
}
else
{
OngoingBattles();
DisplayMatchResults();
DisplayMatchResultMessage();
}
}
// Automatic match result
private static bool IsMatchAutomaticallyATie()
{
return FightingTeam.All(p => p.SuccessChance == -1);
}
private static bool IsMatchAutomaticallyALoss()
{
return FightingTeam.All(p => p.SuccessChance == 0);
}
private static bool IsMatchAutomaticallyOver()
{
return IsMatchAutomaticallyATie() || IsMatchAutomaticallyALoss();
}
private static void DisplayAutomaticMatchResultMessage()
{
if (IsMatchAutomaticallyATie())
Console.WriteLine("\nYour match against Rival ended in a tie.");
else if (IsMatchAutomaticallyALoss())
Console.WriteLine("\nYou lost the match against Rival.");
}
// Random battles result
private static void OngoingBattles()
{
Console.WriteLine("\nFighting...\n");
foreach (var pokemon in FightingTeam)
if (IsDraw(pokemon))
{
_ties++;
}
else if (IsWin(pokemon))
{
Console.WriteLine($"Cool! {pokemon.Name} won!");
_wins++;
}
else
{
Console.WriteLine($"Oh no! {pokemon.Name} lost!");
_losses++;
}
}
private static bool IsDraw(Pokemon pokemon)
{
if (pokemon == null) throw new NullReferenceException("Unexpected error occurred. Pokémon is null.");
return pokemon.SuccessChance == -1;
}
private static bool IsWin(Pokemon pokemon)
{
if (pokemon == null) throw new NullReferenceException("Unexpected error occurred. Pokémon is null.");
var random = new Random();
return random.Next(100) < pokemon.SuccessChance;
}
// Match result
private static void DisplayMatchResults()
{
if (_wins <= 0 && _losses <= 0 && _ties <= 0)
throw new Exception("Unexpected error occurred. Invalid battle results.");
Console.WriteLine($"\nWins: {_wins}");
Console.WriteLine($"Losses: {_losses}");
if (_ties > 0)
Console.WriteLine($"Ties: {_ties}");
}
private static void DisplayMatchResultMessage()
{
Console.WriteLine(_wins == FightingTeam.Count
? "\nCongrats! You won the match against Rival. "
: "\nYou did not win the match against Rival.");
}
private static bool FightRivalAgain()
{
return Confirm("\nDo you want to fight this rival again?");
}
private static bool FightRivalWithSameTeam()
{
return Confirm("\nDo you want to fight with the same pokémon?");
}
private static void ResetFightRivalVariables(bool sameTeam = false)
{
if (!sameTeam)
FightingTeam.Clear();
foreach (var pokemon in FightingTeam)
{
pokemon.SuccessChance = 50;
pokemon.Opponent = null;
}
RivalsTeam.Clear();
_wins = 0;
_losses = 0;
_ties = 0;
}
// **** HELPER METHODS ****
private static bool Confirm(string prompt)
{
do
{
Console.WriteLine($"{prompt} ({Y}/{N})");
var input = Console.ReadLine();
if (string.Equals(input, Y, StringComparison.InvariantCultureIgnoreCase))
return true;
if (string.Equals(input, N, StringComparison.InvariantCultureIgnoreCase))
return false;
} while (true);
}
private static string PokemonInfo(Pokemon pokemon)
{
return pokemon != null
? $"{pokemon.Name} => " +
$"Type: {GetFormattedTypes(pokemon)} | " +
$"Level: {pokemon.Level} | " +
$"Exp: {pokemon.Exp}"
: "Unexpected error occurred. Pokémon is null.";
}
private static string GetFormattedTypes(Pokemon pokemon)
{
return string.Join(", ", pokemon.Type.Select(t => t.Name));
}
private static string DisplayOwnedPokemon()
{
return string.Join("\n", _playersCollection.GetCollection().Select(PokemonInfo).ToList());
}
private static string DisplayTeam(IEnumerable<Pokemon> team)
{
return string.Join("\n", team.Select(PokemonInfo).ToList());
}
private static void AddSingleDefaultPokemonToTeam(ICollection<Pokemon> team)
{
team.Add(_playersCollection.GetCollection().First());
}
private static void SetTeam(ICollection<Pokemon> team, int max)
{
var isValidPokemon = false;
do
{
if (team.Count == max || team.Count == _playersCollection.GetCollection().Count)
break;
if (_fightRival)
if (!ArePokemonWithValidLevelLeftInCollection())
break;
if (team.Count > 0 && isValidPokemon)
{
Console.WriteLine($"\nCurrent team:\n\n{DisplayTeam(team)}");
if (_fightRival)
if (!ArePokemonWithValidLevelLeftInCollection())
break;
if (!AddAnotherPokemonToTeam())
break;
}
do
{
var chosenPokemon = ChosenPokemon(max);
isValidPokemon = IsChosenPokemonValid(chosenPokemon, team);
if (isValidPokemon) AddPokemonToTeam(chosenPokemon, team);
} while (!isValidPokemon);
} while (true);
}
private static string ChosenPokemon(int max)
{
Console.WriteLine(
"\nType the name of a pokémon from your collection that you'd like to add to your team.");
Console.WriteLine($"You must add between 1 and {max} pokémon.\n");
var chosenPokemon = Console.ReadLine();
if (string.IsNullOrWhiteSpace(chosenPokemon)) return "";
chosenPokemon = FormatChosenPokemon(chosenPokemon);
return chosenPokemon;
}
private static string FormatChosenPokemon(string chosenPokemon)
{
chosenPokemon = chosenPokemon.Trim().ToLowerInvariant();
chosenPokemon = chosenPokemon.First().ToString().ToUpperInvariant() + chosenPokemon.Substring(1);
return chosenPokemon;
}
private static bool IsChosenPokemonValid(string chosenPokemon, ICollection<Pokemon> team)
{
if (string.IsNullOrWhiteSpace(chosenPokemon))
return false;
if (_playersCollection.GetCollection().All(p => p.Name != chosenPokemon))
return false;
if (team.All(p => p.Name != chosenPokemon))
{
if (!_fightRival) return true;
var pokemon = _playersCollection.GetCollection().FirstOrDefault(p => p.Name == chosenPokemon);
if (pokemon == null) throw new NullReferenceException("Unexpected error occurred. Pokémon is null.");
var chosenPokemonLvl = pokemon.Level;
if (chosenPokemonLvl >= _rivalsCollection.MinLevel)
return true;
Console.WriteLine("\nThis pokémon's level is below Rival's level requirement.");
return false;
}
Console.WriteLine($"\nYou already added {chosenPokemon}.");
return false;
}
private static void AddPokemonToTeam(string chosenPokemon, ICollection<Pokemon> team)
{
if (chosenPokemon == null)
throw new NullReferenceException("Unexpected error occurred. Null pokémon string given.");
var chosenPokemonFromCollection = _playersCollection.GetCollection()
.SingleOrDefault(p => p.Name == chosenPokemon);
if (chosenPokemonFromCollection == null)
throw new NullReferenceException("Unexpected error occurred. There is no such pokémon in World.");
team.Add(chosenPokemonFromCollection);
}
private static bool AddAnotherPokemonToTeam()
{
return Confirm("\nDo you want to add another pokémon?");
}
}
}