# ⚔️ Java RPG Game

A text-based role‑playing game built in Java, demonstrating core Object‑Oriented Programming principles such as inheritance, polymorphism, interfaces, abstraction, and encapsulation.

The player chooses a hero (Knight, Wizard, or Assassin), equips weapons and armour, and battles various enemies (Skeleton, Vampire, Goblin) in a simple turn‑based loop. Locations and consumable items are also partially implemented.

---

## 📁 Project Structure
---

## 🎮 Gameplay Overview

1. Character Selection – Enter your name, pick a class (Assassin, Wizard, Knight), choose a weapon and armour.
2. Combat Loop – You face random enemies from a list. Each turn you can:
   - Light Attack
   - Heavy Attack (normal attack)
   - Defend
   - Heal
   - Use Special Ability
3. Enemy AI – Enemies randomly choose between light and heavy attacks. Some enemies (e.g. Goblin) have special behaviours.
4. Progression – After defeating an enemy, the player's maximum HP and MP increase, and both player and enemy stats are refreshed.
5. Relocation – You can choose to move to another location (currently selecting a random enemy from the list).

---

## 🧱 Class Hierarchy & Interfaces

### Interface Entity
Defines the contract for all living beings in the game.

| Method | Description |
|--------|-------------|
| void attack(Entity target) | Basic attack on a target. |
| void LightAttack(Entity target, int base_damage) | A weaker attack with fixed damage. |
| void defend(Entity me, int damage) | Defensive action (confusing signature, see Player). |
| String getName() | Returns the entity's name. |
| void heal(int health) | Restores health points. |
| void fillMana(int mana) | Restores mana points. |
| void takeDamage(int damage) | Applies damage after armour reduction. |
| int getMaxHP() | Returns maximum health. |
| int getMaxMP() | Returns maximum mana. |
| boolean ISLive() | Checks if the entity is alive (HP > 0). |

### Interface Item
Defines usable items.

| Method | Description |
|--------|-------------|
| void use(Entity target) | Apply the item's effect to the target. |
| String getName() | Returns the item's name. |

---

## 🧙 Abstract Classes

### Player (extends Entity)
Common base for all player characters.

Fields:
- name, weapon, armor, hp, maxHP, mp, maxMP, baseDamage (unused)

Constructors:
- Player(String name, int hp, int mp, Weapon weapon, Armor armor, int baseDamage)
- Player(String name, int hp, int mp, Weapon weapon, Armor armor) – sets maxHP/maxMP equal to initial hp/mp.

Methods:
- void attack(Entity target) – Deals weapon damage.
- void defend(Entity me, int damage) – Heals the entity itself (unusual).
- void takeDamage(int damage) – Reduces damage by armour defence.
- void heal(int health) – Adds health, capped at maxHP.
- void fillMana(int mana) – Adds mana, capped at maxMP.
- abstract void specialAttack(Entity target) – Each subclass defines its own special move.
- boolean IsLive() – Returns true if HP > 0.
- void LightAttack(Entity target, int base_damage) – Deals flat damage.
- void UpGradeMaxHP() / UpGradeMaxMP() – Increases max stats by 20% (used after battle).
- void freshFactors() – Fully restores HP and MP.

### Enemy (extends Entity)
Base for all enemy types.

Fields:
- weapon, hp, mp, maxHp, maxMp

Constructor:
- Enemy(int hp, int mp, Weapon weapon) – Initialises stats and weapon.

Methods:
- int getHp(), int getMp(), Weapon getWeapon(), void setNewHp(int newhp)
- void takeDamage(int damage) – Direct HP reduction.
- abstract void attack(Entity target)
- abstract void check_hp() – Intended for death/recovery checks.
- abstract void defend() – Normal defend.
- abstract String getName()
- void heal(int health), void fillMana(int mana) – Standard recovery.
- boolean IsLive() – HP > 0.
- void LightAttack(Entity target, int base_damage) – Flat damage.
- int getMaxHP(), int getMaxMp()
- void freshFactors() – Resets HP/MP to max.

### Consumable (implements Item)
Base for consumable items.

- Consumable(String name) – Sets the item name.
- String getName()

### Weapon (abstract)
Base for all weapons.

Fields:
- int damage, int manaCost

Constructor: Weapon(int damage, int manaCost)

Methods:
- int getDamage(), int getManaCost()
- (No use method – not implementing Item)

### Armor (abstract)
Base for all armour pieces.
Fields:
- defense, maxDefense, durability, maxDurability, isBroke (private)

Constructors:
- Armor(int defense, int durability) – Main constructor (does not initialise max values correctly).
- Armor(int maxDefense, int maxDurability, boolean isBroke) – Unused overload.

Methods:
- void checkBreak() – If durability ≤ 0, sets isBroke = true and defense = 0.
- void repair() – Restores defence/durability to max values.
- int getDefense(), int getDurability(), boolean isBroke()
- void setMaxDefense(int max)
- void newDurability() – Decrements durability (does not auto‑call checkBreak).

