// Bravean Ketheeswaran
// TEJ4M
// April 16, 2025
// Pokemon Adventure: Sinnoh Quest
// This is a text-based Pokemon-style game played through the Serial Monitor.
// You pick your starter, fight wild Pokemon, level up, and face a gym leader.
// The game includes difficulty levels and becomes progressively harder.
// All gameplay is managed through functions and makes use of arrays, loops, conditions, and user input.
// Basic setup for the game's core variables
String trainerName = ""; // Stores the name of the player
String playerPokemon = ""; // The name of the player's chosen Pokémon
String playerMove = ""; // The attack move the player's Pokémon uses
int playerHP = 0; // Current health points of the player's Pokémon
int maxPlayerHP = 0; // Maximum health points for the player's Pokémon
int playerLevel = 1; // Tracks the player's Pokémon level
int playerXP = 0; // Experience points for leveling up
int badgeCount = 0; // Number of badges earned from gym battles
bool gameStarted = false; // Tracks whether the game has started
int starterChoice = 0; // Tracks which starter Pokémon the player selected
int gymAttempts = 0; // Number of attempts at the gym leader battle
int difficulty = 1; // Game difficulty: 1 = Easy, 2 = Normal, 3 = Hard
// Defines the starter Pokémon options with their respective moves and stats
String starters[3][2] = {
{"Chimchar", "Ember"}, // Fire-type starter Pokémon
{"Piplup", "Bubble"}, // Water-type starter Pokémon
{"Turtwig", "Razor Leaf"} // Grass-type starter Pokémon
};
int starterHPs[3] = {44, 53, 55}; // Starting health points for each Pokémon
// Defines the wild Pokémon pool and their respective moves
String wildPokemon[6][2] = {
{"Starly", "Tackle"}, // Flying-type Pokémon
{"Shinx", "Bite"}, // Electric-type Pokémon
{"Bidoof", "Headbutt"}, // Normal-type Pokémon
{"Ponyta", "Flame Wheel"}, // Fire-type Pokémon
{"Zubat", "Wing Attack"}, // Poison/Flying-type Pokémon
{"Machop", "Karate Chop"} // Fighting-type Pokémon
};
// Defines the gym leader and their Pokémon for the final challenge
String gymLeader = "Zara"; // Name of the gym leader
String gymPokemon = "Luxio"; // The gym leader's Pokémon
String gymMove = "Spark"; // The attack move used by the gym leader's Pokémon
int gymHP = 70; // Initial health points of the gym leader's Pokémon
// Setup function initializes the game and sets up the Serial Monitor
void setup() {
Serial.begin(115200); // Initializes communication with the Serial Monitor
randomSeed(analogRead(A0)); // Seeds random number generation for game events
delay(1000); // Short delay before displaying the main menu
mainMenu(); // Displays the main menu
}
void loop() {} // The main game logic is handled through functions, so no need for a continuous loop
// Displays the main menu and handles player choices
void mainMenu() {
Serial.println("\n=== POKEMON ADVENTURE: SINNOH QUEST ===");
Serial.println("1. Start Game"); // Start a new game
Serial.println("2. Help"); // View game instructions
Serial.println("3. Exit"); // Exit the game
Serial.println("Choose: ");
int choice = getValidInput(1, 3); // Ensures valid input between 1 and 3
switch (choice) {
case 1: startGame(); break; // Starts the main game
case 2: helpMenu(); break; // Displays the help menu
case 3: Serial.println("Good game. Goodbye trainer!"); break; // Ends the program
}
}
// Provides instructions on how to play the game
void helpMenu() {
Serial.println("\n=== HELP MENU ===");
Serial.println("- Pick a starter Pokémon to begin your journey.");
Serial.println("- Battle wild Pokémon to gain experience and level up.");
Serial.println("- You can catch wild Pokémon more easily when their HP is low.");
Serial.println("- Reach level 3 to challenge the gym leader.");
delay(2500); // Gives the player time to read the instructions
mainMenu(); // Returns to the main menu
}
// Main function to start the game
void startGame() {
selectDifficulty(); // Lets the player select a difficulty level
getTrainerName(); // Prompts the player to enter their name
chooseStarter(); // Allows the player to select their starter Pokémon
meetOpps(); // Introduces the player's rival
encounterWildPokemon(); // Starts wild Pokémon encounters
}
// Allows the player to select a difficulty level
void selectDifficulty() {
Serial.println("Choose your difficulty:");
Serial.println("1. Easy"); // Lower difficulty for casual play
Serial.println("2. Normal"); // Balanced difficulty
Serial.println("3. Hard"); // Higher difficulty for a greater challenge
Serial.print("Choice: ");
difficulty = getValidInput(1, 3); // Ensures input is within valid range
}
// Prompts the player to enter their trainer name
void getTrainerName() {
Serial.println("PROF. MEESHA: Welcome trainer! What's your name?");
while (Serial.available() == 0) {} // Waits for the player to input their name
trainerName = Serial.readString(); // Reads the player's input
}
// Lets the player pick one of the three starter Pokémon
void chooseStarter() {
Serial.print("PROF. MEESHA: Hello " + trainerName);
Serial.println("! Time to choose your starter Pokémon!");
for (int i = 0; i < 3; i++) {
Serial.println(String(i + 1) + ". " + starters[i][0] + " (Move: " + starters[i][1] + ", HP: " + starterHPs[i] + ")");
}
Serial.println("Pick 1-3: ");
delay(2500);
starterChoice = getValidInput(1, 3) - 1; // Stores the player's selection (adjusted for 0-indexing)
playerPokemon = starters[starterChoice][0]; // Assigns the selected Pokémon
playerMove = starters[starterChoice][1]; // Assigns the corresponding attack move
playerHP = starterHPs[starterChoice]; // Sets the Pokémon's starting HP
maxPlayerHP = playerHP; // Updates the max HP
Serial.println("PROF. MEESHA: Nice! You picked " + playerPokemon + ".");
delay(2500);
}
// Rival introduction - establishes some friendly competition
void meetOpps() {
Serial.println("GURT (RIVAL): So you're starting your journey too?");
Serial.println("GURT: I picked the one strong against yours! Haha!");
Serial.println("GURT: Catch up if you can!");
gameStarted = true; // Marks the game as officially started
delay(2000);
}
// Handles encounters with wild Pokémon
void encounterWildPokemon() {
int wildIndex = random(0, 6); // Randomly selects one of the wild Pokémon
String wildName = wildPokemon[wildIndex][0]; // Gets the name of the wild Pokémon
String wildMove = wildPokemon[wildIndex][1]; // Gets the wild Pokémon's attack move
int wildHP = 35 + random(0, 20) + (difficulty * 5); // Calculates the wild Pokémon's HP based on difficulty
Serial.println("A wild " + wildName + " appeared!"); // Displays the encounter
delay(2500);
battle(wildName, wildMove, wildHP); // Initiates the battle with the wild Pokémon
}
// Handles the battle mechanics between the player's Pokémon and an opponent (wild or gym Pokémon)
void battle(String enemy, String move, int hp) {
while (hp > 0 && playerHP > 0) { // Continue battle until one side's HP drops to 0
Serial.println("Choose an action:");
Serial.println("1. Attack"); // Option to deal damage to the opponent
Serial.println("2. Throw Pokeball"); // Option to try to catch the opponent (wild Pokémon only)
Serial.print("Choice: ");
int action = getValidInput(1, 2); // Ensures a valid choice is made
if (action == 1) { // Player attacks
int damage = 12 + random(5, 10); // Calculates random damage within a range
hp -= damage; // Subtracts damage from opponent's HP
Serial.println(playerPokemon + " used " + playerMove + "! " + enemy + " lost " + damage + " HP.");
if (hp <= 0) { // Checks if the opponent's HP has dropped to 0
Serial.println("You defeated " + enemy + "!");
playerXP += 10; // Awards XP for defeating the opponent
if (playerXP >= (20 + difficulty * 10)) levelUp(); // Player levels up if enough XP is earned
break; // Ends the battle
}
int enemyDamage = 3 + random(0, 5 + difficulty); // Calculates opponent's attack damage
playerHP -= enemyDamage; // Subtracts damage from player's Pokémon HP
Serial.println(enemy + " used " + move + "! Your " + playerPokemon + " lost " + enemyDamage + " HP.");
} else { // Player attempts to catch the opponent
if (tryCatch(enemy, hp)) break; // Ends the encounter if the Pokémon is caught successfully
}
}
if (playerHP <= 0) { // Checks if the player's Pokémon fainted
Serial.println("Your Pokémon fainted... Game Over.");
gameStarted = false; // Marks the game as over
mainMenu(); // Returns to the main menu
} else {
playerHP = maxPlayerHP * 0.75; // Heals the player's Pokémon partially after battle
Serial.println("Your " + playerPokemon + " is patched up a bit!");
if (playerLevel >= 3 && badgeCount == 0) { // Unlocks the gym challenge if the player reaches level 3
gymBattle();
} else {
delay(1000); // Short pause before continuing
encounterWildPokemon(); // Initiates another wild Pokémon encounter
}
}
}
// Attempts to catch a Pokémon during a battle
bool tryCatch(String enemy, int hp) {
int chance = 90 - hp; // Catching chance increases as the opponent's HP decreases
if (chance > 90) chance = 90; // Caps maximum catch chance at 90%
if (chance < 30) chance = 30; // Ensures minimum catch chance is 30%
if (random(100) < chance) { // Checks if random roll succeeds based on chance
Serial.println("Success! You caught the wild " + enemy + "!");
return true; // Pokémon is caught
}
Serial.println("It broke free!"); // Catching attempt fails
return false;
}
// Handles the gym battle sequence
void gymBattle() {
Serial.println("GYM LEADER " + gymLeader + ": Ready for a real challenge, " + trainerName + "?");
while (gymAttempts < 3 && badgeCount == 0) { // Player has three chances to defeat the gym leader
delay(2500); // Pause before battle begins
int currentGymHP = gymHP + (gymAttempts * 10) + (difficulty * 10); // Gym Pokémon's HP increases with attempts and difficulty
playerHP = maxPlayerHP * 0.75; // Partially restores player's Pokémon's HP before battle
if (playerHP < 1) playerHP = 1; // Ensures player's Pokémon has at least 1 HP
Serial.println(gymLeader + " sent out " + gymPokemon + "! (HP: " + String(currentGymHP) + ")");
while (currentGymHP > 0 && playerHP > 0) { // Continue gym battle until one side's HP drops to 0
Serial.println("Choose an action:");
Serial.println("1. Attack"); // Only attack option available for gym battles
Serial.print("Choice: ");
int action = getValidInput(1, 1); // Ensures valid choice
int playerDamage = 12 + random(5, 10); // Calculates player's attack damage
currentGymHP -= playerDamage; // Subtracts damage from gym Pokémon's HP
Serial.println(playerPokemon + " used " + playerMove + "! " + gymPokemon + " lost " + playerDamage + " HP.");
if (currentGymHP <= 0) { // Checks if gym Pokémon's HP has dropped to 0
Serial.println(gymPokemon + " fainted!");
badgeCount++; // Awards the badge for victory
break; // Ends the gym battle
}
int baseDamage = 10 + random(0, 7) + gymAttempts + difficulty; // Calculates gym Pokémon's attack damage
bool crit = random(100) < 15; // Checks for critical hit
if (crit) {
baseDamage *= 2; // Doubles damage for critical hits
Serial.println("CRITICAL HIT!");
}
playerHP -= baseDamage; // Subtracts damage from player's Pokémon's HP
Serial.println(gymPokemon + " used " + gymMove + "! Your " + playerPokemon + " lost " + baseDamage + " HP.");
}
if (playerHP > 0 && badgeCount > 0) { // Checks if player won the gym battle
Serial.println("You beat Zara! You got the Spark Badge!");
if (difficulty == 3) { // Adds an extra challenge for Hard difficulty
Serial.println("Zara: You thought I was done? Go, Onix!");
battle("Onix", "Rock Throw", 80 + difficulty * 10); // Bonus battle with Onix
}
Serial.println("Congrats " + trainerName + "! THE END");
return; // Ends the game after victory
} else {
gymAttempts++; // Tracks failed attempts
if (gymAttempts < 3) {
Serial.println("You lost the gym battle... but you can try again. Luxio just got stronger.");
} else {
Serial.println("You lost 3 times... Game Over.");
gameStarted = false; // Marks the game as over
mainMenu(); // Returns to the main menu
return;
}
}
}
}
// Handles leveling up the player's Pokémon
void levelUp() {
playerLevel++; // Increases level by 1
playerXP = 0; // Resets XP after leveling up
maxPlayerHP += 6; // Boosts max HP
playerHP = maxPlayerHP; // Fully heals the player's Pokémon
Serial.println("Your " + playerPokemon + " leveled up to level " + String(playerLevel) + "!");
Serial.println("Your HP is now " + String(maxPlayerHP));
}
// Validates player input to ensure it falls within a specified range
int getValidInput(int min, int max) {
int input;
while (true) { // Repeats until valid input is provided
while (Serial.available() == 0) {} // Waits for input from player
input = Serial.parseInt(); // Reads integer input
if (input >= min && input <= max) break; // Checks if input is within range
Serial.print("Enter a valid number (" + String(min) + "-" + String(max) + "): "); // Prompts for valid input
}
return input; // Returns the validated input
}