diff --git a/.gitignore b/.gitignore index af0005f..85c104a 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,7 @@ hs_err_pid* # Script files *.bat *.sh + +# IDE files +*.iml +.idea diff --git a/java/Game.java b/java/Game.java deleted file mode 100644 index 470425f..0000000 --- a/java/Game.java +++ /dev/null @@ -1,375 +0,0 @@ -import java.util.Scanner; -import java.util.ArrayList; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintWriter; -import java.lang.NumberFormatException; -import java.text.NumberFormat; -import java.util.Locale; -import java.text.ParseException; - -/** Simulates the game Pokémon. */ -public class Game { - public static Scanner in = new Scanner(System.in); - - public static void main(String[] args) { - ArrayList pokemon = readPokemon(); - int initialPokemon = pokemon.size(); - - System.out.println("What is your name?"); - String name = in.nextLine(); - Trainer player = new Trainer(name, randomTeam(), createInventory()); - - boolean done = false; - Pokemon opponentPokemon = null; - Pokemon trainersPokemon = null; - Pokeball currentPokeball = null; - Potion currentPotion = null; - boolean fleeSuccess = false; - Pokemon pokemonToHeal = null; - - opponentPokemon = randomPokemon(pokemon); - System.out.printf("A wild %s appeared.%n", opponentPokemon.getName()); - - while (!done) { - if (opponentPokemon == null) { - System.out.printf("You have brutally murdered %d pokemon.%n" - + "The only ones left are the ones in your posession.%n" - + "There really is nothing more to do here.%n", initialPokemon); - return; - } - if (player.getConsciousPokemon().size() < 1) { - System.out.println("All your pokemon have fainted. Your journey ends here."); - return; - } - while (trainersPokemon == null || !trainersPokemon.isConscious()) { - player.availablePokemon(true); - trainersPokemon = player.choosePokemon(true); - } - System.out.printf("Opponent: %s%nWhat will you do?%n", opponentPokemon); - System.out.printf("b: battle" - + "%nh: heal or revive" - + "%nt: throw pokeball" - + "%nc: change pokemon" - + "%nf: flee" - + "%nv: view my pokemon" - + "%ns: save" - + "%nl: load" - + "%nq: quit%n>"); - char command = in.next().toLowerCase().charAt(0); - switch (command) { - case 'b': - if (opponentPokemon.isConscious() && trainersPokemon.isConscious()) { - trainersPokemon.attack(opponentPokemon); - if (opponentPokemon.isConscious()) { - opponentPokemon.attack(trainersPokemon); - if (!trainersPokemon.isConscious()) { - System.out.println("Your pokemon fainted."); - } - } else { - pokemonFainted(pokemon, opponentPokemon); - System.out.println("The opponent pokemon fainted."); - opponentPokemon = randomPokemon(pokemon); - } - } - break; - case 'h': - if (player.getInventory().getPotions().size() > 0) { - player.getInventory().availablePotions(); - currentPotion = player.getInventory().chosenPotion(); - if (currentPotion == null) { - in.nextLine(); - System.out.println("Invalid potion."); - } else { - if (currentPotion.needsAlive()) { - player.availablePokemon(true); - pokemonToHeal = player.choosePokemon(true); - } else { - player.availablePokemon(false); - pokemonToHeal = player.choosePokemon(false); - } - if (pokemonToHeal == null) { - System.out.println("That is not a valid pokemon"); - } else { - if (currentPotion.use(pokemonToHeal)) { - opponentPokemon.attack(trainersPokemon); - } - } - } - } else { - System.out.println("You have used all your healing items."); - } - break; - case 't': - if (player.getInventory().getPokeballs().size() > 0) { - player.getInventory().availablePokeballs(); - currentPokeball = player.getInventory().chosenPokeball(); - if (currentPokeball == null) { - in.nextLine(); - System.out.println("Invalid pokeball."); - } else { - if (currentPokeball.getType() == Pokeball.Pokeballs.MASTERBALL) { - currentPokeball.use(opponentPokemon, pokemon, player); - opponentPokemon = randomPokemon(pokemon); - System.out.printf("A wild %s appeared.%n", opponentPokemon.getName()); - } else { - boolean captured = currentPokeball.use(opponentPokemon, pokemon, player); - if (captured) { - opponentPokemon = randomPokemon(pokemon); - System.out.printf("A wild %s appeared.%n", opponentPokemon.getName()); - } else { - opponentPokemon.attack(trainersPokemon); - } - } - } - } else { - System.out.println("You have used all your pokeballs."); - } - break; - case 'c': - player.availablePokemon(true); - trainersPokemon = player.choosePokemon(true); - while (trainersPokemon == null) { - player.availablePokemon(true); - trainersPokemon = player.choosePokemon(true); - } - opponentPokemon.attack(trainersPokemon); - break; - case 's': - savePokemon(pokemon, "pokemon.save"); - savePokemon(player.getPokemon(), "user.save"); - saveInventory(player.getInventory(), "inventory.save"); - break; - case 'l': - ArrayList loadedPokemon = loadPokemon("pokemon.save"); - ArrayList loadedUsersPokemon = loadPokemon("user.save"); - Inventory loadedInventory = loadInventory("inventory.save"); - if (loadedPokemon == null || loadedUsersPokemon == null || loadedInventory == null) { - System.out.println("One or more savefiles seem corrupt or missing. Please delete, create or fix the affected file(s)."); - } else { - pokemon = loadedPokemon; - player.setPokemon(loadedUsersPokemon); - player.setInventory(loadedInventory); - if (pokemon.size() > 0 && player.getPokemon().size() > 0) { - do { - player.availablePokemon(true); - trainersPokemon = player.choosePokemon(true); - } while (trainersPokemon == null || !trainersPokemon.isConscious()); - opponentPokemon = randomPokemon(pokemon); - } - } - break; - case 'f': - fleeSuccess = trainersPokemon.flee(opponentPokemon); - if (fleeSuccess) { - System.out.println("You fled the battle."); - opponentPokemon = randomPokemon(pokemon); - System.out.printf("A wild %s appeared.%n", opponentPokemon.getName()); - } else { - System.out.printf("Failed to flee from %s.%n", opponentPokemon.getName()); - opponentPokemon.attack(trainersPokemon); - } - break; - case 'v': - player.printPokemon(); - break; - case 'q': - done = true; - break; - default: - System.out.println("[Invalid command]"); - } - } - } - - /** - * Prevents wild fainted pokemon from ever being encountered again. - * @param pokemonList List of pokemon to search. - * @param target The pokemon to remove. - */ - public static void pokemonFainted(ArrayList pokemonList, Pokemon target) { - for (int i = 0; i < pokemonList.size(); i++) { - if (pokemonList.get(i).equals(target)) { - pokemonList.remove(i); - } - } - } - - /** - * Gives a trainer necessary starting items. - * @return A list of items. - */ - public static Inventory createInventory() { - Inventory inventory = new Inventory(); - inventory.addPokeball("Poke Ball", "A device for catching wild Pokémon. It's thrown like a ball at a Pokémon, comfortably encapsulating its target.", 15); - inventory.addPokeball("Great ball", "A good, high-performance Poké Ball that provides a higher Pokémon catch rate than a standard Poké Ball.", 10); - inventory.addPokeball("Ultra ball", "An ultra-high-performance Poké Ball that provides a higher success rate for catching Pokémon than a Great Ball.", 5); - inventory.addPokeball("Master ball", "The best Poké Ball with the ultimate level of performance. With it, you will catch any wild Pokémon without fail.", 1); - inventory.addPotion("Potion", "Heals a pokemon for 20 HP.", 20, true); - inventory.addPotion("Super Potion", "Heals a pokemon for 50 HP.", 10, true); - inventory.addPotion("Hyper Potion", "Heals a pokemon for 200 HP.", 5, true); - inventory.addPotion("Max Potion", "Fully heals a pokemon.", 1, true); - inventory.addPotion("Revive", "Revives a fainted pokemon.", 2, false); - return inventory; - } - - /** - * Chooses a random pokemon from a list. - * @param pokemon The list to choose from. - * @return A Pokemon object, or null if the list is empty. - */ - public static Pokemon randomPokemon(ArrayList pokemon) { - if (pokemon.size() > 0) { - return pokemon.get((int)(Math.random() * pokemon.size())); - } else { - return null; - } - } - - /** - * Reads pokemon from Pokemon.txt to an ArrayList. - * @return An ArrayList of pokemon objects. - */ - public static ArrayList readPokemon() { - ArrayList pokemon = new ArrayList(); - try (Scanner file = new Scanner(new File("config/Pokemon.txt"))) { - while (file.hasNextLine()) { - pokemon.add(new Pokemon(file.nextLine())); - } - } catch (FileNotFoundException e) { - /** If the file is compiled as jar, this will prevent an empty list. */ - try (Scanner file = new Scanner(Game.class.getResourceAsStream("/config/Pokemon.txt"))) { - while (file.hasNextLine()) { - pokemon.add(new Pokemon(file.nextLine())); - } - } - } - return pokemon; - } - - /** - * Picks a random pokemon from a list. - * @param pokemon A list of pokemon objects. - * @return A pokemon object. - */ - public static Pokemon pick(ArrayList pokemon) { - int index = (int)(Math.random() * (pokemon.size())); - Pokemon randomPokemon = pokemon.get(index); - pokemon.remove(index); - return randomPokemon; - } - - /** - * Saves all pokemon in a list with stats to a text file. - * @param pokemonList List of Pokemon objects to save. - * @param savefile The file to write to. - */ - public static void savePokemon(ArrayList pokemonList, String savefile) { - try (PrintWriter file = new PrintWriter(savefile)) { - for (Pokemon pokemon : pokemonList) { - file.println(pokemon.saveString()); - } - System.out.println("Successfully saved pokemon."); - } catch (FileNotFoundException e) { - System.out.println("The savefile could not be written."); - } - } - - /** - * Saves all items in a list to a text file. - * @param itemList List of Item objects to save. - * @param savefile The file to write to. - */ - public static void saveInventory(Inventory inventory, String savefile) { - try (PrintWriter file = new PrintWriter(savefile)) { - for (Pokeball pokeball : inventory.getPokeballs()) { - file.println(pokeball.saveString()); - } - file.println(":NEXTLIST:"); - for (Potion potion : inventory.getPotions()) { - file.println(potion.saveString()); - } - System.out.println("Successfully saved inventory."); - } catch (FileNotFoundException e) { - System.out.println("The savefile could not be written."); - } - } - - /** - * Loads pokemon from a text file. - * @param savefile The file to write to. - * @return A list of pokemon or null on failiure. - */ - public static ArrayList loadPokemon(String savefile) { - ArrayList pokemon = new ArrayList(); - try (Scanner file = new Scanner(new File(savefile))) { - NumberFormat format = NumberFormat.getInstance(Locale.ENGLISH); - while (file.hasNextLine()) { - String[] data = file.nextLine().split(";"); - try { - pokemon.add(new Pokemon(data[0], Integer.parseInt(data[1]), Integer.parseInt(data[2]), Integer.parseInt(data[3]), format.parse(data[4]).doubleValue(), Integer.parseInt(data[5]), Integer.parseInt(data[6]), Integer.parseInt(data[7]))); - } catch (NumberFormatException e) { - System.out.println("Malformed number " + e); - } catch (ParseException e) { - System.out.println("Malformed number " + e); - } catch (ArrayIndexOutOfBoundsException e) { - System.out.println("Invalid savefile: " + savefile); - return null; - } - } - System.out.println("Successfully loaded pokemon."); - } catch (FileNotFoundException e) { - System.out.println("Missing savefile " + savefile); - return null; - } - return pokemon; - } - - /** - * Loads items from a text file. - * @param savefile The file to write to. - * @return A list of items or null on failiure. - */ - public static Inventory loadInventory(String savefile) { - ArrayList pokeballs = new ArrayList(); - ArrayList potions = new ArrayList(); - try (Scanner file = new Scanner(new File(savefile))) { - String next = ""; - while (file.hasNextLine() && !next.equals(":NEXTLIST:")) { - try { - next = file.nextLine(); - if (!next.equals(":NEXTLIST:")) { - String[] data = next.split(";"); - pokeballs.add(new Pokeball(data[0], data[1], Integer.parseInt(data[2]), Pokeball.Pokeballs.valueOf(data[0].toUpperCase().replace(" ", "")))); - } - } catch (ArrayIndexOutOfBoundsException e) { - System.out.println("Invalid savefile: " + savefile); - return null; - } - } - while (file.hasNextLine()) { - try { - String[] data = file.nextLine().split(";"); - potions.add(new Potion(data[0], data[1], Integer.parseInt(data[2]), Potion.Potions.valueOf(data[0].toUpperCase().replace(" ", "")))); - } catch (ArrayIndexOutOfBoundsException e) { - System.out.println("Invalid savefile: " + savefile); - return null; - } - } - System.out.println("Successfully loaded items."); - } catch (FileNotFoundException e) { - System.out.println("Missing savefile " + savefile); - return null; - } - return new Inventory(pokeballs, potions); - } - - public static ArrayList randomTeam() { - ArrayList temporary = readPokemon(); - ArrayList pokemon = new ArrayList(); - for (int i = 1; i <= 6; i++) { - pokemon.add(pick(temporary)); - } - return pokemon; - } -} diff --git a/java/Inventory.java b/java/Inventory.java deleted file mode 100644 index 940edb0..0000000 --- a/java/Inventory.java +++ /dev/null @@ -1,97 +0,0 @@ -import java.util.ArrayList; -import java.util.Scanner; - -public class Inventory { - public static Scanner in = new Scanner(System.in); - private ArrayList pokeballs; - private ArrayList potions; - - public Inventory() { - this.pokeballs = new ArrayList(); - this.potions = new ArrayList(); - } - - public Inventory(ArrayList pokeballs, ArrayList potions) { - this.pokeballs = pokeballs; - this.potions = potions; - } - - public void addPokeball(String name, String description, int amount) { - Pokeball pokeball = new Pokeball(name, description, amount, Pokeball.Pokeballs.valueOf(name.toUpperCase().replace(" ", ""))); - if (pokeball != null) { - this.pokeballs.add(pokeball); - } - } - - public void addPotion(String name, String description, int amount, boolean alive) { - Potion potion = new Potion(name, description, amount, Potion.Potions.valueOf(name.toUpperCase().replace(" ", "")), alive); - if (potion != null) { - this.potions.add(potion); - } - } - - public ArrayList getPokeballs() { - ArrayList pokeballs = new ArrayList(); - for (Pokeball pokeball : this.pokeballs) { - if (pokeball.getAmount() > 0) { - pokeballs.add(pokeball); - } - } - return pokeballs; - } - - public ArrayList getPotions() { - ArrayList potions = new ArrayList(); - for (Potion potion : this.potions) { - if (potion.getAmount() > 0) { - potions.add(potion); - } - } - return potions; - } - - public void availablePokeballs() { - System.out.println("You may choose from these items:"); - for (int i = 0; i < this.pokeballs.size(); i++) { - System.out.printf("%d: %s%n", i + 1, this.pokeballs.get(i)); - } - System.out.print(">"); - } - - public void availablePotions() { - System.out.println("You may choose from these items:"); - ArrayList potionList = this.getPotions(); - for (int i = 0; i < potionList.size(); i++) { - System.out.printf("%d: %s%n", i + 1, potionList.get(i)); - } - System.out.print(">"); - } - - public Potion chosenPotion() { - ArrayList potions = this.getPotions(); - if (in.hasNextInt()) { - int choice = in.nextInt() - 1; - if (choice >= 0 && choice < potions.size()) { - in.nextLine(); - return potions.get(choice); - } - } else { - in.nextLine(); - } - return null; - } - - public Pokeball chosenPokeball() { - ArrayList pokeballs = this.getPokeballs(); - if (in.hasNextInt()) { - int choice = in.nextInt() - 1; - if (choice >= 0 && choice < pokeballs.size()) { - in.nextLine(); - return pokeballs.get(choice); - } - } else { - in.nextLine(); - } - return null; - } -} diff --git a/java/Pokeball.java b/java/Pokeball.java deleted file mode 100644 index eff4944..0000000 --- a/java/Pokeball.java +++ /dev/null @@ -1,62 +0,0 @@ -import java.util.ArrayList; - -public class Pokeball { - public static enum Pokeballs { POKEBALL, GREATBALL, ULTRABALL, MASTERBALL } - private String name; - private String description; - private Pokeballs type; - private int amount; - - public Pokeball(String name, String description, int amount, Pokeballs type) { - this.type = type; - this.name = name; - this.description = description; - this.amount = amount; - } - - public String toString() { - return String.format("(%d) %s: %s", this.amount, this.name, this.description); - } - - public String saveString() { - return String.format("%s;%s;%d", this.name, this.description, this.amount); - } - - public int getAmount() { - return this.amount; - } - - public String getName() { - return this.name; - } - - public Pokeballs getType() { - return this.type; - } - - /** - * Uses a pokeball on an opponent. - * @param target Which pokemon to target. - * @param current Current list the pokemon belongs to. - * @param catcher Where we send the pokemon on a successfull capture. - * @return True if nothing went wrong. False otherwise. - */ - public boolean use(Pokemon target, ArrayList current, Trainer catcher) { - if (this.amount > 0) { - this.amount--; - switch (this.type) { - case POKEBALL: - return target.tryCapture(current, catcher, 255); - case GREATBALL: - return target.tryCapture(current, catcher, 200); - case ULTRABALL: - return target.tryCapture(current, catcher, 150); - case MASTERBALL: - return target.tryCapture(current, catcher, 0); - } - } else { - System.out.println("No cheating!"); - } - return false; - } -} diff --git a/java/Pokemon.java b/java/Pokemon.java deleted file mode 100644 index 859a029..0000000 --- a/java/Pokemon.java +++ /dev/null @@ -1,203 +0,0 @@ -import java.util.Random; -import java.util.ArrayList; - -public class Pokemon { - private String name; - private int healthPoints; - private int maxHealthPoints; - private int strength; - private double criticalChance; - private Random random; - private int catchRate; - private int exp; - private int level; - private int fleeCount; - - public Pokemon(String name) { - this.random = new Random(); - this.name = name; - this.healthPoints = 30 + random.nextInt(70); - this.maxHealthPoints = this.healthPoints; - this.criticalChance = Math.abs(0.1 * random.nextGaussian()); - this.catchRate = (int)(Math.random() * 256); - this.exp = 0; - this.level = (int)(Math.abs(2 * random.nextGaussian()) + 1); - this.strength = random.nextInt(7) + this.level; - this.fleeCount = 0; - } - - public Pokemon(String name, int healthPoints, int maxHealthPoints, int strength, double criticalChance, int catchRate, int exp, int level) { - this.random = new Random(); - this.name = name; - this.healthPoints = healthPoints; - this.maxHealthPoints = maxHealthPoints; - this.criticalChance = criticalChance; - this.catchRate = catchRate; - this.exp = exp; - this.level = level; - this.strength = strength; - this.fleeCount = 0; - } - - public String toString() { - return String.format("Level %d %s HP: (%d/%d) STR: %d CHC: %.0f%%", this.level, this.name, this.healthPoints, this.maxHealthPoints, this.strength, (this.criticalChance*100)); - } - - /** - * Returns a string containing all the pokemon's data. - */ - public String saveString() { - return String.format("%s;%d;%d;%d;%f;%d;%d;%d", this.name, this.healthPoints, this.maxHealthPoints, this.strength, this.criticalChance, this.catchRate, this.exp, this.level); - } - - public String getName() { - return this.name; - } - - public int getHP() { - return this.healthPoints; - } - - public boolean equals(Pokemon target) { - return target == this; - } - - /** - * Heals a pokemon. - * @param amount How many hitpoints to heal. - * @return The exact amount of hitpoints healed. - */ - public int heal(int amount) { - if (amount < 0) { - amount = this.maxHealthPoints - this.healthPoints; - } else { - amount = Math.min(this.maxHealthPoints - this.healthPoints, amount); - } - this.healthPoints += amount; - return amount; - } - - /** - * Checks if a pokemon has not taken any damage or is fully healed. - * @param return True if health is full. False otherwise. - */ - public boolean isDamaged() { - return this.healthPoints < this.maxHealthPoints; - } - - /** - * Tries to catch a pokemon. - * @param current The list where the pokemon currently belongs. - * @param catcher The list to send the pokemon on successfull capture. - * @return True on successfull capture. False otherwise. - */ - public boolean tryCapture(ArrayList current, Trainer catcher, int range) { - if (range == 0) { - this.capture(current, catcher); - System.out.printf("%s was caught.%n", this.name); - return true; - } - if ((int)(Math.random() * (range + 1)) < Math.max((3 * this.maxHealthPoints - 2 * this.healthPoints) * this.catchRate / (3 * this.maxHealthPoints), 1)) { - this.capture(current, catcher); - System.out.printf("%s was caught.%n", this.name); - return true; - } else { - System.out.printf("%s escaped from the pokeball.%n", this.name); - return false; - } - } - - /** - * Captures a wild pokemon. - * @param current The pokemon list the pokemon belongs to. - * @param catcher The pokemon list of the trainer. - */ - private void capture(ArrayList current, Trainer trainer) { - trainer.addPokemon(this); - for (int i = 0; i < current.size(); i++) { - if (current.get(i) == this) { - current.remove(i); - } - } - } - - /** Restores the health of a fainted pokemon. */ - public void revive() { - this.healthPoints = this.maxHealthPoints; - } - - /** - * Checks if the pokemon has any HP left. - * @return True if any HP is left. False otherwise. - */ - public boolean isConscious() { - return this.healthPoints > 0; - } - - /** - * Damages a pokemon. - * @param How many hitpoints are to be deducted. - */ - public void damage(int damageTaken) { - this.healthPoints = Math.max(this.healthPoints -= damageTaken, 0); - System.out.printf("%s takes %d damage and is left with %d/%d HP%n", this.name, damageTaken, this.healthPoints, this.maxHealthPoints); - } - - /** - * Gives a pokemon exp after each successfull battle. Also handles leveling up. - * @target Which pokemon did we beat. - */ - private void giveEXP(Pokemon target) { - int exp = (100 * target.level)/7; - this.exp += exp; - System.out.printf("%s gained %d exp.%n", this.name, exp); - if (this.exp > (4 * Math.pow(this.level, 3)) / 5) { - this.level++; - this.maxHealthPoints += 5; - this.healthPoints = maxHealthPoints; - this.strength += 1; - System.out.printf("%s is now level %d. Health has been increased and restored. Strength has been increased.%n", this.name, this.level); - } - } - - /** - * Makes a pokemon attack another pokemon. - * @param target The pokemon to take damage. - */ - public void attack(Pokemon target) { - if (this.healthPoints > 0) { - System.out.printf("%s attacks %s.%n", this.getName(), target.getName()); - double critical = 1; - if (Math.random() < this.criticalChance) { - System.out.println("Critical hit!"); - critical = (2 * this.level +5) / (this.level + 5); - } - double randomDouble = 0.85 + (1.0 - 0.85) * random.nextDouble(); - int moveDamage = (int)(Math.random() * 60 + 40); - int damageInflicted = this.level + (int)((((((2 * this.strength) / 5) + 2) * moveDamage * 1.75) / 50 + 2) * critical * randomDouble); - target.damage(damageInflicted); - if (!target.isConscious()) { - System.out.printf("%s is defeated by %s.%n", target.getName(), this.getName()); - this.giveEXP(target); - this.fleeCount = 0; - } - } else { - System.out.println("No cheating!"); - } - } - - /** - * The trainer may flee if the battle is too hard. - * @param target Who are we trying to flee from - * @return True on successfull escape. False otherwise. - */ - public boolean flee(Pokemon target) { - if (random.nextInt(256) < (this.level * 128 / target.level) + (30 * this.fleeCount % 256)) { - this.fleeCount = 0; - return true; - } else { - this.fleeCount++; - return false; - } - } -} diff --git a/java/Potion.java b/java/Potion.java deleted file mode 100644 index f31fcb5..0000000 --- a/java/Potion.java +++ /dev/null @@ -1,106 +0,0 @@ -import java.util.ArrayList; - -public class Potion { - public static enum Potions { POTION, SUPERPOTION, HYPERPOTION, MAXPOTION, REVIVE } - private String name; - private String description; - private Potions type; - private boolean alive; - private int amount; - - public Potion(String name, String description, int amount, Potions type) { - this.type = type; - this.name = name; - this.description = description; - this.alive = true; - this.amount = amount; - } - - public Potion(String name, String description, int amount, Potions type, boolean alive) { - this.type = Potions.valueOf(name.toUpperCase().replace(" ", "")); - this.name = name; - this.description = description; - this.alive = alive; - this.amount = amount; - } - - public String toString() { - return String.format("(%d) %s: %s", this.amount, this.name, this.description); - } - - public String saveString() { - return String.format("%s;%s;%d;%b", this.name, this.description, this.amount, this.alive); - } - - public int getAmount() { - return this.amount; - } - - public String getName() { - return this.name; - } - - /** Checks if an item should be used on alive or fainted pokemon. */ - public boolean needsAlive() { - return alive; - } - - /** - * Spends an item and does something based on the type of item. - * @param target Which pokemon should the item be used on. - * @return True if nothing went wrong. False otherwise. - */ - public boolean use(Pokemon target) { - if (this.amount > 0) { - switch (this.type) { - case POTION: - return potion(target, 20); - case SUPERPOTION: - return potion(target, 50); - case HYPERPOTION: - return potion(target, 200); - case MAXPOTION: - return potion(target, -1); - case REVIVE: - if (!target.isConscious()) { - this.amount--; - target.revive(); - System.out.printf("%s was revived.%n", target.getName()); - return true; - } else { - System.out.println("You can't revive a conscious pokemon."); - return false; - } - default: - System.out.printf("Invalid item %s%n", name); - return false; - } - } else { - System.out.println("No cheating!"); - return false; - } - } - - /** - * Checks if a pokemon is able to, and in need of a potion. If it is, heal it. - * @param target The pokemon to heal. - * @param amount The amount to heal the pokemon. - * @return True if nothing went wrong. False otherwise. - */ - private boolean potion(Pokemon target, int amount) { - if (target.isConscious()) { - if (target.isDamaged()) { - this.amount--; - int healed = target.heal(amount); - System.out.printf("%s was healed for %d HP and now has %d HP.%n", target.getName(), healed, target.getHP()); - return true; - } else { - System.out.printf("%s has not taken damage, and does not require a potion.%n", target.getName()); - return false; - } - } else { - System.out.println("You can't heal a fainted pokemon."); - return false; - } - } -} diff --git a/java/Trainer.java b/java/Trainer.java deleted file mode 100644 index 9fc295f..0000000 --- a/java/Trainer.java +++ /dev/null @@ -1,99 +0,0 @@ -import java.util.ArrayList; -import java.util.Scanner; - -public class Trainer { - public static Scanner in = new Scanner(System.in); - String name; - private ArrayList pokemon; - private Inventory inventory; - - public Trainer(String name, ArrayList pokemon, Inventory inventory) { - this.name = name; - this.pokemon = pokemon; - this.inventory = inventory; - } - - public void setPokemon(ArrayList pokemon) { - this.pokemon = pokemon; - } - - public void setInventory(Inventory inventory) { - this.inventory = inventory; - } - - public ArrayList getPokemon() { - return this.pokemon; - } - - public void addPokemon(Pokemon pokemon) { - this.pokemon.add(pokemon); - } - - public ArrayList getConsciousPokemon() { - ArrayList pokemon = new ArrayList(); - for (Pokemon singlePokemon : this.pokemon) { - if (singlePokemon.isConscious()) { - pokemon.add(singlePokemon); - } - } - return pokemon; - } - - public ArrayList getFaintedPokemon() { - ArrayList pokemon = new ArrayList(); - for (Pokemon singlePokemon : this.pokemon) { - if (!singlePokemon.isConscious()) { - pokemon.add(singlePokemon); - } - } - return pokemon; - } - - public Inventory getInventory() { - return this.inventory; - } - - /** Lists all currently available pokemon for the trainer.*/ - public void availablePokemon(boolean alive) { - ArrayList pokemonList = null; - if (alive) { - pokemonList = this.getConsciousPokemon(); - } else { - pokemonList = this.getFaintedPokemon(); - } - System.out.println("You may choose from these pokemon:"); - for (int i = 0; i < pokemonList.size(); i++) { - System.out.printf("%d: %s%n", i + 1, pokemonList.get(i)); - } - System.out.print(">"); - } - - public void printPokemon() { - for (Pokemon pokemon : this.pokemon) { - System.out.println(pokemon); - } - } - - /** - * Asks the user for the name of a pokemon and returns it. - * @param pokemonList A list of available pokemon - * @return A pokemon object or null. - */ - public Pokemon choosePokemon(boolean alive) { - ArrayList pokemonList = null; - if (alive) { - pokemonList = this.getConsciousPokemon(); - } else { - pokemonList = this.getFaintedPokemon(); - } - if (in.hasNextInt()) { - int choice = in.nextInt() - 1; - if (choice >= 0 && choice < pokemonList.size()) { - in.nextLine(); - return pokemonList.get(choice); - } - } - in.nextLine(); - return null; - } -} diff --git a/manifest.txt b/manifest.txt deleted file mode 100644 index 3c4a207..0000000 --- a/manifest.txt +++ /dev/null @@ -1,3 +0,0 @@ -Main-Class: Game -Name: pokemon-cmd/package/ -Sealed: true diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..002f64f --- /dev/null +++ b/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + + pokemon-cmd + pokemon-cmd + 0.1-alpha + + jar + + Pokemon CMD + https://git.knarcraft.net/EpicKnarvik97/pokemon-cmd + 2017 + + + GNU GENERAL PUBLIC LICENSE + https://fsf.org/ + + + + + EpicKnarvik97 + Kristian Knarvik + https://kristianknarvik.knarcraft.net + + leader + developer + + Europe/Oslo + + + + + UTF-8 + 1.8 + 1.8 + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + + true + lib/ + Game + + + + + + + \ No newline at end of file diff --git a/src/main/java/Game.java b/src/main/java/Game.java new file mode 100644 index 0000000..e84dab0 --- /dev/null +++ b/src/main/java/Game.java @@ -0,0 +1,419 @@ +import items.*; +import pokemon.Pokemon; +import storage.Inventory; +import storage.Trainer; + +import java.util.*; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.lang.NumberFormatException; +import java.text.NumberFormat; +import java.text.ParseException; + +/** Simulates the game Pokémon */ +public class Game { + public static final Scanner in = new Scanner(System.in); + private static Pokemon opponentPokemon; + private static List availableOpponentPokemon; + private static Pokemon playersCurrentPokemon; + private static Trainer player; + + public static void main(String[] args) { + availableOpponentPokemon = readPokemon(); + int initialPokemon = availableOpponentPokemon.size(); + + System.out.println("What is your name?"); + String name = in.nextLine(); + player = new Trainer(name, randomTeam(), createInventory()); + + boolean done = false; + + triggerNewEncounter(); + + while (!done) { + if (opponentPokemon == null) { + System.out.printf("You have brutally murdered %d pokemon.%n" + + "The only ones left are the ones in your possession.%n" + + "There really is nothing more for you to do here.%n", initialPokemon); + return; + } + if (player.getConsciousPokemon().size() < 1) { + System.out.println("All your pokemon have fainted. Your journey ends here."); + return; + } + while (playersCurrentPokemon == null || !playersCurrentPokemon.isConscious()) { + player.listAvailablePokemon(true); + playersCurrentPokemon = player.choosePokemon(true); + } + System.out.printf("Opponent: %s%nWhat will you do?%n", opponentPokemon); + System.out.printf("b: battle" + + "%nh: heal or revive" + + "%nt: throw pokeball" + + "%nc: change pokemon" + + "%nf: flee" + + "%nv: view my pokemon" + + "%ns: save" + + "%nl: load" + + "%nq: quit%n>"); + char command = in.next().toLowerCase().charAt(0); + switch (command) { + case 'b': + battle(); + break; + case 'h': + healPokemon(); + break; + case 't': + throwPokeBall(); + break; + case 'c': + choosePokemon(); + break; + case 's': + save(); + break; + case 'l': + load(); + break; + case 'f': + flee(); + break; + case 'v': + showPokemon(); + break; + case 'q': + done = true; + break; + default: + System.out.println("[Invalid command]"); + } + } + } + + /** + * Lists all of the player's pokemon + */ + private static void showPokemon() { + player.printPokemon(); + } + + + /** + * Tries to flee from the current opponent + */ + private static void flee() { + boolean fleeSuccessful = playersCurrentPokemon.flee(opponentPokemon); + if (fleeSuccessful) { + System.out.println("You fled the battle."); + triggerNewEncounter(); + } else { + System.out.printf("Failed to flee from %s.%n", opponentPokemon.getName()); + opponentPokemon.attack(playersCurrentPokemon); + } + } + + /** + * Loads game information from a save + */ + private static void load() { + List loadedPokemon = loadPokemon("pokemon.save"); + List loadedUsersPokemon = loadPokemon("user.save"); + Inventory loadedInventory = loadInventory("inventory.save"); + if (loadedPokemon == null || loadedUsersPokemon == null || loadedInventory == null) { + System.out.println("One or more savefiles seem corrupt or missing. Please delete, create or fix the affected file(s)."); + } else { + availableOpponentPokemon = loadedPokemon; + player.setPokemon(loadedUsersPokemon); + player.setInventory(loadedInventory); + if (availableOpponentPokemon.size() > 0 && player.getPokemon().size() > 0) { + do { + player.listAvailablePokemon(true); + playersCurrentPokemon = player.choosePokemon(true); + } while (playersCurrentPokemon == null || !playersCurrentPokemon.isConscious()); + opponentPokemon = randomPokemon(availableOpponentPokemon); + } + } + } + + /** + * Saves all stats about the game + */ + private static void save() { + savePokemon(availableOpponentPokemon, "pokemon.save"); + savePokemon(player.getPokemon(), "user.save"); + saveInventory(player.getInventory(), "inventory.save"); + } + + /** + * Chooses a new pokemon from the player's available pokemon + */ + private static void choosePokemon() { + player.listAvailablePokemon(true); + playersCurrentPokemon = player.choosePokemon(true); + while (playersCurrentPokemon == null) { + player.listAvailablePokemon(true); + playersCurrentPokemon = player.choosePokemon(true); + } + opponentPokemon.attack(playersCurrentPokemon); + } + + /** + * Makes the player's pokemon attack the enemy pokemon + */ + private static void battle() { + if (opponentPokemon.isConscious() && playersCurrentPokemon.isConscious()) { + playersCurrentPokemon.attack(opponentPokemon); + if (opponentPokemon.isConscious()) { + opponentPokemon.attack(playersCurrentPokemon); + if (!playersCurrentPokemon.isConscious()) { + System.out.println("Your pokemon fainted."); + } + } else { + pokemonFainted(availableOpponentPokemon, opponentPokemon); + System.out.println("The opponent pokemon fainted."); + triggerNewEncounter(); + } + } + } + + /** + * Heals a pokemon if possible + */ + private static void healPokemon() { + if (player.getInventory().getPotions().size() > 0) { + player.getInventory().availablePotions(); + AbstractPotion currentPotion = player.getInventory().getChosenPotion(); + if (currentPotion == null) { + in.nextLine(); + System.out.println("Invalid potion."); + } else { + Pokemon pokemonToHeal; + if (currentPotion.needsAlive()) { + player.listAvailablePokemon(true); + pokemonToHeal = player.choosePokemon(true); + } else { + player.listAvailablePokemon(false); + pokemonToHeal = player.choosePokemon(false); + } + if (pokemonToHeal == null) { + System.out.println("That is not a valid pokemon"); + } else { + if (currentPotion.use(pokemonToHeal)) { + player.getInventory().addItem(currentPotion, -1); + opponentPokemon.attack(playersCurrentPokemon); + } + } + } + } else { + System.out.println("You have used all your healing items."); + } + } + + /** + * Tries throwing a poke ball at the enemy pokemon + */ + private static void throwPokeBall() { + if (player.getInventory().getPokeBalls().size() > 0) { + player.getInventory().availablePokeBalls(); + AbstractPokeBall currentPokeBall = player.getInventory().getChosenPokeBall(); + if (currentPokeBall == null) { + in.nextLine(); + System.out.println("Invalid pokeball."); + } else { + boolean captured = currentPokeBall.use(opponentPokemon, availableOpponentPokemon, player); + player.getInventory().addItem(currentPokeBall, -1); + if (captured) { + triggerNewEncounter(); + } else { + opponentPokemon.attack(playersCurrentPokemon); + } + } + } else { + System.out.println("You have used all your pokeballs."); + } + } + + /** + * Triggers an encounter with a new wild pokemon + */ + private static void triggerNewEncounter() { + opponentPokemon = randomPokemon(availableOpponentPokemon); + System.out.printf("A wild %s appeared.%n", opponentPokemon.getName()); + } + + /** + * Removes a fainted pokemon from encounter-able pokemon + * @param pokemonList