---

## 🧝‍♂️ Concrete Player Classes

### Knight
- Base stats: HP=40, MP=20
- specialAttack(Entity target) – Deals 5 damage.

### Wizard
- Base stats: HP=40, MP=20
- specialAttack(Entity target) – Deals 5 damage and heals self for 10 HP (capped at max).

### Assassin
- Base stats: HP=20, MP=40
- specialAttack(Entity target) – Deals weapon damage.

All three override ISLive() to always return false (bug – should use IsLive() from Player).

---

## 👹 Concrete Enemy Classes

### Skeleton
- HP=10, MP=2
- attack(Entity target) – Weapon damage.
- check_hp() – If HP ≤ 0 and not yet revived, sets HP to Max_hp/2 (5). (Bug: ISLive() returns false, so this may not work as intended.)
- getName() returns "Skeleton".

### Vampire
- HP=12, MP=5
- attack(Entity target) – Weapon damage, heals self by damage/3, capped at Max_hp.
- getName() returns "Vampire".

### Goblin
- HP=6, MP=18
- attack(Entity target) – Weapon damage.
- getName() returns "Gobblin".

### Dragon
- Extends Enemy but currently all methods are empty/return default values – not fully implemented.

---

## ⚔️ Weapons

### Sword
- damage=3, manaCost=4 (constants, but constructor accepts parameters that are ignored)
- Copy constructor: Sword(Weapon other) copies damage and manaCost from another weapon.
- uniqueAbility(ArrayList<Entity> targets) – deals weapon damage to all targets.

### SwordPro
- damage=4, manaCost=3
- Same copy constructor and unique ability.

### SwordProMax
- damage=5, manaCost=2
- Same pattern.

---

## 🛡️ Armors

### KnightArmor
- defense=3, durability=2 (constructor ignores parameters, always uses static constants)
- No copy constructor.

### ArmorNormal
- defense=1, durability=2

### ArmorPro
- defense=2, durability=2

### ArmorProMax
- defense=1, durability=5

All armours use the same pattern: a static final value passed to super().

---

## 🧪 Consumables

### Flask (extends Consumable)
- Flask(String name) – calls super.
- use(Entity target) – Heals target by 10% of its max HP.

Currently unused in gameplay; the Main loop does not reference flasks.

---

## 📍 Location

- Fields: name, enemies (ArrayList<Enemy>), locations (ArrayList<Location>)
- Constructor takes locations and enemies, but does not assign name (remains null).
- Not integrated into the main game loop yet.

---

## 🎯 Main Class (Game Loop)

The main method contains:

1. Setup: Creates weapon instances, enemy list (Skeleton, Vampire, Goblin), scanner, random.
2. Player creation: Asks for name, class (1‑3), weapon (1‑3), armour (1‑4). Uses copy constructors for weapons.
3. Game loop: While player is alive (checks player.ISLive() – currently buggy, always false so loop never enters). Inside:
   - Displays current enemy name.
   - Offers two options: Fight (1) or Move (2). Moving picks a random enemy from the list.
   - When fight is selected, calls playerMove() (player attacks), then if enemy lives, enemyMove() (enemy attacks).
   - After enemy dies, player’s max HP/MP increase, both are refreshed.
4. Helper methods:
- playerMove(Player, Enemy) – Displays a menu of actions (Light Attack, Heavy Attack, Defend, Heal, Special) and calls the corresponding method.
   - enemyMove(Player, Enemy, int) – Randomly chooses Light Attack or normal Attack for the enemy.
   - showDetails(Player, Enemy) – Prints current stats.
   - pause(double seconds) – Sleeps the program for a given time.

---

## 🐞 Known Issues / Quirks

- Player.ISLive() always returns false because overridden incorrectly in subclasses; the loop condition is never satisfied.
- Armor constructors do not properly initialise maxDefense/maxDurability.
- Entity interface contains defend(Entity me, int damage) which doesn’t match the usual defend() signature.
- Many ISLive() overrides just return false, while the correct logic is in IsLive() (non‑interface method). The game uses ISLive() (interface method) which clashes with the intended behaviour.
- Location is not used; its name field is never set.

---

## 🚀 How to Run

1. Compile all .java files inside the org/project package.
2. Run org.project.Main.
3. Follow the console prompts to play.

---

## 📚 OOP Concepts Demonstrated

- Inheritance: Player and Enemy extend Entity; weapons extend Weapon; armours extend Armor.
- Polymorphism: Entity references used for both players and enemies in combat.
- Encapsulation: Private fields with getters/setters (though some fields could be better protected).
- Abstraction: Abstract classes Player, Enemy, Weapon, Armor define common behaviour; subclasses fill in specifics.

---

Enjoy the game! Contributions and fixes are welcome.