# ⚔️ 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 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), locations (ArrayList) - 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.