List of pokemon to search

+ * @param target

The pokemon to remove

+ */ + public static void pokemonFainted(List pokemonList, Pokemon target) { + pokemonList.removeIf(pokemon -> pokemon.equals(target)); + } + + /** + * Gives a trainer necessary starting items + * @return

A list of items

+ */ + public static Inventory createInventory() { + Inventory inventory = new Inventory(); + inventory.addItem(new PokeBall(), 15); + inventory.addItem(new GreatBall(), 10); + inventory.addItem(new UltraBall(), 5); + inventory.addItem(new MasterBall(), 1); + inventory.addItem(new Potion(), 20); + inventory.addItem(new SuperPotion(), 10); + inventory.addItem(new HyperPotion(), 5); + inventory.addItem(new MaxPotion(), 1); + inventory.addItem(new Revive(), 2); + return inventory; + } + + /** + * Chooses a random pokemon from a list + * @param pokemon

The list to choose from

+ * @return

A pokemon.Pokemon object, or null if the list is empty

+ */ + public static Pokemon randomPokemon(List pokemon) { + if (pokemon.size() > 0) { + return pokemon.get((int)(Math.random() * pokemon.size())); + } else { + throw new IllegalArgumentException("Can't get random pokemon from empty list"); + } + } + + /** + * Reads pokemon from pokemon.Pokemon.txt to an ArrayList. + * @return

An ArrayList of pokemon objects

+ */ + public static ArrayList readPokemon() { + ArrayList pokemon = new ArrayList<>(); + try (Scanner file = new Scanner(new File("config/Pokemon.txt"))) { + while (file.hasNextLine()) { + pokemon.add(new Pokemon(file.nextLine())); + } + } catch (FileNotFoundException e) { + /* If the file is compiled as jar, this will prevent an empty list. */ + try (Scanner file = new Scanner(Game.class.getResourceAsStream("config/Pokemon.txt"))) { + while (file.hasNextLine()) { + pokemon.add(new Pokemon(file.nextLine())); + } + } + } + return pokemon; + } + + /** + * Picks a random pokemon from a list + * @param pokemon

A list of pokemon objects

+ * @return

A pokemon object which exists in the input list

+ */ + public static Pokemon pickRandomPokemon(ArrayList pokemon) { + int index = (int)(Math.random() * (pokemon.size())); + Pokemon randomPokemon = pokemon.get(index); + pokemon.remove(index); + return randomPokemon; + } + + /** + * Saves all pokemon in a list to a text file + * @param pokemonList

List of pokemon.Pokemon objects to save

+ * @param saveFile

The file to write to

+ */ + public static void savePokemon(List pokemonList, String saveFile) { + try (PrintWriter file = new PrintWriter(saveFile)) { + for (Pokemon pokemon : pokemonList) { + file.println(pokemon.saveString()); + } + System.out.println("Successfully saved pokemon."); + } catch (FileNotFoundException e) { + System.out.println("The saveFile could not be written."); + } + } + + /** + * Saves the inventory to a text file + * @param inventory

The inventory to save

+ * @param saveFile

The file to write to

+ */ + public static void saveInventory(Inventory inventory, String saveFile) { + try (PrintWriter file = new PrintWriter(saveFile)) { + file.println(inventory.getSaveString()); + System.out.println("Successfully saved inventory."); + } catch (FileNotFoundException e) { + System.out.println("The saveFile could not be written."); + } + } + + /** + * Loads pokemon from a text file + * @param saveFile

The file to read

+ * @return

A list of pokemon or null on failure

+ */ + public static ArrayList loadPokemon(String saveFile) { + ArrayList pokemon = new ArrayList<>(); + try (Scanner file = new Scanner(new File(saveFile))) { + NumberFormat format = NumberFormat.getInstance(Locale.ENGLISH); + while (file.hasNextLine()) { + String[] data = file.nextLine().split(";"); + try { + pokemon.add(new Pokemon(data[0], Integer.parseInt(data[1]), Integer.parseInt(data[2]), + Integer.parseInt(data[3]), format.parse(data[4]).doubleValue(), + Integer.parseInt(data[5]), Integer.parseInt(data[6]), Integer.parseInt(data[7]))); + } catch (NumberFormatException | ParseException e) { + System.out.println("Malformed number " + e.getMessage()); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println("Invalid saveFile: " + saveFile); + return null; + } + } + System.out.println("Successfully loaded pokemon."); + } catch (FileNotFoundException e) { + System.out.println("Missing saveFile " + saveFile); + return null; + } + return pokemon; + } + + /** + * Loads inventory from a text file + * @param saveFile

The file to write to

+ * @return

A list of items or null on failure

+ */ + public static Inventory loadInventory(String saveFile) { + Inventory inventory = new Inventory(); + try (Scanner file = new Scanner(new File(saveFile))) { + while (file.hasNextLine()) { + try { + String line = file.nextLine(); + if (line.isEmpty()) { + break; + } + String[] data = line.split(";"); + inventory.addItem(Item.getItemByName(data[0]), Integer.parseInt(data[1])); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println("Invalid saveFile: " + saveFile); + return null; + } + } + System.out.println("Successfully loaded items."); + } catch (FileNotFoundException e) { + System.out.println("Missing saveFile " + saveFile); + return null; + } + return inventory; + } + + /** + * Returns a random list of 6 pokemon + * @return

A list of pokemon.Pokemon

+ */ + public static ArrayList randomTeam() { + ArrayList temporary = readPokemon(); + ArrayList pokemon = new ArrayList<>(); + for (int i = 1; i <= 6; i++) { + pokemon.add(pickRandomPokemon(temporary)); + } + return pokemon; + } +} diff --git a/src/main/java/items/AbstractPokeBall.java b/src/main/java/items/AbstractPokeBall.java new file mode 100644 index 0000000..1c5d9dd --- /dev/null +++ b/src/main/java/items/AbstractPokeBall.java @@ -0,0 +1,31 @@ +package items; + +import pokemon.Pokemon; +import storage.Trainer; + +import java.util.List; + +/** + * An abstract class representing a poke ball + */ +public abstract class AbstractPokeBall extends Item { + /** + * Instantiates a new poke ball + * @param name

The name of the poke ball

+ * @param description

The description of the poke ball

+ */ + public AbstractPokeBall(String name, String description) { + super(name, description); + } + + /** + * Uses a poke ball on an opponent + * @param target

Which pokemon to target

+ * @param current

Current list the pokemon belongs to

+ * @param catcher

Where we send the pokemon on a successful capture

+ * @return

True if nothing went wrong. False otherwise

+ */ + public boolean use(Pokemon target, List current, Trainer catcher) { + return false; + } +} diff --git a/src/main/java/items/AbstractPotion.java b/src/main/java/items/AbstractPotion.java new file mode 100644 index 0000000..9d6757c --- /dev/null +++ b/src/main/java/items/AbstractPotion.java @@ -0,0 +1,67 @@ +package items; + +import pokemon.Pokemon; + +/** + * An abstract class representing a potion + */ +public abstract class AbstractPotion extends Item { + final boolean alive; + + /** + * Instantiates a new potion + * @param name

The name of the potion

+ * @param description

The description of the potion

+ */ + public AbstractPotion(String name, String description) { + super(name, description); + this.alive = true; + } + + /** + * Instantiates a new potion + * @param name

The name of the potion

+ * @param description

The description of the potion

+ * @param alive

Whether the pokemon needs to be alive to use the potion

+ */ + public AbstractPotion(String name, String description, boolean alive) { + super(name, description); + this.alive = alive; + } + + /** Checks if an item should be used on alive or fainted pokemon. */ + public boolean needsAlive() { + return alive; + } + + /** + * Uses an item and does something based on the type of item + * @param target

Which pokemon should the item be used on

+ * @return

True if nothing went wrong. False otherwise

+ */ + public boolean use(Pokemon target) { + return false; + } + + /** + * Checks if a pokemon is able to, and in need of a potion. If it is, heal it + * @param target

The pokemon to heal

+ * @param amount

The amount to heal the pokemon

+ * @return

True if nothing went wrong. False otherwise

+ */ + boolean potion(Pokemon target, int amount) { + if (target.isConscious()) { + if (target.isDamaged()) { + int healed = target.heal(amount); + System.out.printf("%s was healed for %d HP and now has %d HP.%n", target.getName(), healed, target.getHP()); + return true; + } else { + System.out.printf("%s has not taken damage, and does not require a potion.%n", target.getName()); + return false; + } + } else { + System.out.println("You can't heal a fainted pokemon."); + return false; + } + } +} diff --git a/src/main/java/items/GreatBall.java b/src/main/java/items/GreatBall.java new file mode 100644 index 0000000..16b209a --- /dev/null +++ b/src/main/java/items/GreatBall.java @@ -0,0 +1,22 @@ +package items; + +import pokemon.Pokemon; +import storage.Trainer; + +import java.util.List; + +/** + * This class represents a great ball item + */ +public class GreatBall extends AbstractPokeBall { + public GreatBall() { + super("Great ball", + "A good, high-performance Poké Ball that provides a higher Pokémon catch rate than a " + + "standard Poké Ball."); + } + + @Override + public boolean use(Pokemon target, List current, Trainer catcher) { + return target.tryCapture(current, catcher, 200); + } +} diff --git a/src/main/java/items/HyperPotion.java b/src/main/java/items/HyperPotion.java new file mode 100644 index 0000000..800598b --- /dev/null +++ b/src/main/java/items/HyperPotion.java @@ -0,0 +1,17 @@ +package items; + +import pokemon.Pokemon; + +/** + * This class represents a hyper potion item + */ +public class HyperPotion extends AbstractPotion { + public HyperPotion() { + super("Hyper Potion", "Heals a pokemon for 200 HP."); + } + + @Override + public boolean use(Pokemon target) { + return potion(target, 200); + } +} diff --git a/src/main/java/items/Item.java b/src/main/java/items/Item.java new file mode 100644 index 0000000..978712c --- /dev/null +++ b/src/main/java/items/Item.java @@ -0,0 +1,82 @@ +package items; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class represents a general item which can be stored in an inventory + */ +public abstract class Item { + final String name; + final String description; + static List availableItems = new ArrayList<>(); + + /** + * Instantiates a new item + * @param name

The name of the item

+ * @param description

The description of the item

+ */ + public Item(String name, String description) { + this.name = name; + this.description = description; + } + + /** + * Returns an item by the given name + * @param name

The name of the item to get

+ * @return

An item with the name, or null if no such item exists

+ */ + public static Item getItemByName(String name) { + if (availableItems.isEmpty()) { + initializeItems(); + } + for (Item item : availableItems) { + if (item.name.equals(name)) { + return item; + } + } + return null; + } + + /** + * Initializes all known items so that they are usable + */ + private static void initializeItems() { + availableItems.add(new PokeBall()); + availableItems.add(new GreatBall()); + availableItems.add(new HyperPotion()); + availableItems.add(new MasterBall()); + availableItems.add(new MaxPotion()); + availableItems.add(new Potion()); + availableItems.add(new Revive()); + availableItems.add(new SuperPotion()); + availableItems.add(new UltraBall()); + } + + /** + * Makes a nice string describing the item + * @return

Name: Description

+ */ + public String toString() { + return String.format("%s: %s", this.name, this.description); + } + + /** + * Returns a string used for saving the item + * @return

Name;Description

+ */ + public String saveString() { + return String.format("%s", this.name); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!Item.class.isAssignableFrom(obj.getClass())) { + return false; + } + return this.name.equals(((Item) obj).name); + } +} diff --git a/src/main/java/items/MasterBall.java b/src/main/java/items/MasterBall.java new file mode 100644 index 0000000..6f3d957 --- /dev/null +++ b/src/main/java/items/MasterBall.java @@ -0,0 +1,21 @@ +package items; + +import pokemon.Pokemon; +import storage.Trainer; + +import java.util.List; + +/** + * This class represents a master ball item + */ +public class MasterBall extends AbstractPokeBall { + public MasterBall() { + super("Master ball", "The best Poké Ball with the ultimate level of performance. With it, " + + "you will catch any wild Pokémon without fail."); + } + + @Override + public boolean use(Pokemon target, List current, Trainer catcher) { + return target.tryCapture(current, catcher, 0); + } +} diff --git a/src/main/java/items/MaxPotion.java b/src/main/java/items/MaxPotion.java new file mode 100644 index 0000000..78e123a --- /dev/null +++ b/src/main/java/items/MaxPotion.java @@ -0,0 +1,17 @@ +package items; + +import pokemon.Pokemon; + +/** + * This class represents a max potion item + */ +public class MaxPotion extends AbstractPotion { + public MaxPotion() { + super("Max Potion", "Fully heals a pokemon."); + } + + @Override + public boolean use(Pokemon target) { + return potion(target, -1); + } +} diff --git a/src/main/java/items/PokeBall.java b/src/main/java/items/PokeBall.java new file mode 100644 index 0000000..71e2d72 --- /dev/null +++ b/src/main/java/items/PokeBall.java @@ -0,0 +1,21 @@ +package items; + +import pokemon.Pokemon; +import storage.Trainer; + +import java.util.List; + +/** + * This class represents a poke ball item + */ +public class PokeBall extends AbstractPokeBall { + public PokeBall() { + super("Poke Ball", "A device for catching wild Pokémon. It's thrown like a ball at a " + + "Pokémon, comfortably encapsulating its target."); + } + + @Override + public boolean use(Pokemon target, List current, Trainer catcher) { + return target.tryCapture(current, catcher, 255); + } +} diff --git a/src/main/java/items/Potion.java b/src/main/java/items/Potion.java new file mode 100644 index 0000000..de5c37a --- /dev/null +++ b/src/main/java/items/Potion.java @@ -0,0 +1,20 @@ +package items; + +import pokemon.Pokemon; + +/** + * This class represents potion item + */ +public class Potion extends AbstractPotion { + /** + * Instantiates a potion + */ + public Potion() { + super("Potion", "Heals a pokemon for 20 HP."); + } + + @Override + public boolean use(Pokemon target) { + return potion(target, 20); + } +} diff --git a/src/main/java/items/Revive.java b/src/main/java/items/Revive.java new file mode 100644 index 0000000..82a1c0d --- /dev/null +++ b/src/main/java/items/Revive.java @@ -0,0 +1,24 @@ +package items; + +import pokemon.Pokemon; + +/** + * This class represents a revive item + */ +public class Revive extends AbstractPotion { + public Revive() { + super("Revive", "Revives a fainted pokemon.", true); + } + + @Override + public boolean use(Pokemon target) { + if (!target.isConscious()) { + target.revive(); + System.out.printf("%s was revived.%n", target.getName()); + return true; + } else { + System.out.println("You can't revive a conscious pokemon."); + return false; + } + } +} diff --git a/src/main/java/items/SuperPotion.java b/src/main/java/items/SuperPotion.java new file mode 100644 index 0000000..8be094e --- /dev/null +++ b/src/main/java/items/SuperPotion.java @@ -0,0 +1,17 @@ +package items; + +import pokemon.Pokemon; + +/** + * This class represents a super potion item + */ +public class SuperPotion extends AbstractPotion { + public SuperPotion() { + super("Super Potion", "Heals a pokemon for 50 HP."); + } + + @Override + public boolean use(Pokemon target) { + return potion(target, 50); + } +} diff --git a/src/main/java/items/UltraBall.java b/src/main/java/items/UltraBall.java new file mode 100644 index 0000000..47ae09a --- /dev/null +++ b/src/main/java/items/UltraBall.java @@ -0,0 +1,21 @@ +package items; + +import pokemon.Pokemon; +import storage.Trainer; + +import java.util.List; + +/** + * This class represents an ultra ball item + */ +public class UltraBall extends AbstractPokeBall { + public UltraBall() { + super("Ultra ball", "An ultra-high-performance Poké Ball that provides a higher success rate " + + "for catching Pokémon than a Great Ball."); + } + + @Override + public boolean use(Pokemon target, List current, Trainer catcher) { + return target.tryCapture(current, catcher, 150); + } +} diff --git a/src/main/java/pokemon/Pokemon.java b/src/main/java/pokemon/Pokemon.java new file mode 100644 index 0000000..01958cc --- /dev/null +++ b/src/main/java/pokemon/Pokemon.java @@ -0,0 +1,243 @@ +package pokemon; + +import storage.Trainer; + +import java.util.List; +import java.util.Random; + +/** + * This class represents a pokemon + */ +public class Pokemon { + private final String name; + private int healthPoints; + private int maxHealthPoints; + private int strength; + private final double criticalChance; + private final Random random; + private final int catchRate; + private int exp; + private int level; + private int fleeCount; + + /** + * Instantiates a new pokemon with random stats + * @param name

The name of the pokemon

+ */ + public Pokemon(String name) { + this.random = new Random(); + this.name = name; + this.healthPoints = 30 + random.nextInt(70); + this.maxHealthPoints = this.healthPoints; + this.criticalChance = Math.abs(0.1 * random.nextGaussian()); + this.catchRate = (int)(Math.random() * 256); + this.exp = 0; + this.level = (int)(Math.abs(2 * random.nextGaussian()) + 1); + this.strength = random.nextInt(7) + this.level; + this.fleeCount = 0; + } + + /** + * Instantiates a pokemon with set stats + * @param name

The name of the pokemon

+ * @param healthPoints

The current HP of the pokemon

+ * @param maxHealthPoints

The max HP of the pokemon

+ * @param strength

The strength of the pokemon

+ * @param criticalChance

The critical hit chance of the pokemon

+ * @param catchRate

The catch rate of the pokemon. A higher rate makes it easier to catch

+ * @param exp

The current xp of the pokemon

+ * @param level

The current level of the pokemon

+ */ + public Pokemon(String name, int healthPoints, int maxHealthPoints, int strength, double criticalChance, int catchRate, int exp, int level) { + this.random = new Random(); + this.name = name; + this.healthPoints = healthPoints; + this.maxHealthPoints = maxHealthPoints; + this.criticalChance = criticalChance; + this.catchRate = catchRate; + this.exp = exp; + this.level = level; + this.strength = strength; + this.fleeCount = 0; + } + + /** + * Makes a string containing all information about the pokemon + * @return

A descriptive string

+ */ + public String toString() { + return String.format("Level %d %s HP: (%d/%d) STR: %d CHC: %.0f%%", this.level, this.name, this.healthPoints, + this.maxHealthPoints, this.strength, (this.criticalChance*100)); + } + + /** + * Returns a string containing all the pokemon's data in a save-able format + */ + public String saveString() { + return String.format("%s;%d;%d;%d;%f;%d;%d;%d", this.name, this.healthPoints, this.maxHealthPoints, + this.strength, this.criticalChance, this.catchRate, this.exp, this.level); + } + + /** + * Gets the name of the pokemon + * @return

The name of the pokemon

+ */ + public String getName() { + return this.name; + } + + /** + * Gets the current hit points of the pokemon + * @return

The current HP of the pokemon

+ */ + public int getHP() { + return this.healthPoints; + } + + /** + * Checks whether two pokemon are equal + * @param target

The pokemon to check against

+ * @return

True if they are equal. False otherwise

+ */ + public boolean equals(Pokemon target) { + return target == this; + } + + /** + * Heals a pokemon + * @param amount

How many hit points to heal

+ * @return

The exact amount of hit points healed

+ */ + public int heal(int amount) { + if (amount < 0) { + amount = this.maxHealthPoints - this.healthPoints; + } else { + amount = Math.min(this.maxHealthPoints - this.healthPoints, amount); + } + this.healthPoints += amount; + return amount; + } + + /** + * Checks if a pokemon has not taken any damage or is fully healed + * @return

True if health is full. False otherwise

+ */ + public boolean isDamaged() { + return this.healthPoints < this.maxHealthPoints; + } + + /** + * Tries to catch a pokemon + * @param current

The list where the pokemon currently belongs

+ * @param catcher

The list to send the pokemon on successful capture

+ * @return

True on successful capture. False otherwise

+ */ + public boolean tryCapture(List current, Trainer catcher, int range) { + if (range == 0) { + this.capture(current, catcher); + System.out.printf("%s was caught.%n", this.name); + return true; + } + if ((int)(Math.random() * (range + 1)) < Math.max((3 * this.maxHealthPoints - 2 * this.healthPoints) * + this.catchRate / (3 * this.maxHealthPoints), 1)) { + this.capture(current, catcher); + System.out.printf("%s was caught.%n", this.name); + return true; + } else { + System.out.printf("%s escaped from the pokeball.%n", this.name); + return false; + } + } + + /** + * Captures a wild pokemon + * @param current

The pokemon list the pokemon belongs to

+ * @param trainer

The trainer capturing the pokemon

+ */ + private void capture(List current, Trainer trainer) { + trainer.addPokemon(this); + current.removeIf(pokemon -> pokemon == this); + } + + /** + * Restores the health of a fainted pokemon + */ + public void revive() { + this.healthPoints = this.maxHealthPoints; + } + + /** + * Checks if the pokemon has any HP left + * @return

True if any HP is left. False otherwise

+ */ + public boolean isConscious() { + return this.healthPoints > 0; + } + + /** + * Damages a pokemon + * @param damageTaken

How many hit points are to be deducted

+ */ + public void damage(int damageTaken) { + this.healthPoints = Math.max(this.healthPoints -= damageTaken, 0); + System.out.printf("%s takes %d damage and is left with %d/%d HP%n", this.name, damageTaken, this.healthPoints, this.maxHealthPoints); + } + + /** + * Gives a pokemon exp after each successful battle. Also handles leveling up + * @param target

Which pokemon did we beat

+ */ + private void giveEXP(Pokemon target) { + int exp = (100 * target.level)/7; + this.exp += exp; + System.out.printf("%s gained %d exp.%n", this.name, exp); + if (this.exp > (4 * Math.pow(this.level, 3)) / 5) { + this.level++; + this.maxHealthPoints += 5; + this.healthPoints = maxHealthPoints; + this.strength += 1; + System.out.printf("%s is now level %d. Health has been increased and restored. Strength has been increased.%n", this.name, this.level); + } + } + + /** + * Makes a pokemon attack another pokemon + * @param target

The pokemon to take damage

+ */ + public void attack(Pokemon target) { + if (this.healthPoints > 0) { + System.out.printf("%s attacks %s.%n", this.getName(), target.getName()); + double critical = 1; + if (Math.random() < this.criticalChance) { + System.out.println("Critical hit!"); + critical = (2.0 * this.level +5) / (this.level + 5); + } + double randomDouble = 0.85 + (1.0 - 0.85) * random.nextDouble(); + int moveDamage = (int)(Math.random() * 60 + 40); + int damageInflicted = this.level + (int)((((((2 * this.strength) / 5) + 2) * moveDamage * 1.75) / 50 + 2) * critical * randomDouble); + target.damage(damageInflicted); + if (!target.isConscious()) { + System.out.printf("%s is defeated by %s.%n", target.getName(), this.getName()); + this.giveEXP(target); + this.fleeCount = 0; + } + } else { + System.out.println("No cheating!"); + } + } + + /** + * The trainer may flee if the battle is too hard + * @param target

Who are we trying to flee from

+ * @return

True on successful escape. False otherwise

+ */ + public boolean flee(Pokemon target) { + if (random.nextInt(256) < (this.level * 128 / target.level) + (30 * this.fleeCount % 256)) { + this.fleeCount = 0; + return true; + } else { + this.fleeCount++; + return false; + } + } +} diff --git a/src/main/java/storage/Inventory.java b/src/main/java/storage/Inventory.java new file mode 100644 index 0000000..8318f25 --- /dev/null +++ b/src/main/java/storage/Inventory.java @@ -0,0 +1,136 @@ +package storage; + +import items.*; + +import java.util.*; + +/** + * This class represents a pokemon trainer's inventory + */ +public class Inventory { + public static final Scanner in = new Scanner(System.in); + private final Map items; + + /** + * Initializes a new empty inventory + */ + public Inventory() { + this.items = new HashMap<>(); + } + + /** + * Adds a new item to the inventory + * + *

If the inventory already contains the item, the amount will be added to the existing amount.

+ * + * @param item

The item to be added to the inventory

+ * @param amount

The amount of the item to add

+ */ + public void addItem(Item item, Integer amount) { + if (items.get(item) != null) { + amount += items.get(item); + } + items.put(item, amount); + } + + /** + * Gets all available poke balls from the inventory + * @return

A list of poke balls

+ */ + public List getPokeBalls() { + List pokeBalls = new ArrayList<>(); + for (Item item : items.keySet()) { + if (AbstractPokeBall.class.isAssignableFrom(item.getClass()) && items.get(item) > 0) { + pokeBalls.add((AbstractPokeBall) item); + } + } + return pokeBalls; + } + + /** + * Gets all available potions from the inventory + * @return

A list of potions

+ */ + public List getPotions() { + List potions = new ArrayList<>(); + for (Item item : items.keySet()) { + if (AbstractPotion.class.isAssignableFrom(item.getClass()) && items.get(item) > 0) { + potions.add((AbstractPotion) item); + } + } + return potions; + } + + /** + * Prints out information about available poke balls + */ + public void availablePokeBalls() { + System.out.println("You may choose from these items:"); + List pokeBalls = getPokeBalls(); + for (int i = 0; i < pokeBalls.size(); i++) { + System.out.printf("%d: (%d) %s%n", i + 1, items.get(pokeBalls.get(i)), pokeBalls.get(i)); + } + System.out.print(">"); + } + + /** + * Prints out information about available potions + */ + public void availablePotions() { + System.out.println("You may choose from these items:"); + List potionList = getPotions(); + for (int i = 0; i < potionList.size(); i++) { + System.out.printf("%d: (%d) %s%n", i + 1, items.get(potionList.get(i)), potionList.get(i)); + } + System.out.print(">"); + } + + /** + * Gets a potion according to the user's input + * @return

The potion the user chose, or null on invalid choice

+ */ + public AbstractPotion getChosenPotion() { + List potions = getPotions(); + if (in.hasNextInt()) { + int choice = in.nextInt() - 1; + if (choice >= 0 && choice < potions.size()) { + in.nextLine(); + return potions.get(choice); + } + } else { + in.nextLine(); + } + return null; + } + + /** + * Gets a poke ball according to the user's input + * @return

The poke ball the user chose, or null on invalid choice

+ */ + public AbstractPokeBall getChosenPokeBall() { + List pokeBalls = getPokeBalls(); + if (in.hasNextInt()) { + int choice = in.nextInt() - 1; + if (choice >= 0 && choice < pokeBalls.size()) { + in.nextLine(); + return pokeBalls.get(choice); + } + } else { + in.nextLine(); + } + return null; + } + + /** + * Gets a save-able string containing all non-empty items in the inventory + * @return

A save string Name;Amount

+ */ + public String getSaveString() { + StringBuilder saveString = new StringBuilder(); + for (Item item : items.keySet()) { + saveString.append(item.saveString()).append(";").append(items.get(item)); + saveString.append("\n"); + } + return saveString.toString(); + } +} diff --git a/src/main/java/storage/Trainer.java b/src/main/java/storage/Trainer.java new file mode 100644 index 0000000..237ac42 --- /dev/null +++ b/src/main/java/storage/Trainer.java @@ -0,0 +1,147 @@ +package storage; + +import pokemon.Pokemon; + +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +/** + * This class represents a pokemon trainer + */ +public class Trainer { + public static final Scanner in = new Scanner(System.in); + final String name; + private List pokemon; + private Inventory inventory; + + /** + * Instantiates a new trainer + * @param name

The name of the trainer

+ * @param pokemon

The pokemon belonging to the trainer

+ * @param inventory

The inventory belonging to the trainer

+ */ + public Trainer(String name, ArrayList pokemon, Inventory inventory) { + this.name = name; + this.pokemon = pokemon; + this.inventory = inventory; + } + + /** + * Sets the list of pokemon belonging to the trainer + * @param pokemon

A list of pokemon

+ */ + public void setPokemon(List pokemon) { + this.pokemon = pokemon; + } + + /** + * Sets the inventory belonging to the trainer + * @param inventory

An inventory

+ */ + public void setInventory(Inventory inventory) { + this.inventory = inventory; + } + + /** + * Gets the list of pokemon belonging to the trainer + * @return

A list of pokemon

+ */ + public List getPokemon() { + return this.pokemon; + } + + /** + * Adds a pokemon to the trainer's list of pokemon + * @param pokemon

A pokemon

+ */ + public void addPokemon(Pokemon pokemon) { + this.pokemon.add(pokemon); + } + + /** + * Gets all conscious pokemon belonging to the trainer + * @return

A list of pokemon

+ */ + public ArrayList getConsciousPokemon() { + ArrayList pokemon = new ArrayList<>(); + for (Pokemon singlePokemon : this.pokemon) { + if (singlePokemon.isConscious()) { + pokemon.add(singlePokemon); + } + } + return pokemon; + } + + /** + * Gets all fainted pokemon belonging to the trainer + * @return

A list of pokemon

+ */ + public ArrayList getFaintedPokemon() { + ArrayList pokemon = new ArrayList<>(); + for (Pokemon singlePokemon : this.pokemon) { + if (!singlePokemon.isConscious()) { + pokemon.add(singlePokemon); + } + } + return pokemon; + } + + /** + * Gets the inventory of the user + * @return

An inventory

+ */ + public Inventory getInventory() { + return this.inventory; + } + + /** + * Lists all currently available pokemon for the trainer + * @param alive

Whether to list alive pokemon or dead

+ */ + public void listAvailablePokemon(boolean alive) { + ArrayList pokemonList; + if (alive) { + pokemonList = this.getConsciousPokemon(); + } else { + pokemonList = this.getFaintedPokemon(); + } + System.out.println("You may choose from these pokemon:"); + for (int i = 0; i < pokemonList.size(); i++) { + System.out.printf("%d: %s%n", i + 1, pokemonList.get(i)); + } + System.out.print(">"); + } + + /** + * Prints all pokemon belonging to the trainer + */ + public void printPokemon() { + for (Pokemon pokemon : this.pokemon) { + System.out.println(pokemon); + } + } + + /** + * Asks the user for the name of a pokemon and returns it + * @param alive

Whether the chosen pokemon has to be alive

+ * @return

A pokemon object or null

+ */ + public Pokemon choosePokemon(boolean alive) { + ArrayList pokemonList; + if (alive) { + pokemonList = this.getConsciousPokemon(); + } else { + pokemonList = this.getFaintedPokemon(); + } + if (in.hasNextInt()) { + int choice = in.nextInt() - 1; + if (choice >= 0 && choice < pokemonList.size()) { + in.nextLine(); + return pokemonList.get(choice); + } + } + in.nextLine(); + return null; + } +} diff --git a/java/config/Pokemon.txt b/src/main/resources/config/Pokemon.txt similarity index 89% rename from java/config/Pokemon.txt rename to src/main/resources/config/Pokemon.txt index 7aefb01..a110d35 100644 --- a/java/config/Pokemon.txt +++ b/src/main/resources/config/Pokemon.txt @@ -1,719 +1,719 @@ -Bulbasaur -Ivysaur -Venusaur -Charmander -Charmeleon -Charizard -Squirtle -Wartortle -Blastoise -Caterpie -Metapod -Butterfree -Weedle -Kakuna -Beedrill -Pidgey -Pidgeotto -Pidgeot -Rattata -Raticate -Spearow -Fearow -Ekans -Arbok -Pikachu -Raichu -Sandshrew -Sandslash -Nidoran♀ -Nidorina -Nidoqueen -Nidoran♂ -Nidorino -Nidoking -Clefairy -Clefable -Vulpix -Ninetales -Jigglypuff -Wigglytuff -Zubat -Golbat -Oddish -Gloom -Vileplume -Paras -Parasect -Venonat -Venomoth -Diglett -Dugtrio -Meowth -Persian -Psyduck -Golduck -Mankey -Primeape -Growlithe -Arcanine -Poliwag -Poliwhirl -Poliwrath -Abra -Kadabra -Alakazam -Machop -Machoke -Machamp -Bellsprout -Weepinbell -Victreebel -Tentacool -Tentacruel -Geodude -Graveler -Golem -Ponyta -Rapidash -Slowpoke -Slowbro -Magnemite -Magneton -Farfetch'd -Doduo -Dodrio -Seel -Dewgong -Grimer -Muk -Shellder -Cloyster -Gastly -Haunter -Gengar -Onix -Drowzee -Hypno -Krabby -Kingler -Voltorb -Electrode -Exeggcute -Exeggutor -Cubone -Marowak -Hitmonlee -Hitmonchan -Lickitung -Koffing -Weezing -Rhyhorn -Rhydon -Chansey -Tangela -Kangaskhan -Horsea -Seadra -Goldeen -Seaking -Staryu -Starmie -Mr. Mime -Scyther -Jynx -Electabuzz -Magmar -Pinsir -Tauros -Magikarp -Gyarados -Lapras -Ditto -Eevee -Vaporeon -Jolteon -Flareon -Porygon -Omanyte -Omastar -Kabuto -Kabutops -Aerodactyl -Snorlax -Articuno -Zapdos -Moltres -Dratini -Dragonair -Dragonite -Mewtwo -Mew -Chikorita -Bayleef -Meganium -Cyndaquil -Quilava -Typhlosion -Totodile -Croconaw -Feraligatr -Sentret -Furret -Hoothoot -Noctowl -Ledyba -Ledian -Spinarak -Ariados -Crobat -Chinchou -Lanturn -Pichu -Cleffa -Igglybuff -Togepi -Togetic -Natu -Xatu -Mareep -Flaaffy -Ampharos -Bellossom -Marill -Azumarill -Sudowoodo -Politoed -Hoppip -Skiploom -Jumpluff -Aipom -Sunkern -Sunflora -Yanma -Wooper -Quagsire -Espeon -Umbreon -Murkrow -Slowking -Misdreavus -Unown -Wobbuffet -Girafarig -Pineco -Forretress -Dunsparce -Gligar -Steelix -Snubbull -Granbull -Qwilfish -Scizor -Shuckle -Heracross -Sneasel -Teddiursa -Ursaring -Slugma -Magcargo -Swinub -Piloswine -Corsola -Remoraid -Octillery -Delibird -Mantine -Skarmory -Houndour -Houndoom -Kingdra -Phanpy -Donphan -Porygon2 -Stantler -Smeargle -Tyrogue -Hitmontop -Smoochum -Elekid -Magby -Miltank -Blissey -Raikou -Entei -Suicune -Larvitar -Pupitar -Tyranitar -Lugia -Ho-Oh -Celebi -Treecko -Grovyle -Sceptile -Torchic -Combusken -Blaziken -Mudkip -Marshtomp -Swampert -Poochyena -Mightyena -Zigzagoon -Linoone -Wurmple -Silcoon -Beautifly -Cascoon -Dustox -Lotad -Lombre -Ludicolo -Seedot -Nuzleaf -Shiftry -Taillow -Swellow -Wingull -Pelipper -Ralts -Kirlia -Gardevoir -Surskit -Masquerain -Shroomish -Breloom -Slakoth -Vigoroth -Slaking -Nincada -Ninjask -Shedinja -Whismur -Loudred -Exploud -Makuhita -Hariyama -Azurill -Nosepass -Skitty -Delcatty -Sableye -Mawile -Aron -Lairon -Aggron -Meditite -Medicham -Electrike -Manectric -Plusle -Minun -Volbeat -Illumise -Roselia -Gulpin -Swalot -Carvanha -Sharpedo -Wailmer -Wailord -Numel -Camerupt -Torkoal -Spoink -Grumpig -Spinda -Trapinch -Vibrava -Flygon -Cacnea -Cacturne -Swablu -Altaria -Zangoose -Seviper -Lunatone -Solrock -Barboach -Whiscash -Corphish -Crawdaunt -Baltoy -Claydol -Lileep -Cradily -Anorith -Armaldo -Feebas -Milotic -Castform -Kecleon -Shuppet -Banette -Duskull -Dusclops -Tropius -Chimecho -Absol -Wynaut -Snorunt -Glalie -Spheal -Sealeo -Walrein -Clamperl -Huntail -Gorebyss -Relicanth -Luvdisc -Bagon -Shelgon -Salamence -Beldum -Metang -Metagross -Regirock -Regice -Registeel -Latias -Latios -Kyogre -Groudon -Rayquaza -Jirachi -Deoxys -Turtwig -Grotle -Torterra -Chimchar -Monferno -Infernape -Piplup -Prinplup -Empoleon -Starly -Staravia -Staraptor -Bidoof -Bibarel -Kricketot -Kricketune -Shinx -Luxio -Luxray -Budew -Roserade -Cranidos -Rampardos -Shieldon -Bastiodon -Burmy -Wormadam -Mothim -Combee -Vespiquen -Pachirisu -Buizel -Floatzel -Cherubi -Cherrim -Shellos -Gastrodon -Ambipom -Drifloon -Drifblim -Buneary -Lopunny -Mismagius -Honchkrow -Glameow -Purugly -Chingling -Stunky -Skuntank -Bronzor -Bronzong -Bonsly -Mime Jr. -Happiny -Chatot -Spiritomb -Gible -Gabite -Garchomp -Munchlax -Riolu -Lucario -Hippopotas -Hippowdon -Skorupi -Drapion -Croagunk -Toxicroak -Carnivine -Finneon -Lumineon -Mantyke -Snover -Abomasnow -Weavile -Magnezone -Lickilicky -Rhyperior -Tangrowth -Electivire -Magmortar -Togekiss -Yanmega -Leafeon -Glaceon -Gliscor -Mamoswine -Porygon-Z -Gallade -Probopass -Dusknoir -Froslass -Rotom -Uxie -Mesprit -Azelf -Dialga -Palkia -Heatran -Regigigas -Giratina -Cresselia -Phione -Manaphy -Darkrai -Shaymin -Arceus -Victini -Snivy -Servine -Serperior -Tepig -Pignite -Emboar -Oshawott -Dewott -Samurott -Patrat -Watchog -Lillipup -Herdier -Stoutland -Purrloin -Liepard -Pansage -Simisage -Pansear -Simisear -Panpour -Simipour -Munna -Musharna -Pidove -Tranquill -Unfezant -Blitzle -Zebstrika -Roggenrola -Boldore -Gigalith -Woobat -Swoobat -Drilbur -Excadrill -Audino -Timburr -Gurdurr -Conkeldurr -Tympole -Palpitoad -Seismitoad -Throh -Sawk -Sewaddle -Swadloon -Leavanny -Venipede -Whirlipede -Scolipede -Cottonee -Whimsicott -Petilil -Lilligant -Basculin -Sandile -Krokorok -Krookodile -Darumaka -Darmanitan -Maractus -Dwebble -Crustle -Scraggy -Scrafty -Sigilyph -Yamask -Cofagrigus -Tirtouga -Carracosta -Archen -Archeops -Trubbish -Garbodor -Zorua -Zoroark -Minccino -Cinccino -Gothita -Gothorita -Gothitelle -Solosis -Duosion -Reuniclus -Ducklett -Swanna -Vanillite -Vanillish -Vanilluxe -Deerling -Sawsbuck -Emolga -Karrablast -Escavalier -Foongus -Amoonguss -Frillish -Jellicent -Alomomola -Joltik -Galvantula -Ferroseed -Ferrothorn -Klink -Klang -Klinklang -Tynamo -Eelektrik -Eelektross -Elgyem -Beheeyem -Litwick -Lampent -Chandelure -Axew -Fraxure -Haxorus -Cubchoo -Beartic -Cryogonal -Shelmet -Accelgor -Stunfisk -Mienfoo -Mienshao -Druddigon -Golett -Golurk -Pawniard -Bisharp -Bouffalant -Rufflet -Braviary -Vullaby -Mandibuzz -Heatmor -Durant -Deino -Zweilous -Hydreigon -Larvesta -Volcarona -Cobalion -Terrakion -Virizion -Tornadus -Thundurus -Reshiram -Zekrom -Landorus -Kyurem -Keldeo -Meloetta -Genesect -Chespin -Quilladin -Chesnaught -Fennekin -Braixen -Delphox -Froakie -Frogadier -Greninja -Bunnelby -Diggersby -Fletchling -Fletchinder -Talonflame -Scatterbug -Spewpa -Vivillon -Litleo -Pyroar -Flabébé -Floette -Florges -Skiddo -Gogoat -Pancham -Pangoro -Furfrou -Espurr -Meowstic -Honedge -Doublade -Aegislash -Spritzee -Aromatisse -Swirlix -Slurpuff -Inkay -Malamar -Binacle -Barbaracle -Skrelp -Dragalge -Clauncher -Clawitzer -Helioptile -Heliolisk -Tyrunt -Tyrantrum -Amaura -Aurorus -Sylveon -Hawlucha -Dedenne -Carbink -Goomy -Sliggoo -Goodra -Klefki -Phantump -Trevenant -Pumpkaboo -Gourgeist -Bergmite -Avalugg -Noibat -Noivern -Xerneas -Yveltal -Zygarde -Diancie +Bulbasaur +Ivysaur +Venusaur +Charmander +Charmeleon +Charizard +Squirtle +Wartortle +Blastoise +Caterpie +Metapod +Butterfree +Weedle +Kakuna +Beedrill +Pidgey +Pidgeotto +Pidgeot +Rattata +Raticate +Spearow +Fearow +Ekans +Arbok +Pikachu +Raichu +Sandshrew +Sandslash +Nidoran♀ +Nidorina +Nidoqueen +Nidoran♂ +Nidorino +Nidoking +Clefairy +Clefable +Vulpix +Ninetales +Jigglypuff +Wigglytuff +Zubat +Golbat +Oddish +Gloom +Vileplume +Paras +Parasect +Venonat +Venomoth +Diglett +Dugtrio +Meowth +Persian +Psyduck +Golduck +Mankey +Primeape +Growlithe +Arcanine +Poliwag +Poliwhirl +Poliwrath +Abra +Kadabra +Alakazam +Machop +Machoke +Machamp +Bellsprout +Weepinbell +Victreebel +Tentacool +Tentacruel +Geodude +Graveler +Golem +Ponyta +Rapidash +Slowpoke +Slowbro +Magnemite +Magneton +Farfetch'd +Doduo +Dodrio +Seel +Dewgong +Grimer +Muk +Shellder +Cloyster +Gastly +Haunter +Gengar +Onix +Drowzee +Hypno +Krabby +Kingler +Voltorb +Electrode +Exeggcute +Exeggutor +Cubone +Marowak +Hitmonlee +Hitmonchan +Lickitung +Koffing +Weezing +Rhyhorn +Rhydon +Chansey +Tangela +Kangaskhan +Horsea +Seadra +Goldeen +Seaking +Staryu +Starmie +Mr. Mime +Scyther +Jynx +Electabuzz +Magmar +Pinsir +Tauros +Magikarp +Gyarados +Lapras +Ditto +Eevee +Vaporeon +Jolteon +Flareon +Porygon +Omanyte +Omastar +Kabuto +Kabutops +Aerodactyl +Snorlax +Articuno +Zapdos +Moltres +Dratini +Dragonair +Dragonite +Mewtwo +Mew +Chikorita +Bayleef +Meganium +Cyndaquil +Quilava +Typhlosion +Totodile +Croconaw +Feraligatr +Sentret +Furret +Hoothoot +Noctowl +Ledyba +Ledian +Spinarak +Ariados +Crobat +Chinchou +Lanturn +Pichu +Cleffa +Igglybuff +Togepi +Togetic +Natu +Xatu +Mareep +Flaaffy +Ampharos +Bellossom +Marill +Azumarill +Sudowoodo +Politoed +Hoppip +Skiploom +Jumpluff +Aipom +Sunkern +Sunflora +Yanma +Wooper +Quagsire +Espeon +Umbreon +Murkrow +Slowking +Misdreavus +Unown +Wobbuffet +Girafarig +Pineco +Forretress +Dunsparce +Gligar +Steelix +Snubbull +Granbull +Qwilfish +Scizor +Shuckle +Heracross +Sneasel +Teddiursa +Ursaring +Slugma +Magcargo +Swinub +Piloswine +Corsola +Remoraid +Octillery +Delibird +Mantine +Skarmory +Houndour +Houndoom +Kingdra +Phanpy +Donphan +Porygon2 +Stantler +Smeargle +Tyrogue +Hitmontop +Smoochum +Elekid +Magby +Miltank +Blissey +Raikou +Entei +Suicune +Larvitar +Pupitar +Tyranitar +Lugia +Ho-Oh +Celebi +Treecko +Grovyle +Sceptile +Torchic +Combusken +Blaziken +Mudkip +Marshtomp +Swampert +Poochyena +Mightyena +Zigzagoon +Linoone +Wurmple +Silcoon +Beautifly +Cascoon +Dustox +Lotad +Lombre +Ludicolo +Seedot +Nuzleaf +Shiftry +Taillow +Swellow +Wingull +Pelipper +Ralts +Kirlia +Gardevoir +Surskit +Masquerain +Shroomish +Breloom +Slakoth +Vigoroth +Slaking +Nincada +Ninjask +Shedinja +Whismur +Loudred +Exploud +Makuhita +Hariyama +Azurill +Nosepass +Skitty +Delcatty +Sableye +Mawile +Aron +Lairon +Aggron +Meditite +Medicham +Electrike +Manectric +Plusle +Minun +Volbeat +Illumise +Roselia +Gulpin +Swalot +Carvanha +Sharpedo +Wailmer +Wailord +Numel +Camerupt +Torkoal +Spoink +Grumpig +Spinda +Trapinch +Vibrava +Flygon +Cacnea +Cacturne +Swablu +Altaria +Zangoose +Seviper +Lunatone +Solrock +Barboach +Whiscash +Corphish +Crawdaunt +Baltoy +Claydol +Lileep +Cradily +Anorith +Armaldo +Feebas +Milotic +Castform +Kecleon +Shuppet +Banette +Duskull +Dusclops +Tropius +Chimecho +Absol +Wynaut +Snorunt +Glalie +Spheal +Sealeo +Walrein +Clamperl +Huntail +Gorebyss +Relicanth +Luvdisc +Bagon +Shelgon +Salamence +Beldum +Metang +Metagross +Regirock +Regice +Registeel +Latias +Latios +Kyogre +Groudon +Rayquaza +Jirachi +Deoxys +Turtwig +Grotle +Torterra +Chimchar +Monferno +Infernape +Piplup +Prinplup +Empoleon +Starly +Staravia +Staraptor +Bidoof +Bibarel +Kricketot +Kricketune +Shinx +Luxio +Luxray +Budew +Roserade +Cranidos +Rampardos +Shieldon +Bastiodon +Burmy +Wormadam +Mothim +Combee +Vespiquen +Pachirisu +Buizel +Floatzel +Cherubi +Cherrim +Shellos +Gastrodon +Ambipom +Drifloon +Drifblim +Buneary +Lopunny +Mismagius +Honchkrow +Glameow +Purugly +Chingling +Stunky +Skuntank +Bronzor +Bronzong +Bonsly +Mime Jr. +Happiny +Chatot +Spiritomb +Gible +Gabite +Garchomp +Munchlax +Riolu +Lucario +Hippopotas +Hippowdon +Skorupi +Drapion +Croagunk +Toxicroak +Carnivine +Finneon +Lumineon +Mantyke +Snover +Abomasnow +Weavile +Magnezone +Lickilicky +Rhyperior +Tangrowth +Electivire +Magmortar +Togekiss +Yanmega +Leafeon +Glaceon +Gliscor +Mamoswine +Porygon-Z +Gallade +Probopass +Dusknoir +Froslass +Rotom +Uxie +Mesprit +Azelf +Dialga +Palkia +Heatran +Regigigas +Giratina +Cresselia +Phione +Manaphy +Darkrai +Shaymin +Arceus +Victini +Snivy +Servine +Serperior +Tepig +Pignite +Emboar +Oshawott +Dewott +Samurott +Patrat +Watchog +Lillipup +Herdier +Stoutland +Purrloin +Liepard +Pansage +Simisage +Pansear +Simisear +Panpour +Simipour +Munna +Musharna +Pidove +Tranquill +Unfezant +Blitzle +Zebstrika +Roggenrola +Boldore +Gigalith +Woobat +Swoobat +Drilbur +Excadrill +Audino +Timburr +Gurdurr +Conkeldurr +Tympole +Palpitoad +Seismitoad +Throh +Sawk +Sewaddle +Swadloon +Leavanny +Venipede +Whirlipede +Scolipede +Cottonee +Whimsicott +Petilil +Lilligant +Basculin +Sandile +Krokorok +Krookodile +Darumaka +Darmanitan +Maractus +Dwebble +Crustle +Scraggy +Scrafty +Sigilyph +Yamask +Cofagrigus +Tirtouga +Carracosta +Archen +Archeops +Trubbish +Garbodor +Zorua +Zoroark +Minccino +Cinccino +Gothita +Gothorita +Gothitelle +Solosis +Duosion +Reuniclus +Ducklett +Swanna +Vanillite +Vanillish +Vanilluxe +Deerling +Sawsbuck +Emolga +Karrablast +Escavalier +Foongus +Amoonguss +Frillish +Jellicent +Alomomola +Joltik +Galvantula +Ferroseed +Ferrothorn +Klink +Klang +Klinklang +Tynamo +Eelektrik +Eelektross +Elgyem +Beheeyem +Litwick +Lampent +Chandelure +Axew +Fraxure +Haxorus +Cubchoo +Beartic +Cryogonal +Shelmet +Accelgor +Stunfisk +Mienfoo +Mienshao +Druddigon +Golett +Golurk +Pawniard +Bisharp +Bouffalant +Rufflet +Braviary +Vullaby +Mandibuzz +Heatmor +Durant +Deino +Zweilous +Hydreigon +Larvesta +Volcarona +Cobalion +Terrakion +Virizion +Tornadus +Thundurus +Reshiram +Zekrom +Landorus +Kyurem +Keldeo +Meloetta +Genesect +Chespin +Quilladin +Chesnaught +Fennekin +Braixen +Delphox +Froakie +Frogadier +Greninja +Bunnelby +Diggersby +Fletchling +Fletchinder +Talonflame +Scatterbug +Spewpa +Vivillon +Litleo +Pyroar +Flabébé +Floette +Florges +Skiddo +Gogoat +Pancham +Pangoro +Furfrou +Espurr +Meowstic +Honedge +Doublade +Aegislash +Spritzee +Aromatisse +Swirlix +Slurpuff +Inkay +Malamar +Binacle +Barbaracle +Skrelp +Dragalge +Clauncher +Clawitzer +Helioptile +Heliolisk +Tyrunt +Tyrantrum +Amaura +Aurorus +Sylveon +Hawlucha +Dedenne +Carbink +Goomy +Sliggoo +Goodra +Klefki +Phantump +Trevenant +Pumpkaboo +Gourgeist +Bergmite +Avalugg +Noibat +Noivern +Xerneas +Yveltal +Zygarde +Diancie