+ Added Armors

+ Added Weapons
+ Added REPORT.md
+ Finished the classes
+ (fix) Fixed problems caused by class hierarchy
- (todo) main loop, key mechanic.
This commit is contained in:
2026-05-10 17:38:01 +03:30
parent 4e8daa6655
commit deb26fc24f
25 changed files with 305 additions and 116 deletions
@@ -1,15 +1,71 @@
package org.project;
import org.project.entity.enemies.Dragon;
import org.project.location.Location;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
public class Main {
// Colors
private static final String RESET = "\u001B[0m"; // Reset ANSI code
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 static void main(String[] args) {
// TODO: ADD LOCATIONS TO YOUR GAME
// Scanner
Scanner scanner = new Scanner(System.in);
Random random1 = new Random(112233); // for initial location
Random random2 = new Random(123123); // to choose enemy
// Note : seed numbers don't mean anything (They are just magical numbers)
List<Location> locations = new ArrayList<>();
Location castle = new Location("Castle", new Dragon());
Location forest = new Location("Forest");
Location ruins = new Location("Ruins");
Location village = new Location("Village");
locations.add(castle);
locations.add(forest);
locations.add(ruins);
locations.add(village);
int randNum1 = random1.nextInt() % 3;
int randNum2 = random2.nextInt() % 3;
Location initialPlayerLoc = locations.get(randNum1 + 1); // since the index 0 : castle can't be the player initial location.
// Main loop
boolean isRunning = true;
while (isRunning){
System.out.println(YELLOW + "------------------Legend of AP------------------" + RESET);
System.out.println(" Choose your option :");
System.out.println(BLUE + " 1." + RESET + " Start a new game");
System.out.println(BLUE + " 2." + RESET + " Exit");
int option = scanner.nextInt();
switch (option){
case 1:
case 2:
System.out.println("Goodbye!");
isRunning = false;
break;
default:
continue;
}
}
// TODO: IMPLEMENT GAMEPLAY
}
}
@@ -1,42 +1,24 @@
package org.project.entity;
import org.project.entity.players.Player;
public abstract class Entity {
void takeDamage(int damage){};
void specialAbility(Entity target){};
void stun(){};
public abstract void stun(boolean value);
void makeCritical(boolean value){};
boolean isStunned(){};
public abstract void setHp(int newHp);
boolean isCritical(){};
public abstract boolean isCritical();
public abstract boolean isStunned();
boolean isDead(){};
public abstract void makeCritical(boolean value);
void makeDie(){};
public abstract void makeDie();
void setHp(int hp){};
public abstract void takeDamage(int damage);
void stun(boolean value){};
public abstract boolean isDead();
public abstract boolean isDead();
public abstract void heal(int health);
}
@@ -1,22 +1,21 @@
package org.project.entity.enemies;
import org.project.entity.Entity;
import org.project.entity.players.Player;
import org.project.item.weapons.DragonBreath;
import org.project.item.weapons.Weapon;
public class Dragon extends Enemy{
public Dragon(int hp, Weapon weapon){
super(hp, weapon);
private static final int HP = 600;
public Dragon(){
Weapon dragonBreath = new DragonBreath();
super(HP, dragonBreath);
}
@Override
public void specialAbility(Entity target) {
Player targetPlayer = (Player)target;
if (targetPlayer.isDefending()){
targetPlayer.breakShield();
}
super.attack(targetPlayer);
public void specialAbility(Player target) {
target.breakShield();
super.attack(target);
}
}
@@ -1,9 +1,10 @@
package org.project.entity.enemies;
import org.project.entity.Entity;
import org.project.entity.players.Player;
import org.project.item.weapons.Weapon;
public abstract class Enemy implements Entity {
public abstract class Enemy extends Entity {
Weapon weapon;
private int hp;
private boolean stunned = false;
@@ -26,6 +27,10 @@ public abstract class Enemy implements Entity {
}
}
@Override
public void heal(int health) {
hp += health;
}
@Override
public void takeDamage(int damage) {
@@ -53,7 +58,9 @@ public abstract class Enemy implements Entity {
}
@Override
public boolean isCritical(){ return critical;}
public boolean isCritical(){
return critical;
}
@Override
public boolean isStunned() {
@@ -73,5 +80,5 @@ public abstract class Enemy implements Entity {
return weapon;
}
public abstract void specialAbility(Entity target);
public abstract void specialAbility(Player target);
}
@@ -3,25 +3,28 @@ package org.project.entity.enemies;
import java.util.Random;
import org.project.entity.Entity;
import org.project.entity.players.Player;
import org.project.item.weapons.Dagger;
import org.project.item.weapons.Weapon;
public class Goblin extends Enemy{
private static final Random random = new Random();
private static final int HEALTH_POINT = 100;
public Goblin(int mp, Weapon weapon){
super(HEALTH_POINT, weapon);
public Goblin(){
Weapon goblinDagger = new Dagger();
super(HEALTH_POINT, goblinDagger);
}
@Override
public void specialAbility(Entity target) {
public void specialAbility(Player target) {
this.criticality();
super.attack(target);
}
// makes the next move critical with a probability of 80
private void criticality(){
Random random = new Random();
int randNum = random.nextInt(100);
if (randNum < 80){
this.makeCritical(true);
@@ -1,21 +1,28 @@
package org.project.entity.enemies;
import org.project.entity.players.Player;
import org.project.item.weapons.Dagger;
import org.project.item.weapons.Weapon;
public class Skeleton extends Enemy {
private static final int HP = 100;
private int deathCounter = 0;
private int initialHp;
public Skeleton(int hp, Weapon weapon){
super(hp,weapon);
initialHp = hp;
public Skeleton(){
Weapon skeletonDagger = new Dagger();
super(HP,skeletonDagger);
}
@Override
public void specialAbility(Player target) {
super.attack(target);
}
@Override
public void makeDie() {
if (deathCounter == 0){
this.setHp(initialHp / 2);
this.setHp(HP / 2);
deathCounter++;
return;
}
@@ -1,19 +1,21 @@
package org.project.entity.enemies;
import org.project.entity.Entity;
import org.project.entity.players.Player;
import org.project.item.weapons.Weapon;
public class Vampire extends Enemy{
private static final int SPECIAL_ABL_DMG = 40;
private static final int RANDEMANT_PERCENT = 70; // this constant determines how much of dealt damage should be given to vamp.
private static final int HP = 350;
public Vampire(int hp, Weapon weapon){
super(hp, weapon);
public Vampire(){
super(HP, null); // vampire doesn't need a weapon.
}
@Override
public void specialAbility(Entity target) {
public void specialAbility(Player target) {
System.out.println("Stealing life!...");
target.takeDamage(SPECIAL_ABL_DMG);
this.heal((SPECIAL_ABL_DMG * RANDEMANT_PERCENT) / 100);
@@ -1,18 +1,27 @@
package org.project.entity.players;
import org.project.entity.Entity;
import org.project.entity.enemies.Enemy;
import org.project.item.armors.Armor;
import org.project.item.armors.AssasinArmor;
import org.project.item.weapons.LightSaber;
import org.project.item.weapons.Weapon;
public class Assassin extends Player{
public Assassin(String name, int hp, int mp, Weapon weapon, Armor armor){
super(name, hp, mp, weapon, armor, 300,50);
private static final int MAX_HP = 300;
private static final int MAX_MP = 50;
public Assassin(String name){
Weapon assassinSaber = new LightSaber("Green"); // idk why but i gave assassin a light saber.
Armor assassinArmor = new AssasinArmor();
super(name, MAX_HP, MAX_MP, assassinSaber, assassinArmor, MAX_HP,MAX_MP);
}
@Override
public void specialAbility(Entity target) {
public void specialAbility(Enemy target) {
System.out.println("Turning invisible...");
this.defend();
this.makeCritical(true);
}
}
@@ -1,21 +1,27 @@
package org.project.entity.players;
import org.project.entity.Entity;
import org.project.entity.enemies.Enemy;
import org.project.item.armors.Armor;
import org.project.item.armors.KnightArmor;
import org.project.item.weapons.Sword;
import org.project.item.weapons.Weapon;
// TODO: UPDATE IMPLEMENTATION
public class Knight extends Player {
public Knight(String name, int hp, int mp, Weapon weapon, Armor armor){
super(name, hp, mp, weapon, armor, 400,40);
private static final int MAX_HP = 400;
private static final int MAX_MP = 40;
public Knight(String name){
Weapon knightSword = new Sword();
Armor knightArmor = new KnightArmor();
super(name, MAX_HP, MAX_MP, knightSword, knightArmor, MAX_HP,MAX_MP);
}
@Override
public void specialAbility(Entity target) {
public void specialAbility(Enemy target) {
System.out.println("Performing shield bash...");
target.stun(true);
target.takeDamage(50);
}
@@ -1,10 +1,11 @@
package org.project.entity.players;
import org.project.entity.Entity;
import org.project.entity.enemies.Enemy;
import org.project.item.armors.Armor;
import org.project.item.weapons.Weapon;
public abstract class Player implements Entity {
public abstract class Player extends Entity {
protected String name;
Weapon weapon;
Armor armor;
@@ -12,8 +13,8 @@ public abstract class Player implements Entity {
private int maxHP;
private int mp;
private int maxMP;
private boolean isDefending = false;
private boolean stunned = false;
private boolean isDefending = false;
private boolean critical = false;
private boolean dead = false;
@@ -71,6 +72,7 @@ public abstract class Player implements Entity {
public void takeDamage(int damage) {
if (!isDefending) {
hp -= damage - armor.getDefense();
armor.use();
}
else {
System.out.println("Defended the attack.");
@@ -79,6 +81,7 @@ public abstract class Player implements Entity {
}
@Override
public void heal(int health) {
mp -= HEAL_MP_COST;
hp += health;
@@ -93,7 +96,7 @@ public abstract class Player implements Entity {
mp = maxMP;
}
}
@Override
public void makeCritical(boolean value) {
critical = value;
@@ -104,9 +107,26 @@ public abstract class Player implements Entity {
dead = true;
}
public abstract void specialAbility(Enemy target);
@Override
public void stun(boolean value) {
stunned = value;
}
@Override
public void setHp(int newHp) {
hp = newHp;
}
@Override
public boolean isCritical(){ return critical;}
@Override
public boolean isStunned() {
return stunned;
}
public String getName() {
return name;
}
@@ -1,19 +1,29 @@
package org.project.entity.players;
import org.project.entity.Entity;
import org.project.entity.enemies.Enemy;
import org.project.item.armors.Armor;
import org.project.item.armors.WizardArmor;
import org.project.item.weapons.FireBall;
import org.project.item.weapons.Weapon;
public class Wizard extends Player{
public Wizard(String name, int hp, int mp, Weapon weapon, Armor armor){
super(name, hp, mp, weapon, armor, 500,30);
private static final int MAX_HP = 500;
private static final int MAX_MP = 30;
private static final int SPELL_DAMAGE = 40;
private static final int SPELL_HEAL_AMOUNT = 20;
public Wizard(String name ){
Weapon wizardWeapon = new FireBall();
Armor wizardArmor = new WizardArmor();
super(name, MAX_HP, MAX_MP, wizardWeapon, wizardArmor, MAX_HP, MAX_MP);
}
@Override
public void specialAbility(Entity target) {
public void specialAbility(Enemy target) {
System.out.println("Casting spell...");
target.takeDamage(30);
this.heal(10);
target.takeDamage(SPELL_DAMAGE);
this.heal(SPELL_HEAL_AMOUNT);
}
}
@@ -1,11 +0,0 @@
package org.project.item;
import org.project.entity.Entity;
public interface Item {
void use(Entity target);
/*
TODO: ADD OTHER REQUIRED AND BONUS METHODS
*/
}
@@ -1,33 +1,31 @@
package org.project.item.armors;
// TODO: UPDATE IMPLEMENTATION
public abstract class Armor {
private int defense;
private int maxDefense;
private int durability;
private int maxDurability;
private int durabilityCost;
private boolean isBroke;
public Armor(int defense, int durability) {
public Armor(int defense, int durability, int durabilityCost) {
this.defense = defense;
this.durability = durability;
this.durabilityCost = durabilityCost;
}
public void checkBreak() {
public void use(){
durability -= durabilityCost;
checkBreak();
}
private void checkBreak() {
if (durability <= 0) {
isBroke = true;
durability = 0;
defense = 0;
}
}
// TODO: (BONUS) UPDATE THE REPAIR METHOD
public void repair() {
isBroke = false;
defense = maxDefense;
durability = maxDurability;
}
public int getDefense() {
return defense;
}
@@ -0,0 +1,11 @@
package org.project.item.armors;
public class AssasinArmor extends Armor{
private static final int DURABILITY = 75;
private static final int DEFENSE = 20;
private static final int SINGLE_DEFENSE_COST = 25;
public AssasinArmor(){
super(DEFENSE,DURABILITY,SINGLE_DEFENSE_COST);
}
}
@@ -1,6 +1,11 @@
package org.project.item.armors;
// TODO: UPDATE IMPLEMENTATION
public class KnightArmor extends Armor{
// TODO: DESIGN ARMOR'S ATTRIBUTES IMPLEMENT THE CONSTRUCTOR
private static final int DURABILITY = 100;
private static final int DEFENSE = 30;
private static final int SINGLE_DEFENSE_COST = 25;
public KnightArmor(){
super(DEFENSE,DURABILITY,SINGLE_DEFENSE_COST);
}
}
@@ -0,0 +1,11 @@
package org.project.item.armors;
public class WizardArmor extends Armor{
private static final int DURABILITY = 50;
private static final int DEFENSE = 15;
private static final int SINGLE_DEFENSE_COST = 25;
public WizardArmor(){
super(DEFENSE,DURABILITY,SINGLE_DEFENSE_COST);
}
}
@@ -9,8 +9,8 @@ public class Flask extends Consumable {
*/
// TODO: UPDATE USE METHOD
@Override
public void use(Entity target) {
target.heal(target.getMaxHP() / 10);
}
// @Override
// public void use(Entity target) {
// target.heal(target.getMaxHP() / 10);
// }
}
@@ -0,0 +1,9 @@
package org.project.item.weapons;
public class Dagger extends Weapon{
private static final int DAMAGE = 25;
public Dagger(){
super(DAMAGE, 0); // the dagger is only meant to get used by skeleton and goblin, hence it doesen't use mana.
}
}
@@ -0,0 +1,9 @@
package org.project.item.weapons;
public class DragonBreath extends Weapon{
public static final int DAMAGE = 200;
public DragonBreath(){
super(DAMAGE, 0);
}
}
@@ -0,0 +1,10 @@
package org.project.item.weapons;
public class FireBall extends Weapon{
private static final int DAMAGE = 35;
private static final int MANA_COST = 8;
public FireBall() {
super(DAMAGE,MANA_COST);
}
}
@@ -0,0 +1,12 @@
package org.project.item.weapons;
public class LightSaber extends Weapon{ // xD
private static final int DAMAGE = 60;
private static final int MANA_COST = 9;
private String color; // color has no purpose at all, i just made it for fun.
public LightSaber(String color){
this.color = color;
super(DAMAGE,MANA_COST);
}
}
@@ -4,14 +4,13 @@ import org.project.entity.Entity;
import java.util.ArrayList;
// TODO: UPDATE IMPLEMENTATION
public class Sword extends Weapon {
private static final int DAMAGE = 50;
private static final int MANA_COST
private static final int MANA_COST = 8;
public Sword(int damage, int manaCost) {
super(damage, manaCost);
public Sword() {
super(DAMAGE,MANA_COST);
}
}
@@ -1,19 +1,12 @@
package org.project.item.weapons;
import org.project.entity.Entity;
public abstract class Weapon {
private int damage;
private int manaCost;
public Weapon(int damage, int manaCost) {
this.damage = damage;
this.manaCost = manaCost;
}
@Override
public void use(Entity target) {
target.takeDamage(damage);
public Weapon(int dmg, int mpCost) {
this.damage = dmg;
this.manaCost = mpCost;
}
public int getDamage() {
@@ -6,23 +6,35 @@ import java.util.ArrayList;
public class Location {
private String name;
private Enemy enemy;
private ArrayList<Enemy> enemies;
public Location(String name) {
this.name = name;
this.enemy = null;
}
public Location(ArrayList<Location> locations, ArrayList<Enemy> enemies) {
this.locations = locations;
this.enemies = enemies;
public Location(String name, Enemy enemy) {
this.name = name;
this.enemy = enemy;
}
public String getName() {
return name;
}
public ArrayList<Location> getLocations() {
return locations;
public Enemy getEnemy() {
return enemy;
}
public ArrayList<Enemy> getEnemies() {
return enemies;
public void setEnemy(Enemy enemy) {
this.enemy = enemy;
}
}
public boolean hasEnemy() {
return enemy != null && !enemy.isDead();
}
public void clearEnemy() {
this.enemy = null;
}
}
+30
View File
@@ -0,0 +1,30 @@
### Headache : A critique of the project design (Optional to read)
At first i thought this is just another simple assignment like the rest, however as i started working with it i stepped upon a tangled design.
the irony is the fact that TA team allowed changing the design structure indicating they knew the flaws.
#### Flaws :
- First of all,
there is literally no game available in the market in which the NPCs have Mana system. like what do you think a NPC does when it ran out of mana?
will it just stand there and look at you and wait for it destiny?
- Second,
how player should have two attack styles (lightAttack and heavyAttack), if the Entity interface only provides one attack style?
to implement such mechanic you either have to implement two methods for two attack styles in Entity interface which doesn't make sense as Enemies should only have one attack style,
or you can just delete attack completely and implement it based on the entity instance.
The attack method situation was just an example, methods like "defend" ,"fillMana" and "getMaxMP" follow the same story. none of them is usable for Enemy class.
This whole situation and entanglement only defeats the purpose of class hierarchy which is code redundancy and code reusability.
- Third and the most important,
the whole concept of a text-based RougeLike game just don't make sense, for the upcoming years
it would be much more logical to call it a "Card Game" as the follwing
### The actual report
i simply changed anything i complained about in first section (Nah you can't get away without reading that!)
#### Just one more moment...
i changed Entity from interface to abstract since i had problems with Player and Enemy sub-classes (idk if it was my language server issue or it was an actual problem).