Java Knight #2
@@ -1,15 +1,379 @@
|
||||
package org.project;
|
||||
package org.project.main;
|
||||
|
||||
import org.project.location.Location;
|
||||
import org.project.entity.Entity;
|
||||
import org.project.entity.players.Knight;
|
||||
import org.project.entity.enemies.*; // import همه دشمنان
|
||||
import org.project.location.Location; // import کلاس Location
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
// TODO: ADD LOCATIONS TO YOUR GAME
|
||||
List<Location> locations = new ArrayList<>();
|
||||
public class Main
|
||||
{
|
||||
private static final Scanner scanner = new Scanner(System.in);
|
||||
private static final Random random = new Random();
|
||||
private static Knight player;
|
||||
private static List<Location> gameLocations = new ArrayList<>();
|
||||
private static Location currentLocation;
|
||||
private static Set<String> keys = new HashSet<>();
|
||||
private static boolean castleUnlocked = false;
|
||||
|
||||
// TODO: IMPLEMENT GAMEPLAY
|
||||
public static void main(String[] args)
|
||||
{
|
||||
System.out.println("Welcome to Java Knight RPG!");
|
||||
System.out.print("Enter your hero's name: ");
|
||||
String name = scanner.nextLine();
|
||||
player = new Knight(name);
|
||||
|
||||
initializeLocations();
|
||||
if (!gameLocations.isEmpty())
|
||||
{
|
||||
currentLocation = gameLocations.get(0);
|
||||
System.out.println("Your adventure begins in the " + currentLocation.getName() + "!");
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("Error: No locations initialized. Exiting.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
gameLoop();
|
||||
}
|
||||
|
||||
private static void initializeLocations()
|
||||
{
|
||||
Location forest = new Location(new ArrayList<>(), new ArrayList<>());
|
||||
forest.setName("Dark Forest");
|
||||
|
||||
Location cave = new Location(new ArrayList<>(), new ArrayList<>());
|
||||
cave.setName("Mysterious Cave");
|
||||
|
||||
Location castle = new Location(new ArrayList<>(), new ArrayList<>());
|
||||
castle.setName("Dragon's Castle");
|
||||
|
||||
forest.addEnemy(new Goblin());
|
||||
forest.addEnemy(new Skeleton());
|
||||
|
||||
cave.addEnemy(new Vampire());
|
||||
cave.addEnemy(new Skeleton());
|
||||
|
||||
forest.addAdjacentLocation(cave);
|
||||
cave.addAdjacentLocation(forest);
|
||||
cave.addAdjacentLocation(castle);
|
||||
castle.addAdjacentLocation(cave);
|
||||
|
||||
gameLocations.add(forest);
|
||||
gameLocations.add(cave);
|
||||
gameLocations.add(castle);
|
||||
}
|
||||
|
||||
private static void gameLoop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (currentLocation != null && currentLocation.hasLivingEnemies())
|
||||
{
|
||||
System.out.println("\n\u001B[33mEnemies detected in " + currentLocation.getName() + "!\u001B[0m");
|
||||
}
|
||||
|
||||
System.out.println("\n====== Main Menu ======");
|
||||
if (currentLocation != null)
|
||||
{
|
||||
System.out.println("Current Location: " + currentLocation.getName());
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("Current Location: Unknown");
|
||||
}
|
||||
System.out.println("1. Fight enemy");
|
||||
System.out.println("2. Move to another location");
|
||||
if (castleUnlocked)
|
||||
{
|
||||
System.out.println("3. Enter the Castle (Final Boss)");
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("3. Enter the Castle (Locked - Collect all keys!)");
|
||||
}
|
||||
System.out.println("4. Show player info");
|
||||
System.out.println("5. Exit game");
|
||||
System.out.print("Choose an option: ");
|
||||
|
||||
int choice = readInt(1, 5);
|
||||
switch (choice)
|
||||
{
|
||||
case 1 ->
|
||||
{
|
||||
if (currentLocation != null && currentLocation.hasLivingEnemies())
|
||||
{
|
||||
fightEnemy();
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("No enemies here to fight.");
|
||||
}
|
||||
}
|
||||
case 2 -> moveLocation();
|
||||
case 3 ->
|
||||
{
|
||||
if (currentLocation != null && currentLocation.getName().equals("Dragon's Castle") && castleUnlocked)
|
||||
{
|
||||
fightBoss();
|
||||
}
|
||||
else if (castleUnlocked)
|
||||
{
|
||||
System.out.println("You must be at the Castle entrance to enter.");
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("You need to collect all keys before entering the Castle.");
|
||||
}
|
||||
}
|
||||
case 4 -> showPlayerInfo();
|
||||
case 5 ->
|
||||
{
|
||||
System.out.println("Thanks for playing! Goodbye.");
|
||||
scanner.close();
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void fightEnemy()
|
||||
{
|
||||
if (currentLocation == null || !currentLocation.hasLivingEnemies())
|
||||
{
|
||||
System.out.println("No enemies here to fight.");
|
||||
return;
|
||||
}
|
||||
|
||||
Enemy enemy = null;
|
||||
for (Enemy e : currentLocation.getEnemies())
|
||||
{
|
||||
if (e.isAlive())
|
||||
{
|
||||
enemy = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (enemy == null)
|
||||
{
|
||||
System.out.println("No living enemies found.");
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("\nA wild " + enemy.getName() + " appears!");
|
||||
|
||||
boolean playerTurn = true;
|
||||
while (player.isAlive() && enemy.isAlive())
|
||||
{
|
||||
printStatus(player, enemy);
|
||||
if (playerTurn)
|
||||
{
|
||||
System.out.println("\nYour turn! Choose action:");
|
||||
System.out.println("1. Attack");
|
||||
System.out.println("2. Defend");
|
||||
System.out.print("Option: ");
|
||||
int act = readInt(1, 2);
|
||||
if (act == 1)
|
||||
{
|
||||
player.attack(enemy);
|
||||
}
|
||||
else
|
||||
{
|
||||
player.defend();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
enemy.attack(player);
|
||||
}
|
||||
playerTurn = !playerTurn;
|
||||
}
|
||||
|
||||
if (!player.isAlive())
|
||||
{
|
||||
System.out.println("\u001B[31mYou died! Game over.\u001B[0m");
|
||||
scanner.close();
|
||||
System.exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("\u001B[32mYou defeated " + enemy.getName() + "!\u001B[0m");
|
||||
|
||||
tryDropKey(enemy);
|
||||
|
||||
int xpGain = getXPGain(enemy);
|
||||
player.addXP(xpGain);
|
||||
player.checkLevelUp();
|
||||
|
||||
player.setHP(player.getMaxHP());
|
||||
player.setMP(player.getMaxMP());
|
||||
System.out.println("\u001B[36mYour HP and MP are fully restored.\u001B[0m");
|
||||
|
||||
currentLocation.getEnemies().remove(enemy);
|
||||
}
|
||||
}
|
||||
|
||||
private static void moveLocation()
|
||||
{
|
||||
if (currentLocation == null)
|
||||
{
|
||||
System.out.println("You are in an unknown location.");
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<Location> adjacent = currentLocation.getLocations();
|
||||
if (adjacent == null || adjacent.isEmpty())
|
||||
{
|
||||
System.out.println("There are no other locations connected to this place.");
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("\nAvailable locations to move:");
|
||||
for (int i = 0; i < adjacent.size(); i++)
|
||||
{
|
||||
System.out.println((i + 1) + ". " + adjacent.get(i).getName());
|
||||
}
|
||||
System.out.print("Choose a location to move to (or 0 to cancel): ");
|
||||
int choice = readInt(0, adjacent.size());
|
||||
if (choice == 0)
|
||||
{
|
||||
System.out.println("Movement cancelled.");
|
||||
return;
|
||||
}
|
||||
|
||||
currentLocation = adjacent.get(choice - 1);
|
||||
System.out.println("You moved to " + currentLocation.getName());
|
||||
|
||||
if (currentLocation.hasLivingEnemies())
|
||||
{
|
||||
System.out.println("\u001B[33mWatch out! There are enemies here.\u001B[0m");
|
||||
}
|
||||
}
|
||||
|
||||
private static void fightBoss()
|
||||
{
|
||||
if (currentLocation == null || !currentLocation.getName().equals("Dragon's Castle"))
|
||||
{
|
||||
System.out.println("You must be in the Dragon's Castle to fight the boss.");
|
||||
return;
|
||||
}
|
||||
|
||||
Dragon dragon = new Dragon();
|
||||
System.out.println("\nYou enter the Dragon's Lair!");
|
||||
|
||||
boolean playerTurn = true;
|
||||
while (player.isAlive() && dragon.isAlive())
|
||||
{
|
||||
printStatus(player, dragon);
|
||||
if (playerTurn)
|
||||
{
|
||||
System.out.println("\nYour turn! Choose action:");
|
||||
System.out.println("1. Attack");
|
||||
System.out.println("2. Defend");
|
||||
System.out.print("Option: ");
|
||||
int act = readInt(1, 2);
|
||||
if (act == 1)
|
||||
{
|
||||
player.attack(dragon);
|
||||
}
|
||||
else
|
||||
{
|
||||
player.defend();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dragon.attack(player);
|
||||
}
|
||||
playerTurn = !playerTurn;
|
||||
}
|
||||
|
||||
if (player.isAlive())
|
||||
{
|
||||
System.out.println("\u001B[32mCongratulations! You defeated the Dragon and won the game!\u001B[0m");
|
||||
scanner.close();
|
||||
System.exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("\u001B[31mYou died fighting the Dragon. Game over.\u001B[0m");
|
||||
scanner.close();
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
private static void showPlayerInfo()
|
||||
{
|
||||
System.out.println("\n--- Player Info ---");
|
||||
System.out.println("Name: " + player.getName());
|
||||
System.out.println("Level: " + player.level);
|
||||
System.out.println("XP: " + player.xp + " / " + player.xpToNextLevel);
|
||||
System.out.println("HP: " + player.getHP() + "/" + player.getMaxHP());
|
||||
System.out.println("MP: " + player.getMP() + "/" + player.getMaxMP());
|
||||
System.out.println("Keys collected: " + keys);
|
||||
}
|
||||
|
||||
private static int readInt(int min, int max)
|
||||
{
|
||||
int input;
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
input = Integer.parseInt(scanner.nextLine());
|
||||
if (input < min || input > max)
|
||||
{
|
||||
throw new NumberFormatException("Input out of bounds.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
System.out.print("Invalid input. Please enter a number between " + min + " and " + max + ": ");
|
||||
}
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
private static void tryDropKey(Entity enemy)
|
||||
{
|
||||
double dropChance = 0.20;
|
||||
String enemyName = enemy.getName();
|
||||
|
||||
if (keys.contains(enemyName + " Key")) {return;}
|
||||
|
||||
if (random.nextDouble() < dropChance)
|
||||
{
|
||||
keys.add(enemyName + " Key");
|
||||
System.out.println("\u001B[36mYou obtained the " + enemyName + " Key!\u001B[0m");
|
||||
}
|
||||
|
||||
if (keys.contains("Goblin Key") && keys.contains("Skeleton Key") && keys.contains("Vampire Key"))
|
||||
{
|
||||
castleUnlocked = true;
|
||||
System.out.println("\u001B[35mAll keys collected! The Castle is now unlocked!\u001B[0m");
|
||||
}
|
||||
}
|
||||
|
||||
private static int getXPGain(Entity enemy)
|
||||
{
|
||||
return switch (enemy.getName())
|
||||
{
|
||||
case "Goblin" -> 50;
|
||||
case "Skeleton" -> 40;
|
||||
case "Vampire" -> 60;
|
||||
case "Dragon" -> 500;
|
||||
default -> 50;
|
||||
};
|
||||
}
|
||||
|
||||
private static void printStatus(Entity player, Entity enemy)
|
||||
{
|
||||
System.out.println("\n[player HP: " + player.getHP() + " / " + player.getMaxHP() +
|
||||
" | MP: " + player.getMP() + " / " + player.getMaxMP() + "]");
|
||||
System.out.println("[enemy HP: " + enemy.getHP() + " / " + enemy.getMaxHP() + "]");
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,15 @@
|
||||
package org.project.entity;
|
||||
|
||||
public interface Entity {
|
||||
public interface Entity
|
||||
{
|
||||
void attack(Entity target);
|
||||
|
||||
void defend();
|
||||
|
||||
void heal(int health);
|
||||
|
||||
void fillMana(int mana);
|
||||
|
||||
void takeDamage(int damage);
|
||||
|
||||
boolean isAlive();
|
||||
int getHP();
|
||||
int getMaxHP();
|
||||
|
||||
void setHP(int hp);
|
||||
int getMP();
|
||||
int getMaxMP();
|
||||
|
||||
/*
|
||||
TODO: ADD OTHER REQUIRED AND BONUS METHODS
|
||||
*/
|
||||
void setMP(int mp);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.project.entity.enemies;
|
||||
|
||||
public class Dragon extends Enemy
|
||||
{
|
||||
|
||||
public Dragon()
|
||||
{
|
||||
super("Dragon", 200, 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attack(Entity target)
|
||||
{
|
||||
int damage = 40;
|
||||
System.out.println(name + " breathes fire for " + damage + " damage ignoring defense!");
|
||||
|
||||
if (target instanceof Player)
|
||||
{
|
||||
Player p = (Player) target;
|
||||
p.setHP(p.getHP() - damage);
|
||||
if (p.getHP() < 0)
|
||||
p.setHP(0);
|
||||
System.out.println(target.getName() + " takes " + damage + " damage!");
|
||||
}
|
||||
else
|
||||
{
|
||||
target.takeDamage(damage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,75 @@
|
||||
package org.project.entity.enemies;
|
||||
|
||||
import org.project.item.weapons.Weapon;
|
||||
import org.project.entity.Entity;
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public abstract class Enemy {
|
||||
Weapon weapon;
|
||||
private int hp;
|
||||
private int mp;
|
||||
public abstract class Enemy implements Entity
|
||||
{
|
||||
protected String name;
|
||||
|
||||
public Enemy(int hp, int mp, Weapon weapon) {
|
||||
this.hp = hp;
|
||||
this.mp = mp;
|
||||
protected int hp;
|
||||
protected int maxHP;
|
||||
protected int mp;
|
||||
protected int maxMP;
|
||||
protected boolean defending;
|
||||
|
||||
this.weapon = weapon;
|
||||
public Enemy(String name, int maxHP, int maxMP)
|
||||
{
|
||||
this.name = name;
|
||||
this.maxHP = maxHP;
|
||||
this.hp = maxHP;
|
||||
this.maxMP = maxMP;
|
||||
this.mp = maxMP;
|
||||
this.defending = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void takeDamage(int damage) {
|
||||
public boolean isAlive() {return hp > 0;}
|
||||
|
||||
@Override
|
||||
public int getHP() {return hp;}
|
||||
|
||||
@Override
|
||||
public int getMaxHP() {return maxHP;}
|
||||
|
||||
@Override
|
||||
public void setHP(int hp) {this.hp = Math.min(hp, maxHP);}
|
||||
|
||||
@Override
|
||||
public int getMP() {return mp;}
|
||||
|
||||
@Override
|
||||
public int getMaxMP() {return maxMP;}
|
||||
|
||||
@Override
|
||||
public void setMP(int mp) {this.mp = Math.min(mp, maxMP);}
|
||||
|
||||
@Override
|
||||
public void defend()
|
||||
{
|
||||
defending = true;
|
||||
System.out.println(name + " is defending and will reduce damage next turn.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void takeDamage(int damage)
|
||||
{
|
||||
if (defending)
|
||||
{
|
||||
damage /= 2;
|
||||
System.out.println(name + " defended and reduced damage to " + damage);
|
||||
defending = false;
|
||||
}
|
||||
hp -= damage;
|
||||
if (hp < 0) hp = 0;
|
||||
}
|
||||
|
||||
public int getHp() {
|
||||
return hp;
|
||||
@Override
|
||||
public void attack(Entity target)
|
||||
{
|
||||
int damage = 8;
|
||||
System.out.println(name + " attacks for " + damage + " damage!");
|
||||
target.takeDamage(damage);
|
||||
}
|
||||
|
||||
public int getMp() {
|
||||
return mp;
|
||||
}
|
||||
|
||||
public Weapon getWeapon() {
|
||||
return weapon;
|
||||
}
|
||||
public String getName() {return name;}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.project.entity.enemies;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class Goblin extends Enemy
|
||||
{
|
||||
private static final Random random = new Random();
|
||||
|
||||
public Goblin()
|
||||
{
|
||||
super("Goblin", 50, 20);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attack(Entity target)
|
||||
{
|
||||
// Goblin has 25% chance for critical hit (1.5x damage)
|
||||
int baseDamage = 10;
|
||||
double critChance = 0.25;
|
||||
int damage = baseDamage;
|
||||
|
||||
if (random.nextDouble() < critChance)
|
||||
{
|
||||
damage = (int) (baseDamage * 1.5);
|
||||
System.out.println(name + " lands a critical hit!");
|
||||
}
|
||||
System.out.println(name + " attacks for " + damage + " damage!");
|
||||
target.takeDamage(damage);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,14 @@
|
||||
package org.project.entity.enemies;
|
||||
public class Skeleton extends Enemy
|
||||
{
|
||||
public Skeleton()
|
||||
{
|
||||
super("Skeleton", 60, 15);
|
||||
}
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public class Skeleton {
|
||||
// TODO: DESIGN ENEMY AND IMPLEMENT THE CONSTRUCTOR
|
||||
@Override
|
||||
public void attack(Entity target)
|
||||
{
|
||||
System.out.println(name + " shoots a bone arrow!");
|
||||
super.attack(target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.project.entity.enemies;
|
||||
|
||||
public class Vampire extends Enemy
|
||||
{
|
||||
|
||||
public Vampire()
|
||||
{
|
||||
super("Vampire", 60, 30);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attack(Entity target)
|
||||
{
|
||||
int damage = 12;
|
||||
|
||||
System.out.println(name + " attacks for " + damage + " damage and absorbs health!");
|
||||
target.takeDamage(damage);
|
||||
|
||||
int healAmount = damage / 2;
|
||||
hp += healAmount;
|
||||
if (hp > maxHP) hp = maxHP;
|
||||
System.out.println(name + " heals for " + healAmount + " HP.");
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,13 @@
|
||||
package org.project.entity.players;
|
||||
public class Knight extends Player
|
||||
{
|
||||
public Knight(String name)
|
||||
{
|
||||
super(name, 150, 50, new Sword(), new HeavyArmor());
|
||||
}
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public class Knight {
|
||||
// TODO: DESIGN KNIGHT'S WEAPON AND ARMOR AND IMPLEMENT THE CONSTRUCTOR
|
||||
@Override
|
||||
public void defend()
|
||||
{
|
||||
System.out.println(name + " raises shield! Defense is highly increased.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,89 +1,104 @@
|
||||
package org.project.entity.players;
|
||||
|
||||
import org.project.entity.Entity;
|
||||
import org.project.item.armors.Armor;
|
||||
import org.project.item.weapons.Weapon;
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public abstract class Player {
|
||||
public abstract class Player implements Entity
|
||||
{
|
||||
protected String name;
|
||||
Weapon weapon;
|
||||
Armor armor;
|
||||
private int hp;
|
||||
private int maxHP;
|
||||
private int mp;
|
||||
private int maxMP;
|
||||
protected int level;
|
||||
protected int xp;
|
||||
protected int xpToNextLevel;
|
||||
|
||||
public Player(String name, int hp, int mp, Weapon weapon, Armor armor) {
|
||||
protected int hp;
|
||||
protected int maxHP;
|
||||
protected int mp;
|
||||
protected int maxMP;
|
||||
|
||||
protected boolean defending;
|
||||
|
||||
public Player(String name, int maxHP, int maxMP)
|
||||
{
|
||||
this.name = name;
|
||||
this.hp = hp;
|
||||
this.mp = mp;
|
||||
|
||||
this.weapon = weapon;
|
||||
this.armor = armor;
|
||||
this.level = 1;
|
||||
this.xp = 0;
|
||||
this.xpToNextLevel = 100;
|
||||
this.maxHP = maxHP;
|
||||
this.hp = maxHP;
|
||||
this.maxMP = maxMP;
|
||||
this.mp = maxMP;
|
||||
this.defending = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attack(Entity target) {
|
||||
target.takeDamage(weapon.getDamage());
|
||||
}
|
||||
public abstract void specialAbility(Entity target);
|
||||
|
||||
@Override
|
||||
public void defend() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void takeDamage(int damage) {
|
||||
hp -= damage - armor.getDefense();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void heal(int health) {
|
||||
hp += health;
|
||||
if (hp > maxHP) {
|
||||
public boolean checkLevelUp()
|
||||
{
|
||||
if (xp >= xpToNextLevel)
|
||||
{
|
||||
level++;
|
||||
xp -= xpToNextLevel;
|
||||
xpToNextLevel *= 1.5;
|
||||
maxHP += 10;
|
||||
maxMP += 5;
|
||||
hp = maxHP;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillMana(int mana) {
|
||||
mp += mana;
|
||||
if (mp > maxMP) {
|
||||
mp = maxMP;
|
||||
|
||||
System.out.println("\u001B[32m[LEVEL UP] Congratulations! You reached Level " + level + ".\u001B[0m");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addXP(int amount) {xp += amount;}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@Override
|
||||
public boolean isAlive() {return hp > 0;}
|
||||
|
||||
public int getHp() {
|
||||
return hp;
|
||||
@Override
|
||||
public int getHP() {return hp;}
|
||||
|
||||
@Override
|
||||
public int getMaxHP() {return maxHP;}
|
||||
|
||||
@Override
|
||||
public void setHP(int hp) {this.hp = Math.min(hp, maxHP);}
|
||||
|
||||
@Override
|
||||
public int getMP() {return mp;}
|
||||
|
||||
@Override
|
||||
public int getMaxMP() {return maxMP;}
|
||||
|
||||
@Override
|
||||
public void setMP(int mp) {this.mp = Math.min(mp, maxMP);}
|
||||
|
||||
@Override
|
||||
public void defend()
|
||||
{
|
||||
defending = true;
|
||||
System.out.println(name + " is defending and will reduce damage next turn.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHP() {
|
||||
return maxHP;
|
||||
}
|
||||
|
||||
public int getMp() {
|
||||
return mp;
|
||||
public void takeDamage(int damage)
|
||||
{
|
||||
if (defending)
|
||||
{
|
||||
damage /= 2;
|
||||
System.out.println(name + " defended and reduced damage to " + damage);
|
||||
defending = false;
|
||||
}
|
||||
hp -= damage;
|
||||
if (hp < 0) hp = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxMP() {
|
||||
return maxMP;
|
||||
public void attack(Entity target)
|
||||
{
|
||||
int damage = 10 + level * 2;
|
||||
System.out.println(name + " attacks for " + damage + " damage!");
|
||||
target.takeDamage(damage);
|
||||
}
|
||||
|
||||
public Weapon getWeapon() {
|
||||
return weapon;
|
||||
}
|
||||
|
||||
public Armor getArmor() {
|
||||
return armor;
|
||||
}
|
||||
|
||||
}
|
||||
public String getName() {return name;}
|
||||
}
|
||||
@@ -2,10 +2,9 @@ package org.project.item;
|
||||
|
||||
import org.project.entity.Entity;
|
||||
|
||||
public interface Item {
|
||||
public interface Item
|
||||
{
|
||||
void use(Entity target);
|
||||
|
||||
/*
|
||||
TODO: ADD OTHER REQUIRED AND BONUS METHODS
|
||||
*/
|
||||
String getName();
|
||||
String getDescription();
|
||||
}
|
||||
|
||||
@@ -1,42 +1,68 @@
|
||||
package org.project.item.armors;
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public abstract class Armor {
|
||||
public abstract class Armor
|
||||
{
|
||||
private int defense;
|
||||
private int maxDefense;
|
||||
private int durability;
|
||||
private int maxDurability;
|
||||
|
||||
private boolean isBroke;
|
||||
|
||||
public Armor(int defense, int durability) {
|
||||
public Armor(int defense, int durability)
|
||||
{
|
||||
this.defense = defense;
|
||||
this.maxDefense = defense;
|
||||
this.durability = durability;
|
||||
this.maxDurability = durability;
|
||||
this.isBroke = false;
|
||||
}
|
||||
|
||||
public void checkBreak() {
|
||||
if (durability <= 0) {
|
||||
isBroke = true;
|
||||
defense = 0;
|
||||
public void takeHit(int damageToDurability)
|
||||
{
|
||||
if (!isBroke)
|
||||
{
|
||||
durability -= damageToDurability;
|
||||
if (durability < 0) durability = 0;
|
||||
checkBreak();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: (BONUS) UPDATE THE REPAIR METHOD
|
||||
public void repair() {
|
||||
isBroke = false;
|
||||
defense = maxDefense;
|
||||
durability = maxDurability;
|
||||
public void checkBreak()
|
||||
{
|
||||
if (durability <= 0)
|
||||
{
|
||||
isBroke = true;
|
||||
defense = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
isBroke = false;
|
||||
defense = maxDefense;
|
||||
}
|
||||
}
|
||||
|
||||
public int getDefense() {
|
||||
return defense;
|
||||
public void repair()
|
||||
{
|
||||
if (isBroke)
|
||||
{
|
||||
isBroke = false;
|
||||
defense = maxDefense;
|
||||
durability = maxDurability;
|
||||
System.out.println("Armor repaired successfully!");
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("Armor is still intact. No repair needed.");
|
||||
}
|
||||
}
|
||||
|
||||
public int getDurability() {
|
||||
return durability;
|
||||
}
|
||||
public int getDefense() {return defense;}
|
||||
|
||||
public boolean isBroke() {
|
||||
return isBroke;
|
||||
}
|
||||
public int getDurability() {return durability;}
|
||||
|
||||
public boolean isBroke() {return isBroke;}
|
||||
|
||||
public int getMaxDefense() {return maxDefense;}
|
||||
|
||||
public int getMaxDurability() {return maxDurability;}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,27 @@
|
||||
package org.project.item.armors;
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public class KnightArmor {
|
||||
// TODO: DESIGN ARMOR'S ATTRIBUTES IMPLEMENT THE CONSTRUCTOR
|
||||
public class KnightArmor extends Armor
|
||||
{
|
||||
|
||||
public KnightArmor()
|
||||
{
|
||||
super(40, 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkBreak()
|
||||
{
|
||||
super.checkBreak();
|
||||
if (isBroke())
|
||||
{
|
||||
System.out.println("Knight's armor is shattered!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void repair()
|
||||
{
|
||||
super.repair();
|
||||
System.out.println("Knight's armor has been reforged by the royal blacksmith!");
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,29 @@
|
||||
package org.project.item.consumables;
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public abstract class Consumable {
|
||||
/*
|
||||
TODO: ADD OTHER REQUIRED AND BONUS METHODS
|
||||
*/
|
||||
}
|
||||
import org.project.entity.Entity;
|
||||
|
||||
public abstract class Consumable
|
||||
{
|
||||
private String name;
|
||||
private int amount;
|
||||
|
||||
public Consumable(String name, int amount)
|
||||
{
|
||||
this.name = name;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public String getName() {return name;}
|
||||
|
||||
public int getAmount() {return amount;}
|
||||
|
||||
public void setAmount(int amount) {this.amount = amount;}
|
||||
|
||||
public abstract void use(Entity target);
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return name + " (Effect amount: " + amount + ")";
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,18 @@ package org.project.item.consumables;
|
||||
|
||||
import org.project.entity.Entity;
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public class Flask {
|
||||
/*
|
||||
THIS IS AN EXAMPLE OF A CONSUMABLE DESIGN.
|
||||
*/
|
||||
public class Flask extends Consumable
|
||||
{
|
||||
public Flask()
|
||||
{
|
||||
super("Flask", 0);
|
||||
}
|
||||
|
||||
// TODO: UPDATE USE METHOD
|
||||
@Override
|
||||
public void use(Entity target) {
|
||||
target.heal(target.getMaxHP() / 10);
|
||||
public void use(Entity target)
|
||||
{
|
||||
int healAmount = target.getMaxHP() / 10;
|
||||
target.heal(healAmount);
|
||||
System.out.println(target.getName() + " used " + getName() + " and recovered " + healAmount + " HP.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,23 +4,42 @@ import org.project.entity.Entity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public class Sword {
|
||||
/*
|
||||
THIS IS AN EXAMPLE OF A WEAPON DESIGN.
|
||||
*/
|
||||
public class Sword extends Weapon
|
||||
{
|
||||
|
||||
int abilityCharge;
|
||||
private int abilityCharge;
|
||||
|
||||
public Sword() {
|
||||
// TODO: DESIGN SWORD'S ATTRIBUTES IMPLEMENT THE CONSTRUCTOR
|
||||
public Sword()
|
||||
{
|
||||
super(25, 10, 1.2, 0.15, 100);
|
||||
this.abilityCharge = 0;
|
||||
}
|
||||
|
||||
// TODO: (BONUS) UPDATE THE UNIQUE ABILITY
|
||||
public void uniqueAbility(ArrayList<Entity> targets) {
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return "Basic Sword";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription()
|
||||
{
|
||||
return "A sharp melee weapon with balanced damage and good critical chance.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uniqueAbility(Entity... targets)
|
||||
{
|
||||
abilityCharge += 2;
|
||||
for (Entity target : targets) {
|
||||
target.takeDamage(getDamage());
|
||||
|
||||
System.out.println("Sword's unique ability activated! Hitting " + targets.length + " targets.");
|
||||
|
||||
for (Entity target : targets)
|
||||
{
|
||||
if (target != null && target.isAlive())
|
||||
{
|
||||
target.takeDamage(getDamage() + 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,78 @@
|
||||
package org.project.item.weapons;
|
||||
|
||||
import org.project.entity.Entity;
|
||||
import org.project.item.Item;
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public abstract class Weapon {
|
||||
private int damage;
|
||||
private int manaCost;
|
||||
public abstract class Weapon implements Item
|
||||
{
|
||||
private final int damage;
|
||||
private final int manaCost;
|
||||
private final double attackSpeed;
|
||||
private final double critChance;
|
||||
private final int durability;
|
||||
private int currentDurability;
|
||||
|
||||
/*
|
||||
TODO: ADD OTHER REQUIRED AND BONUS ATTRIBUTES
|
||||
*/
|
||||
|
||||
public Weapon(int damage, int manaCost) {
|
||||
public Weapon(int damage, int manaCost, double attackSpeed, double critChance, int durability)
|
||||
{
|
||||
this.damage = damage;
|
||||
this.manaCost = manaCost;
|
||||
this.attackSpeed = attackSpeed;
|
||||
this.critChance = critChance;
|
||||
this.durability = durability;
|
||||
this.currentDurability = durability;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void use(Entity target) {
|
||||
target.takeDamage(damage);
|
||||
public void use(Entity target)
|
||||
{
|
||||
if (currentDurability <= 0)
|
||||
{
|
||||
System.out.println(getName() + " is broken and cannot be used.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
System.out.println("No target to attack.");
|
||||
return;
|
||||
}
|
||||
|
||||
int finalDamage = damage;
|
||||
if (Math.random() < critChance)
|
||||
{
|
||||
finalDamage *= 2;
|
||||
System.out.println("Critical hit!");
|
||||
}
|
||||
|
||||
target.takeDamage(finalDamage);
|
||||
currentDurability--;
|
||||
|
||||
System.out.println(getName() + " used on " + (target.getClass().getSimpleName()) + ", damage: " + finalDamage + ", durability left: " + currentDurability);
|
||||
if (currentDurability == 0)
|
||||
System.out.println(getName() + " is now broken!");
|
||||
}
|
||||
|
||||
public int getDamage() {
|
||||
return damage;
|
||||
public void repair()
|
||||
{
|
||||
currentDurability = durability;
|
||||
System.out.println(getName() + " repaired to full durability!");
|
||||
}
|
||||
|
||||
public int getManaCost() {
|
||||
return manaCost;
|
||||
}
|
||||
public int getDamage() {return damage;}
|
||||
|
||||
/*
|
||||
TODO: ADD OTHER REQUIRED AND BONUS METHODS
|
||||
*/
|
||||
public int getManaCost() {return manaCost;}
|
||||
|
||||
public double getAttackSpeed() {return attackSpeed;}
|
||||
|
||||
public double getCritChance() {return critChance;}
|
||||
|
||||
public int getDurability() {return durability;}
|
||||
|
||||
public int getCurrentDurability() {return currentDurability;}
|
||||
|
||||
public abstract String getName();
|
||||
|
||||
public abstract String getDescription();
|
||||
|
||||
public void uniqueAbility(Entity... targets) {}
|
||||
}
|
||||
|
||||
@@ -4,25 +4,52 @@ import org.project.entity.enemies.Enemy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Location {
|
||||
public class Location
|
||||
{
|
||||
private String name;
|
||||
|
||||
private ArrayList<Location> locations;
|
||||
private ArrayList<Enemy> enemies;
|
||||
|
||||
public Location(ArrayList<Location> locations, ArrayList<Enemy> enemies) {
|
||||
public Location(ArrayList<Location> locations, ArrayList<Enemy> enemies)
|
||||
{
|
||||
this.locations = locations;
|
||||
this.enemies = enemies;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
public String getName() {return name;}
|
||||
|
||||
public ArrayList<Location> getLocations() {return locations;}
|
||||
|
||||
public ArrayList<Enemy> getEnemies() {return enemies;}
|
||||
|
||||
public void setName(String name) {this.name = name;}
|
||||
|
||||
public void addAdjacentLocation(Location location)
|
||||
{
|
||||
if (this.locations == null)
|
||||
{
|
||||
this.locations = new ArrayList<>();
|
||||
}
|
||||
this.locations.add(location);
|
||||
}
|
||||
|
||||
public ArrayList<Location> getLocations() {
|
||||
return locations;
|
||||
public void addEnemy(Enemy enemy)
|
||||
{
|
||||
if (this.enemies == null)
|
||||
{
|
||||
this.enemies = new ArrayList<>();
|
||||
}
|
||||
this.enemies.add(enemy);
|
||||
}
|
||||
|
||||
public ArrayList<Enemy> getEnemies() {
|
||||
return enemies;
|
||||
public boolean hasLivingEnemies()
|
||||
{
|
||||
if (this.enemies == null) {return false;}
|
||||
|
||||
for (Enemy enemy : enemies)
|
||||
{
|
||||
if (enemy.isAlive()) {return true;}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
# ⚔️ Java Knight RPG
|
||||
|
||||
## 🎮 Introduction
|
||||
Java Knight is a text-based RPG game developed in Java using Object-Oriented Programming principles.
|
||||
The player explores different locations, fights enemies, collects keys, gains experience, and becomes stronger throughout the adventure.
|
||||
Each enemy has unique abilities, and the final goal is to defeat the Dragon Boss and complete the quest.
|
||||
|
||||
---
|
||||
|
||||
# 🛠️ Compile & Run
|
||||
|
||||
## ✅ Compile
|
||||
Open the terminal in the project folder and run:
|
||||
|
||||
```bash
|
||||
javac *.java
|
||||
```
|
||||
|
||||
## ▶️ Run
|
||||
After compiling, start the game using:
|
||||
|
||||
```bash
|
||||
java Main
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 🧩 Classes & OOP Design
|
||||
|
||||
## 🧱 Entity
|
||||
The base class of all living characters in the game.
|
||||
It contains common attributes such as:
|
||||
- Name
|
||||
- Health
|
||||
- Damage
|
||||
- Defense
|
||||
|
||||
This class demonstrates:
|
||||
- Inheritance
|
||||
- Encapsulation
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Player
|
||||
Represents the main playable character.
|
||||
The player can:
|
||||
- Fight enemies
|
||||
- Gain XP
|
||||
- Level up
|
||||
- Collect keys
|
||||
- Move between locations
|
||||
|
||||
Concepts used:
|
||||
- Encapsulation
|
||||
- Method overriding
|
||||
- State management
|
||||
|
||||
---
|
||||
|
||||
## ⚔️ Knight
|
||||
A specialized version of the Player class with stronger combat abilities and better starting stats.
|
||||
|
||||
Concepts used:
|
||||
- Inheritance
|
||||
- Polymorphism
|
||||
|
||||
---
|
||||
|
||||
## 👾 Enemy
|
||||
Base class for all enemy types in the game.
|
||||
Defines common enemy behavior such as:
|
||||
- Attacking
|
||||
- Taking damage
|
||||
- Health management
|
||||
|
||||
Concepts used:
|
||||
- Abstraction
|
||||
- Inheritance
|
||||
|
||||
---
|
||||
|
||||
## 💀 Skeleton
|
||||
A simple enemy with balanced combat stats.
|
||||
|
||||
---
|
||||
|
||||
## 👹 Goblin
|
||||
A fast enemy with a chance to deal critical damage.
|
||||
|
||||
---
|
||||
|
||||
## 🧛 Vampire
|
||||
An enemy capable of stealing health from the player during combat.
|
||||
|
||||
---
|
||||
|
||||
## 🐉 Dragon
|
||||
The final boss of the game with powerful attacks that can ignore defense.
|
||||
|
||||
---
|
||||
|
||||
## 📍 Location
|
||||
Handles the world map and movement system.
|
||||
Each location contains:
|
||||
- Enemies
|
||||
- Connected locations
|
||||
- Exploration logic
|
||||
|
||||
Concepts used:
|
||||
- Object relationships
|
||||
- Composition
|
||||
|
||||
---
|
||||
|
||||
## 🎒 Item
|
||||
Represents collectible and usable objects inside the game.
|
||||
Items can help the player by:
|
||||
- Restoring health
|
||||
- Increasing power
|
||||
- Supporting progression
|
||||
|
||||
Concepts used:
|
||||
- Encapsulation
|
||||
- Object interaction
|
||||
|
||||
---
|
||||
|
||||
# 🧠 OOP Principles Used
|
||||
|
||||
- ✅ Inheritance
|
||||
- ✅ Encapsulation
|
||||
- ✅ Polymorphism
|
||||
- ✅ Abstraction
|
||||
|
||||
The project is fully designed using Object-Oriented Programming to make the code modular, reusable, and easier to maintain.
|
||||
|
||||
---
|
||||
|
||||
# 🎯 How to Play
|
||||
|
||||
## 🎮 Controls
|
||||
The game is menu-based.
|
||||
Players select actions by entering numbers in the terminal.
|
||||
|
||||
Example actions:
|
||||
- Attack enemy
|
||||
- View stats
|
||||
- Move to another location
|
||||
- Continue exploration
|
||||
|
||||
---
|
||||
|
||||
## 📊 Player Stats
|
||||
|
||||
### ❤️ Health
|
||||
Determines how much damage the player can survive.
|
||||
|
||||
### ⚔️ Damage
|
||||
Controls attack power against enemies.
|
||||
|
||||
### 🛡️ Defense
|
||||
Reduces incoming damage.
|
||||
|
||||
### ✨ XP
|
||||
Earned after defeating enemies and used for leveling up.
|
||||
|
||||
### 🔑 Keys
|
||||
Required to unlock progression and reach the final boss.
|
||||
|
||||
---
|
||||
|
||||
## 🌍 Gameplay Flow
|
||||
|
||||
1. Start the game
|
||||
2. Explore locations
|
||||
3. Fight enemies
|
||||
4. Gain XP and level up
|
||||
5. Collect keys
|
||||
6. Reach the Dragon Castle
|
||||
7. Defeat the Dragon Boss
|
||||
|
||||
---
|
||||
|
||||
# 👩💻 Credits
|
||||
|
||||
Developed with Java and Object-Oriented Programming concepts.
|
||||
|
||||
Made by Romina
|
||||
Reference in New Issue
Block a user