This commit is contained in:
2026-05-19 11:48:51 +03:30
parent 78d4bedb08
commit fa56a58cea
51 changed files with 1735 additions and 170 deletions
@@ -0,0 +1,25 @@
package org.project;
import org.project.entity.players.Player;
import org.project.location.Location;
import java.io.Serializable;
public class GameState implements Serializable {
private static final long serialVersionUID = 1L;
private Player player;
private Location currentLocation;
public GameState(Player player, Location currentLocation) {
this.player = player;
this.currentLocation = currentLocation;
}
public Player getPlayer() {
return player;
}
public Location getCurrentLocation() {
return currentLocation;
}
}
+292 -6
View File
@@ -1,15 +1,301 @@
package org.project;
import org.project.combat.CombatSystem;
import org.project.entity.Entity;
import org.project.entity.enemies.Dragon;
import org.project.entity.enemies.Goblin;
import org.project.entity.enemies.Skeleton;
import org.project.entity.enemies.Vampire;
import org.project.entity.players.*;
import org.project.location.Location;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO: ADD LOCATIONS TO YOUR GAME
List<Location> locations = new ArrayList<>();
// TODO: IMPLEMENT GAMEPLAY
private static final Scanner scanner = new Scanner(System.in);
private static Location currentLocation;
public static final String RESET = "\u001B[0m";
public static final String RED = "\u001B[31m";
public static final String GREEN = "\u001B[32m";
public static final String YELLOW = "\u001B[33m";
public static final String BLUE = "\u001B[34m";
public static final String PURPLE = "\u001B[35m";
public static final String CYAN = "\u001B[36m";
public static void main(String[] args) {
initializeMap();
while (true) {
System.out.println(CYAN + "\n===============================" + RESET);
System.out.println(YELLOW + " ⚔ JAVA KNIGHT ⚔" + RESET);
System.out.println(CYAN + "===============================" + RESET);
System.out.println("1. Start Game");
System.out.println("2. How To Play");
System.out.println("3. Exit");
System.out.print("> ");
int option = scanner.nextInt();
switch (option) {
case 1 -> startGame();
case 2 -> showHelpMenu();
case 3 -> {
System.out.println(GREEN + "Farewell hero!" + RESET);
System.exit(0);
}
default -> System.out.println(RED + "Invalid option!" + RESET);
}
}
}
private static void startGame()
{
showIntro();
System.out.print("Enter your name: ");
String name = scanner.next();
System.out.println("\nChoose your class:");
System.out.println(BLUE + "1. Knight 🛡" + RESET);
System.out.println(PURPLE + "2. Wizard 🔮" + RESET);
System.out.println(YELLOW + "3. Assassin 🗡" + RESET);
int choice = scanner.nextInt();
Player player;
switch (choice) {
case 1 -> player = new Knight(name);
case 2 -> player = new Wizard(name);
case 3 -> player = new Assassin(name);
default -> player = new Knight(name);
}
player.resetKeys();
System.out.println(GREEN + "\nWelcome " + name + " to Javanest!" + RESET);
currentLocation.enter();
gameLoop(player);
}
private static void gameLoop(Player player)
{
Random random = new Random();
while (player.isAlive())
{
showPlayerStatus(player);
System.out.println(CYAN + "\n===== LOCATION: " + currentLocation.getName() + " =====" + RESET);
System.out.println("1. Fight Enemy");
System.out.println("2. Move Location");
if (player.hasAllKeys() && currentLocation.getName().equals("Vampire Crypt"))
{
System.out.println(RED + "3. Enter Dragon Castle 🐉" + RESET);
}
System.out.print("> ");
int option = scanner.nextInt();
if (option == 1) {
Entity enemy = currentLocation.spawnEnemy();
System.out.println(RED + "\nA wild " + enemy.getName() + " appears!" + RESET);
CombatSystem combat = new CombatSystem();
combat.startBattle(player, enemy);
if (!player.isAlive()) {
System.out.println(RED + "\nYou have fallen..." + RESET);
break;
}
tryToDropKey(player, enemy, random);
recoverPlayer(player);
} else if (option == 2) {
moveLocation();
} else if (option == 3 &&
player.hasAllKeys() &&
currentLocation.getName().equals("Vampire Crypt")) {
System.out.println(RED + "\nYou enter the Dragon Castle..." + RESET);
CombatSystem combat = new CombatSystem();
combat.startBattle(player, new Dragon());
if (player.isAlive()) {
System.out.println(GREEN + "\n🏆 YOU SAVED JAVANEST!" + RESET);
} else {
System.out.println(RED + "\nThe Dragon has defeated you..." + RESET);
}
showProjectFeatures();
break;
} else {
System.out.println(RED + "Invalid option!" + RESET);
}
}
}
private static void showPlayerStatus(Player player) {
System.out.println(YELLOW + "\n===== PLAYER STATUS =====" + RESET);
printBar("HP ", player.getHP(), player.getMaxHP(), RED);
printBar("MP ", player.getMP(), player.getMaxMP(), BLUE);
System.out.println("XP: " + player.getXP());
}
private static void printBar(String label, int value, int max, String color)
{
int totalBars = 20;
int filled = (int)((double)value / max * totalBars);
StringBuilder bar = new StringBuilder();
for (int i = 0; i < filled; i++) bar.append("");
for (int i = filled; i < totalBars; i++) bar.append("");
System.out.println(label + " " + color + bar + RESET + " " + value + "/" + max);
}
private static void moveLocation()
{
System.out.println(YELLOW + "\nWhere do you want to go?" + RESET);
int index = 1;
for (Location loc : currentLocation.getConnectedLocations())
{
System.out.println(index + ". " + loc.getName());
index++;
}
System.out.print("> ");
int choice = scanner.nextInt();
if (choice < 1 || choice > currentLocation.getConnectedLocations().size())
{
System.out.println(RED + "Invalid location!" + RESET);
return;
}
currentLocation = currentLocation.getConnectedLocations().get(choice - 1);
currentLocation.enter();
}
private static void tryToDropKey(Player player, Entity enemy, Random random)
{
int chance = random.nextInt(100) + 1;
if (chance <= 20)
{
if (enemy instanceof Goblin && !player.hasGoblinKey())
{
player.obtainGoblinKey();
System.out.println(YELLOW + "You obtained the Goblin Key!" + RESET);
} else if (enemy instanceof Skeleton && !player.hasSkeletonKey()) {
player.obtainSkeletonKey();
System.out.println(YELLOW + "You obtained the Skeleton Key!" + RESET);
} else if (enemy instanceof Vampire && !player.hasVampireKey()) {
player.obtainVampireKey();
System.out.println(YELLOW + "You obtained the Vampire Key!" + RESET);
}
}
}
private static void recoverPlayer(Player player)
{
player.setHealth(player.getMaxHP());
player.setMana(player.getMaxMP());
System.out.println(GREEN + "You recovered your HP and Mana." + RESET);
}
private static void showIntro()
{
System.out.println(PURPLE + "\n====================================" + RESET);
System.out.println(YELLOW + " LEGEND OF JAVANEST" + RESET);
System.out.println(PURPLE + "====================================" + RESET);
System.out.println("Defeat enemies, collect keys,");
System.out.println("and face the mighty Dragon!");
}
private static void showHelpMenu()
{
System.out.println(YELLOW + "\nHOW TO PLAY:" + RESET);
System.out.println("- Fight enemies to gain XP.");
System.out.println("- Collect 3 keys.");
System.out.println("- Unlock Dragon Castle.");
System.out.println("- Defeat the Dragon to win.");
}
private static void showProjectFeatures()
{
System.out.println(CYAN + "\n====================================" + RESET);
System.out.println(YELLOW + " PROJECT FEATURES" + RESET);
System.out.println(CYAN + "====================================" + RESET);
System.out.println(GREEN + "✔ Multiple Player Classes" + RESET);
System.out.println(GREEN + "✔ Location System" + RESET);
System.out.println(GREEN + "✔ Key Collection System" + RESET);
System.out.println(GREEN + "✔ Combat System" + RESET);
System.out.println(GREEN + "✔ Final Boss Battle" + RESET);
}
private static void initializeMap()
{
Location forest = new Location(
"Forest",
"A dark forest full of goblins.",
1
);
Location graveyard = new Location(
"Graveyard",
"An abandoned graveyard with skeletons.",
2
);
Location vampireCrypt = new Location(
"Vampire Crypt",
"A cursed crypt where vampires sleep.",
3
);
Location dragonCastle = new Location(
"Dragon Castle",
"The castle of the ancient dragon.",
4
);
forest.connectLocation(graveyard);
graveyard.connectLocation(forest);
graveyard.connectLocation(vampireCrypt);
vampireCrypt.connectLocation(graveyard);
vampireCrypt.connectLocation(dragonCastle);
currentLocation = forest;
}
}
@@ -0,0 +1,166 @@
package org.project.combat;
import org.project.entity.players.Player;
import org.project.entity.Entity;
import org.project.entity.enemies.Goblin;
import org.project.entity.enemies.Skeleton;
import org.project.entity.enemies.Vampire;
import java.util.Scanner;
public class CombatSystem
{
private static final String RESET = "\u001B[0m";
private static final String RED = "\u001B[31m";
private static final String GREEN = "\u001B[32m";
private static final String YELLOW = "\u001B[33m";
private static final String BLUE = "\u001B[34m";
private Scanner scanner = new Scanner(System.in);
public void startBattle(Player player, Entity enemy)
{
System.out.println(RED + "\n⚔️ A battle has started!" + RESET);
System.out.println(YELLOW + "Enemy: " + enemy.getName() + RESET);
while (player.isAlive() && enemy.isAlive())
{
System.out.println("\n" + BLUE + "----- YOUR TURN -----" + RESET);
System.out.println("1. Light Attack");
System.out.println("2. Heavy Attack");
System.out.println("3. Defend");
System.out.println("4. Heal");
System.out.println("5. Special Ability");
System.out.println("6. Exit Game");
while (!scanner.hasNextInt())
{
scanner.next();
System.out.println("❌ Please enter a number between 1-6");
}
int choice = scanner.nextInt();
switch (choice)
{
case 1:
player.lightAttack(enemy);
break;
case 2:
player.heavyAttack(enemy);
break;
case 3:
player.defend();
break;
case 4:
player.specialAbility(enemy);
break;
case 5:
if (player.getMP() >= 6)
{
player.heal(10);
player.fillMana(-6);
System.out.println("💚 You restored 10 HP at the cost of 6 MP!");
} else {
System.out.println("❌ Not enough MP to heal!");
}
break;
case 6:
if (player.getXP() >= 10)
{
player.gainXP(-10);
player.fillMana(20);
System.out.println("🔮 +20 MP restored (Cost: 10 XP)");
} else {
System.out.println("❌ Not enough XP to restore mana!");
}
break;
case 7:
if (player.getXP() >= 50)
{
player.gainXP(-50);
player.heal(30);
System.out.println("❤️ +30 HP restored (Cost: 50 XP)");
} else {
System.out.println("❌ Not enough XP to restore HP!");
}
break;
case 8:
System.out.println("👋 Exiting game...");
System.exit(0);
default:
System.out.println("❌ Invalid choice!");
}
if (!enemy.isAlive())
{
System.out.println(GREEN + "\n✅ Enemy defeated!" + RESET);
player.gainXP(50);
dropKey(player, enemy);
recoverPlayer(player);
break;
}
System.out.println(RED + "\n👹 ENEMY TURN!" + RESET);
enemy.attack(player);
if (!player.isAlive())
{
System.out.println(RED + "\n💀 You were defeated..." + RESET);
}
}
}
private void dropKey(Player player, Entity enemy)
{
double chance = Math.random();
if (chance > 0.20) return;
if (enemy instanceof Goblin && !player.hasGoblinKey())
{
System.out.println(YELLOW + "🗝️ Goblin Key obtained!" + RESET);
player.obtainGoblinKey();
}
else if (enemy instanceof Skeleton && !player.hasSkeletonKey())
{
System.out.println(YELLOW + "🗝️ Skeleton Key obtained!" + RESET);
player.obtainSkeletonKey();
}
else if (enemy instanceof Vampire && !player.hasVampireKey())
{
System.out.println(YELLOW + "🗝️ Vampire Key obtained!" + RESET);
player.obtainVampireKey();
}
}
private void recoverPlayer(Player player)
{
player.setHealth(player.getMaxHP());
player.setMana(player.getMaxMP());
System.out.println("\u001B[32m✨ Your HP and Mana have been fully restored!\u001B[0m");
}
}
@@ -1,6 +1,7 @@
package org.project.entity;
public interface Entity {
public interface Entity
{
void attack(Entity target);
void defend();
@@ -11,9 +12,22 @@ public interface Entity {
void takeDamage(int damage);
int getHP();
int getMP();
int getMaxHP();
int getMaxMP();
int getLevel();
String getName();
void setStunned(boolean value);
boolean isStunned();
void setInvisible(boolean value);
boolean isInvisible();
boolean isAlive();
void gainXP(int xp);
/*
TODO: ADD OTHER REQUIRED AND BONUS METHODS
@@ -0,0 +1,38 @@
package org.project.entity.enemies;
import org.project.entity.Entity;
import org.project.item.weapons.BasicWeapon;
import java.util.Random;
public class Dragon extends Enemy
{
private Random random = new Random();
public Dragon()
{
super("Dragon", 200, 50, new BasicWeapon("Flame Breath", 25));
}
@Override
public void attack(Entity target)
{
int damage;
if (random.nextBoolean())
{
damage = weapon.getDamage() + 20;
System.out.println(RED + "🔥 Dragon uses FIRE BREATH!" + RESET);
} else {
damage = weapon.getDamage();
System.out.println(YELLOW + "🐉 Dragon claws viciously!" + RESET);
}
target.takeDamage(damage);
System.out.println(RED + "💥 Dragon deals "
+ damage + " damage!" + RESET);
}
}
@@ -1,34 +1,140 @@
package org.project.entity.enemies;
import org.project.entity.Entity;
import org.project.item.weapons.Weapon;
// TODO: UPDATE IMPLEMENTATION
public abstract class Enemy {
Weapon weapon;
private int hp;
private int mp;
public abstract class Enemy implements Entity
{
public Enemy(int hp, int mp, Weapon weapon) {
protected String name;
protected int hp;
protected int mp;
protected int maxHp;
protected int maxMp;
protected int level;
protected boolean stunned;
protected boolean invisible;
protected Weapon weapon;
protected static final String RESET = "\u001B[0m";
protected static final String RED = "\u001B[31m";
protected static final String YELLOW = "\u001B[33m";
protected static final String PURPLE = "\u001B[35m";
public Enemy(String name, int hp, int mp, Weapon weapon)
{
this.name = name;
this.hp = hp;
this.mp = mp;
this.maxHp = hp;
this.maxMp = mp;
this.level = 1;
this.stunned = false;
this.invisible = false;
this.weapon = weapon;
}
@Override
public void takeDamage(int damage) {
hp -= damage;
public void defend()
{
System.out.println(name + " defends.");
}
public int getHp() {
@Override
public void heal(int health)
{
if (health <= 0) return;
hp += health;
if (hp > maxHp) hp = maxHp;
}
@Override
public void fillMana(int mana)
{
if (mana <= 0) return;
mp += mana;
if (mp > maxMp) mp = maxMp;
}
@Override
public void takeDamage(int damage)
{
if (damage <= 0) return;
hp -= damage;
if (hp < 0) hp = 0;
}
@Override
public int getHP()
{
return hp;
}
public int getMp() {
@Override
public int getMP()
{
return mp;
}
public Weapon getWeapon() {
return weapon;
@Override
public int getMaxHP()
{
return maxHp;
}
@Override
public int getMaxMP()
{
return maxMp;
}
@Override
public int getLevel()
{
return level;
}
@Override
public String getName()
{
return name;
}
@Override
public void setStunned(boolean value)
{
this.stunned = value;
}
@Override
public boolean isStunned()
{
return stunned;
}
@Override
public void setInvisible(boolean value)
{
this.invisible = value;
}
@Override
public boolean isInvisible()
{
return invisible;
}
@Override
public boolean isAlive()
{
return hp > 0;
}
@Override
public void gainXP(int xp)
{
}
@Override
public abstract void attack(Entity target);
}
@@ -0,0 +1,37 @@
package org.project.entity.enemies;
import org.project.entity.Entity;
import org.project.item.weapons.BasicWeapon;
import java.util.Random;
public class Goblin extends Enemy
{
private Random random = new Random();
private static final String RESET = "\u001B[0m";
private static final String RED = "\u001B[31m";
private static final String PURPLE = "\u001B[35m";
public Goblin() {
super("Goblin", 60, 20, new BasicWeapon("Rusty Dagger", 12));
}
@Override
public void attack(Entity target)
{
int damage = weapon.getDamage();
if (random.nextInt(100) < 25)
{
damage *= 2;
System.out.println(PURPLE + "💀 Goblin CRITICAL strike!" + RESET);
}
target.takeDamage(damage);
System.out.println(RED + "👹 Goblin attacks for " + damage + " damage!" + RESET);
}
}
@@ -1,6 +1,46 @@
package org.project.entity.enemies;
// TODO: UPDATE IMPLEMENTATION
public class Skeleton {
// TODO: DESIGN ENEMY AND IMPLEMENT THE CONSTRUCTOR
}
import org.project.entity.Entity;
import org.project.item.weapons.BasicWeapon;
public class Skeleton extends Enemy
{
private boolean revived = false;
private static final String RESET = "\u001B[0m";
private static final String RED = "\u001B[31m";
private static final String YELLOW = "\u001B[33m";
public Skeleton()
{
super("Skeleton", 70, 10, new BasicWeapon("Bone Sword", 15));
}
@Override
public void attack(Entity target)
{
int damage = weapon.getDamage();
target.takeDamage(damage);
System.out.println(RED + "☠ Skeleton slashes for " + damage + " damage!" + RESET);
}
@Override
public void takeDamage(int damage)
{
super.takeDamage(damage);
if (!isAlive() && !revived)
{
revived = true;
this.hp = 40;
System.out.println(YELLOW + "⚠ Skeleton reassembles itself!" + RESET);
}
}
}
@@ -0,0 +1,30 @@
package org.project.entity.enemies;
import org.project.entity.Entity;
import org.project.item.weapons.BasicWeapon;
public class Vampire extends Enemy
{
public Vampire()
{
super("Vampire", 90, 30, new BasicWeapon("Dark Claws", 18));
}
@Override
public void attack(Entity target)
{
int damage = weapon.getDamage();
target.takeDamage(damage);
int healAmount = damage / 2;
this.hp += healAmount;
System.out.println(RED + "🧛 Vampire drains "
+ damage + " HP!" + RESET);
System.out.println(YELLOW + "🩸 Vampire heals "
+ healAmount + " HP!" + RESET);
}
}
@@ -0,0 +1,99 @@
package org.project.entity.players;
import org.project.entity.Entity;
import org.project.item.weapons.BasicWeapon;
import java.util.Random;
public class Assassin extends Player
{
private static final int HEAVY_COST = 15;
private static final int SPECIAL_COST = 25;
private static final String RESET = "\u001B[0m";
private static final String RED = "\u001B[31m";
private static final String GREEN = "\u001B[32m";
private static final String YELLOW = "\u001B[33m";
private static final String BLUE = "\u001B[34m";
private static final String PURPLE = "\u001B[35m";
private Random random = new Random();
public Assassin(String name) {
super(name, 90, 80, new BasicWeapon("Dagger", 18));
}
@Override
public void lightAttack(Entity target)
{
int dmg = weapon.getDamage() + 12;
// 25% critical chance
if (random.nextInt(100) < 25)
{
dmg *= 2;
System.out.println(PURPLE + "💀 CRITICAL HIT!" + RESET);
}
target.takeDamage(dmg);
System.out.println(YELLOW + "🗡️ " + name +
" strikes for " + dmg + " damage!" + RESET);
}
@Override
public void heavyAttack(Entity target)
{
if (mp < HEAVY_COST) {
System.out.println(RED + "❌ Not enough MP!" + RESET);
return;
}
mp -= HEAVY_COST;
int dmg = weapon.getDamage() + 30;
target.takeDamage(dmg);
System.out.println(PURPLE + "⚡ Shadow Slash deals " +
dmg + " damage!" + RESET);
}
@Override
public void defendAction()
{
defend();
System.out.println(BLUE + "🛡️ Quick dodge stance!" + RESET);
}
@Override
public void healAction()
{
heal(20);
System.out.println(GREEN + "💖 " + name +
" uses bandage restoring 20 HP!" + RESET);
}
@Override
public void specialAbility(Entity target)
{
if (mp < SPECIAL_COST)
{
System.out.println(RED + "❌ Not enough MP!" + RESET);
return;
}
mp -= SPECIAL_COST;
setInvisible(true);
int dmg = weapon.getDamage() + 50;
target.takeDamage(dmg);
System.out.println(BLUE + "🌑 SHADOW STRIKE deals " +
dmg + " damage!" + RESET);
System.out.println(YELLOW + "👤 " + name +
" becomes INVISIBLE!" + RESET);
}
}
@@ -0,0 +1,22 @@
package org.project.entity.players;
import org.project.entity.Entity;
public interface ICombatActions
{
// 1. Light Attack
void lightAttack(Entity target);
// 2. Heavy Attack
void heavyAttack(Entity target);
// 3. Defend
void defendAction();
// 4. Heal
void healAction();
// 5. Special Ability
void specialAbility(Entity target);
}
@@ -1,6 +1,101 @@
package org.project.entity.players;
// TODO: UPDATE IMPLEMENTATION
public class Knight {
// TODO: DESIGN KNIGHT'S WEAPON AND ARMOR AND IMPLEMENT THE CONSTRUCTOR
}
import org.project.entity.Entity;
import org.project.item.armors.KnightArmor;
import org.project.item.weapons.Sword;
public class Knight extends Player {
private static final int LIGHT_BONUS = 15;
private static final int HEAVY_COST = 10;
private static final int SPECIAL_COST = 25;
private static final String RESET = "\u001B[0m";
private static final String RED = "\u001B[31m";
private static final String GREEN = "\u001B[32m";
private static final String YELLOW = "\u001B[33m";
private static final String BLUE = "\u001B[34m";
private static final String PURPLE = "\u001B[35m";
public Knight(String name)
{
super(name, 150, 40, new Sword());
new KnightArmor();
}
@Override
public void lightAttack(Entity target)
{
int dmg = weapon.getDamage() + LIGHT_BONUS;
target.takeDamage(dmg);
((Sword) weapon).addCharge(1);
System.out.println(
YELLOW + "⚔️ " + name +
" slashes the enemy for " + dmg + " damage!" +
RESET
);
}
@Override
public void heavyAttack(Entity target)
{
if (mp < HEAVY_COST)
{
System.out.println(RED + "❌ Not enough MP for heavy attack!" + RESET);
return;
}
mp -= HEAVY_COST;
int dmg = weapon.getDamage() + 30;
target.takeDamage(dmg);
((Sword) weapon).addCharge(2);
System.out.println(PURPLE + "💥 " + name +
" performs a HEAVY STRIKE for " + dmg + " damage!" + RESET);
}
@Override
public void defendAction()
{
defend();
System.out.println(BLUE + "🛡️ " + name +
" raises his shield!" + RESET);
}
@Override
public void healAction()
{
heal(30);
System.out.println(GREEN + "💖 " + name +
" heals for 30 HP!" + RESET);
}
@Override
public void specialAbility(Entity target)
{
if (mp < SPECIAL_COST)
{
System.out.println(RED + "❌ Not enough MP!" + RESET);
return;
}
mp -= SPECIAL_COST;
int dmg = weapon.getDamage() + 45;
target.takeDamage(dmg);
target.setStunned(true);
((Sword) weapon).addCharge(3);
System.out.println(
BLUE + "🌋 " + name +
" uses EARTH SHATTERING STRIKE dealing " + dmg + " damage!" +
RESET
);
System.out.println(YELLOW + "⚠️ The enemy is STUNNED!" + RESET);
}
}
@@ -1,89 +1,159 @@
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 {
import java.io.Serializable;
public abstract class Player implements Entity, ICombatActions, Serializable
{
private static final long serialVersionUID = 1L;
protected String name;
Weapon weapon;
Armor armor;
private int hp;
private int maxHP;
private int mp;
private int maxMP;
protected int hp, maxHP;
protected int mp, maxMP;
protected int level = 1;
protected int xp = 0;
public Player(String name, int hp, int mp, Weapon weapon, Armor armor) {
protected boolean stunned = false;
protected boolean invisible = false;
protected boolean defending = false;
private boolean goblinKey = false;
private boolean skeletonKey = false;
private boolean vampireKey = false;
protected Weapon weapon;
private static final String RESET = "\u001B[0m";
private static final String RED = "\u001B[31m";
private static final String GREEN = "\u001B[32m";
private static final String YELLOW = "\u001B[33m";
private static final String BLUE = "\u001B[34m";
private static final String PURPLE = "\u001B[35m";
public Player(String name, int maxHP, int maxMP, Weapon weapon)
{
this.name = name;
this.hp = hp;
this.mp = mp;
this.maxHP = maxHP;
this.hp = maxHP;
this.maxMP = maxMP;
this.mp = maxMP;
this.weapon = weapon;
this.armor = armor;
}
@Override
public void attack(Entity target) {
target.takeDamage(weapon.getDamage());
public void attack(Entity target)
{
lightAttack(target);
}
@Override
public void defend() {
// TODO
}
@Override
public void takeDamage(int damage) {
hp -= damage - armor.getDefense();
public void defend()
{
defending = true;
System.out.println(BLUE + "🛡️ " + name + " is defending!" + RESET);
}
@Override
public void heal(int health) {
hp += health;
if (hp > maxHP) {
public void heal(int amount)
{
hp = Math.min(maxHP, hp + amount);
}
@Override
public void fillMana(int amount)
{
mp = Math.min(maxMP, mp + amount);
}
@Override
public void takeDamage(int damage)
{
if (defending)
{
damage /= 2;
defending = false;
}
hp = Math.max(0, hp - damage);
System.out.println(RED + "💥 " + name + " took " + damage + " damage!" + RESET);
}
@Override
public int getHP() { return hp; }
@Override
public int getMP() { return mp; }
@Override
public int getMaxHP() { return maxHP; }
@Override
public int getMaxMP() { return maxMP; }
@Override
public int getLevel() { return level; }
@Override
public String getName() { return name; }
@Override
public void setStunned(boolean v) { stunned = v; }
@Override
public boolean isStunned() { return stunned; }
@Override
public void setInvisible(boolean v) { invisible = v; }
@Override
public boolean isInvisible() { return invisible; }
@Override
public boolean isAlive() { return hp > 0; }
@Override
public void gainXP(int xp)
{
this.xp += xp;
if (this.xp >= level * 100)
{
level++;
this.xp = 0;
maxHP += 10;
maxMP += 5;
hp = maxHP;
}
}
@Override
public void fillMana(int mana) {
mp += mana;
if (mp > maxMP) {
mp = maxMP;
System.out.println(GREEN + "" + name + " leveled up to level " + level + "!" + RESET);
}
}
public boolean hasGoblinKey() { return goblinKey; }
public boolean hasSkeletonKey() { return skeletonKey; }
public boolean hasVampireKey() { return vampireKey; }
public String getName() {
return name;
public void obtainGoblinKey() { goblinKey = true; }
public void obtainSkeletonKey() { skeletonKey = true; }
public void obtainVampireKey() { vampireKey = true; }
public boolean hasAllKeys()
{
return goblinKey && skeletonKey && vampireKey;
}
public int getHp() {
return hp;
public void resetKeys()
{
goblinKey = false;
skeletonKey = false;
vampireKey = false;
}
@Override
public int getMaxHP() {
return maxHP;
public void setHealth(int hp)
{
this.hp = Math.min(hp, maxHP);
}
public int getMp() {
return mp;
public void setMana(int mp)
{
this.mp = Math.min(mp, maxMP);
}
@Override
public int getMaxMP() {
return maxMP;
public int getXP()
{
return xp;
}
public Weapon getWeapon() {
return weapon;
}
public Armor getArmor() {
return armor;
}
}
}
@@ -0,0 +1,96 @@
package org.project.entity.players;
import org.project.entity.Entity;
import org.project.item.weapons.BasicWeapon;
public class Wizard extends Player
{
private static final int LIGHT_COST = 5;
private static final int HEAVY_COST = 15;
private static final int SPECIAL_COST = 30;
private static final String RESET = "\u001B[0m";
private static final String RED = "\u001B[31m";
private static final String GREEN = "\u001B[32m";
private static final String YELLOW = "\u001B[33m";
private static final String BLUE = "\u001B[34m";
private static final String PURPLE = "\u001B[35m";
public Wizard(String name) {
super(name, 100, 120, new BasicWeapon("Magic Staff", 20));
}
@Override
public void lightAttack(Entity target)
{
if (mp < LIGHT_COST)
{
System.out.println(RED + "❌ Not enough MP!" + RESET);
return;
}
mp -= LIGHT_COST;
int dmg = weapon.getDamage() + 10;
target.takeDamage(dmg);
System.out.println(YELLOW + "" + name + " casts Magic Bolt for " + dmg + " damage!" + RESET);
}
@Override
public void heavyAttack(Entity target)
{
if (mp < HEAVY_COST)
{
System.out.println(RED + "❌ Not enough MP!" + RESET);
return;
}
mp -= HEAVY_COST;
int dmg = weapon.getDamage() + 35;
target.takeDamage(dmg);
System.out.println(PURPLE + "🔥 " + name +
" casts FIREBALL for " + dmg + " damage!" + RESET);
}
@Override
public void defendAction()
{
defend();
System.out.println(BLUE + "🔮 Magical barrier activated!" + RESET);
}
@Override
public void healAction()
{
if (mp < 20)
{
System.out.println(RED + "❌ Not enough MP to heal!" + RESET);
return;
}
mp -= 20;
heal(40);
System.out.println(GREEN + "💖 " + name +
" casts HEAL restoring 40 HP!" + RESET);
}
@Override
public void specialAbility(Entity target)
{
if (mp < SPECIAL_COST)
{
System.out.println(RED + "❌ Not enough MP!" + RESET);
return;
}
mp -= SPECIAL_COST;
int dmg = weapon.getDamage() + 60;
target.takeDamage(dmg);
System.out.println(BLUE + "🌪️ ARCANE BURST hits for " +
dmg + " damage!" + RESET);
}
}
@@ -2,10 +2,14 @@ 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();
int getValue();
}
@@ -7,36 +7,67 @@ public abstract class Armor {
private int durability;
private int maxDurability;
private boolean isBroke;
private boolean isBroken;
public Armor(int defense, int durability) {
this.defense = defense;
this.maxDefense = defense;
this.durability = durability;
this.maxDurability = durability;
this.isBroken = false;
}
public void checkBreak() {
public void takeHit(int damage)
{
durability -= damage;
if (durability < 0)
{
durability = 0;
}
checkBroken();
}
public void checkBroken() {
if (durability <= 0) {
isBroke = true;
isBroken = true;
defense = 0;
}
}
// TODO: (BONUS) UPDATE THE REPAIR METHOD
public void repair() {
isBroke = false;
public void repair()
{
isBroken = false;
defense = maxDefense;
durability = maxDurability;
}
public int getDefense() {
public int getDefense()
{
return defense;
}
public int getDurability() {
public int getDurability()
{
return durability;
}
public boolean isBroke() {
return isBroke;
public int getMaxDefense()
{
return maxDefense;
}
public int getMaxDurability()
{
return maxDurability;
}
public boolean isBroken()
{
return isBroken;
}
public abstract String getArmorName();
}
@@ -1,6 +1,16 @@
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(30, 100);
}
@Override
public String getArmorName()
{
return "Knight's Plate Armor";
}
}
@@ -1,8 +1,50 @@
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
{
protected String name;
protected String description;
protected int restoreAmount;
protected boolean percentageBased;
public Consumable(String name, String description, int restoreAmount, boolean percentageBased)
{
this.name = name;
this.description = description;
this.restoreAmount = restoreAmount;
this.percentageBased = percentageBased;
}
public abstract void use(Entity target);
public String getName()
{
return name;
}
public int getRestoreAmount()
{
return restoreAmount;
}
public String getDescription()
{
return description;
}
public boolean isPercentageBased()
{
return percentageBased;
}
@Override
public String toString()
{
return name + " (" + description + ")";
}
}
@@ -2,15 +2,44 @@ 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
{
private static final int HEAL_AMOUNT = 30;
public Flask()
{
super(
"Health Flask",
"A small flask that restores health.",
HEAL_AMOUNT,
false
);
}
// TODO: UPDATE USE METHOD
@Override
public void use(Entity target) {
target.heal(target.getMaxHP() / 10);
public void use(Entity target)
{
int healValue;
if (percentageBased)
{
healValue = target.getMaxHP() * restoreAmount / 100;
} else
{
healValue = restoreAmount;
}
target.heal(healValue);
System.out.println(
target.getName() +
" used " +
name +
" and restored " +
healValue +
" HP!"
);
}
}
@@ -0,0 +1,20 @@
package org.project.item.weapons;
import org.project.entity.Entity;
import java.util.ArrayList;
import java.io.Serializable;
public class BasicWeapon extends Weapon implements Serializable
{
private static final long serialVersionUID = 1L;
public BasicWeapon(String name, int damage)
{
super(name, damage, 0);
}
@Override
public void uniqueAbility(ArrayList<Entity> targets) {
}
}
@@ -1,26 +1,64 @@
package org.project.item.weapons;
import org.project.entity.Entity;
import java.util.ArrayList;
import java.io.Serializable;
// TODO: UPDATE IMPLEMENTATION
public class Sword {
/*
THIS IS AN EXAMPLE OF A WEAPON DESIGN.
*/
public class Sword extends Weapon implements Serializable
{
int abilityCharge;
private static final long serialVersionUID = 1L;
public Sword() {
// TODO: DESIGN SWORD'S ATTRIBUTES IMPLEMENT THE CONSTRUCTOR
private int abilityCharge;
private static final int MAX_CHARGE = 10;
private static final int REQUIRED_CHARGE = 5;
public Sword()
{
super("Knight Sword", 20, 0);
this.abilityCharge = 0;
}
// TODO: (BONUS) UPDATE THE UNIQUE ABILITY
public void uniqueAbility(ArrayList<Entity> targets) {
abilityCharge += 2;
for (Entity target : targets) {
target.takeDamage(getDamage());
@Override
public void uniqueAbility(ArrayList<Entity> targets)
{
if (abilityCharge < REQUIRED_CHARGE)
{
System.out.println("⚠️ Not enough charge for special ability! (" + abilityCharge + "/" + REQUIRED_CHARGE + ")");
return;
}
if (isBroken)
{
System.out.println("⚠️ " + name + " is broken and can't use its special ability!");
return;
}
System.out.println("⚔️ " + name + " special ability: Cleave!");
for (Entity target : targets)
{
if (target != null && target.isAlive())
{
target.takeDamage((int) (getDamage() * 1.5));
}
}
abilityCharge = 0;
reduceDurability(5);
}
}
public void addCharge(int amount)
{
this.abilityCharge = Math.min(this.abilityCharge + amount, MAX_CHARGE);
}
public int getAbilityCharge()
{
return abilityCharge;
}
public int getMaxCharge()
{
return MAX_CHARGE;
}
}
@@ -1,35 +1,87 @@
package org.project.item.weapons;
import org.project.entity.Entity;
import java.util.ArrayList;
import java.io.Serializable;
// TODO: UPDATE IMPLEMENTATION
public abstract class Weapon {
private int damage;
private int manaCost;
public abstract class Weapon implements Serializable
{
/*
TODO: ADD OTHER REQUIRED AND BONUS ATTRIBUTES
*/
private static final long serialVersionUID = 1L;
public Weapon(int damage, int manaCost) {
protected String name;
protected int damage;
protected int manaCost;
protected int level;
protected int durability;
protected boolean isBroken;
public Weapon(String name, int damage, int manaCost)
{
this.name = name;
this.damage = damage;
this.manaCost = manaCost;
this.level = 1;
this.durability = 100;
this.isBroken = false;
}
@Override
public void use(Entity target) {
public void use(Entity target)
{
if (isBroken)
{
System.out.println("⚠️ " + name + " is broken and can't be used!");
return;
}
target.takeDamage(damage);
reduceDurability(1);
}
public int getDamage() {
public abstract void uniqueAbility(ArrayList<Entity> targets);
protected void reduceDurability(int amount)
{
durability = Math.max(0, durability - amount);
if (durability == 0)
{
isBroken = true;
}
}
public void upgrade()
{
level++;
damage += 5;
System.out.println("🛠️ " + name + " upgraded to level " + level + "!");
}
public String getName() {
return name;
}
public int getDamage()
{
return damage;
}
public int getManaCost() {
public int getManaCost()
{
return manaCost;
}
/*
TODO: ADD OTHER REQUIRED AND BONUS METHODS
*/
}
public int getLevel()
{
return level;
}
public int getDurability()
{
return durability;
}
public boolean isBroken()
{
return isBroken;
}
}
@@ -1,28 +1,64 @@
package org.project.location;
import org.project.entity.enemies.Enemy;
import org.project.entity.enemies.*;
import java.io.Serializable;
import java.util.ArrayList;
public class Location {
public class Location implements Serializable
{
private static final long serialVersionUID = 1L;
private String name;
private String description;
private int difficulty; // 1 = easy, 2 = medium, 3 = hard
private ArrayList<Location> connectedLocations;
private ArrayList<Enemy> enemies;
public Location(ArrayList<Location> locations, ArrayList<Enemy> enemies) {
this.locations = locations;
this.enemies = enemies;
public Location(String name, String description, int difficulty)
{
this.name = name;
this.description = description;
this.difficulty = difficulty;
this.connectedLocations = new ArrayList<>();
}
public String getName() {
public void connectLocation(Location location)
{
connectedLocations.add(location);
}
public ArrayList<Location> getConnectedLocations()
{
return connectedLocations;
}
public String getName()
{
return name;
}
public ArrayList<Location> getLocations() {
return locations;
public int getDifficulty()
{
return difficulty;
}
public ArrayList<Enemy> getEnemies() {
return enemies;
public void enter()
{
System.out.println("\n==============================");
System.out.println("📍 You arrived at: " + name);
System.out.println(description);
System.out.println("Difficulty: " + difficulty);
System.out.println("==============================\n");
}
public Enemy spawnEnemy()
{
return switch (name)
{
case "Forest" -> new Goblin();
case "Graveyard" -> new Skeleton();
case "Vampire Crypt" -> new Vampire();
case "Dragon Castle" -> new Dragon();
default -> new Goblin();
};
}
}
@@ -0,0 +1,27 @@
package org.project.utils;
import org.project.GameState;
import java.io.*;
public class SaveLoadManager {
public static void saveGame(GameState gameState, String filename) {
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename))) {
oos.writeObject(gameState);
System.out.println("\u001B[34m\u2714\u001B[0m Game saved successfully.");
} catch (IOException e) {
System.out.println("\u001B[31m\u2716\u001B[0m Error saving game: " + e.getMessage());
}
}
public static GameState loadGame(String filename) {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename))) {
GameState loadedState = (GameState) ois.readObject();
System.out.println("\u001B[32m\u2714\u001B[0m Game loaded successfully.");
return loadedState;
} catch (IOException | ClassNotFoundException e) {
System.out.println("\u001B[31m\u2716\u001B[0m Error loading game: " + e.getMessage());
return null;
}
}
}
Binary file not shown.