Files
HW-04-JAVA-KNIGHT/README.md
T
2026-07-12 19:20:33 +03:30

196 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Java Knight ⚔️
A turn-based, roguelike-inspired RPG that runs entirely in the terminal, written
in Java for the fourth Advanced Programming assignment.
> *For centuries, the land of Javanest lived in peace, until a magical Dragon
> plunged it into darkness, cursing its people into monsters and scattering the
> three keys to its lair among them. Battle the cursed creatures, recover the
> Goblin, Skeleton and Vampire keys, grow strong, and slay the Dragon to break
> the curse and restore peace to Javanest!*
---
## Table of Contents
1. [How to Compile & Run](#how-to-compile--run)
2. [How to Play](#how-to-play)
3. [Classes, Enemies & Stats](#classes-enemies--stats)
4. [Project Structure](#project-structure)
5. [OOP Principles Used](#oop-principles-used)
6. [Bonus Features](#bonus-features)
---
## How to Compile & Run
The project is a standard Maven project. You need **JDK 21+** installed.
### Using Maven (recommended)
```bash
cd Java-Knight
mvn compile
mvn exec:java -Dexec.mainClass=org.project.Main
```
### Using plain `javac` / `java`
```bash
cd Java-Knight
# compile every source file into the target/classes folder
find src/main/java -name "*.java" > sources.txt
javac -d target/classes @sources.txt
# run it
java -cp target/classes org.project.Main
```
> The game uses ANSI colour codes, so run it in a real terminal (macOS Terminal,
> Linux shell, Windows Terminal) for the intended colourful output.
---
## How to Play
1. **Name your hero** and **pick a class** (Knight, Wizard, or Assassin).
2. You wander into a random **location** and a random standard enemy appears.
For each encounter you choose:
- **1. Fight** enter turn-based combat.
- **2. Move** skip this enemy and travel somewhere new.
- **3. Visit the Merchant** spend coins on potions, a weapon, or repairs.
- **4. Go to the Castle** *only appears once you hold all 3 keys* fight
the Dragon.
3. **Combat is turn-based.** On your turn you pick one of five actions. Only
**Light Attack** is free; the rest cost Mana/Stamina, and the class
**Special** costs the most. If you run out of Mana, you can still Light
Attack.
| # | Action | Cost | Effect |
|---|---------------|-----------|--------|
| 1 | Light Attack | 0 | Moderate damage |
| 2 | Heavy Attack | 8 | Double damage |
| 3 | Defend | 6 | Blocks ~75% of the next hit |
| 4 | Heal | 12 | Restores 40% of max HP |
| 5 | Special | 15 | Unique class ultimate |
| 6 | Use Item | | Drink a potion from your inventory |
4. **Winning a fight** grants **XP** (scaled to the enemy's power), **coins**,
and a chance to drop that species' **key**. Your HP and Mana are then fully
restored.
5. **Leveling up** automatically raises your Max HP, Max Mana and base damage.
6. Collect **all 3 keys**, go to the Castle, and defeat the **Dragon** to win.
Dying at any point is **Game Over**.
---
## Classes, Enemies & Stats
### Player Classes
Each class has deliberately different starting stats, so they play differently.
| Class | HP | Mana | Base Dmg | Weapon | Special ability |
|------------|----|------|----------|-------------|-----------------|
| **Knight** ⚔️ | 50 | 40 | **8 (highest)** | Iron Sword | **Shield Bash** heavy damage + stuns the enemy (skips its next turn) |
| **Wizard** 🧙 | **65 (highest)** | 45 | 5 | Oak Staff | **Arcane Blast** heavy damage AND heals the caster |
| **Assassin** 🗡️ | 45 | **55 (highest)** | 6 | Twin Dagger | **Vanish** dodges the next attack + guarantees a crit on the next strike |
### Enemies
| Enemy | HP | Ability | Key |
|------------|-----|---------|-----|
| **Goblin** 👹 | 30 | 40% chance to land a **critical hit** (double damage) | Goblin Key |
| **Skeleton** ☠️ | 40 | **Resurrects once** per battle at 50% HP | Skeleton Key |
| **Vampire** 🦇 | 48 | **Lifesteal** heals for 50% of the damage it deals | Vampire Key |
| **Dragon** 🐉 | 160 | **True damage** fiery breath ignores armor *and* the Defend stance | — |
Standard enemies each have a **25% chance** to drop their key, and only **one key
per species** can ever drop (once you have the Goblin Key, no other Goblin will
drop one).
---
## Project Structure
```
org.project
├── Main.java // entry point builds the world, starts the game
├── Game.java // the game controller / main loop
├── Merchant.java // bonus shop system
├── entity
│ ├── Entity.java // interface every combatant implements
│ ├── players
│ │ ├── ICombatActions.java // interface: the 5 required actions
│ │ ├── Player.java // abstract base for all heroes
│ │ ├── Knight.java / Wizard.java / Assassin.java
│ └── enemies
│ ├── Enemy.java // abstract base for all monsters
│ ├── KeyType.java // enum of the three keys
│ ├── Goblin.java / Skeleton.java / Vampire.java / Dragon.java
├── item
│ ├── Item.java // interface for anything ownable/sellable
│ ├── weapons (Weapon abstract → Sword, Dagger, Staff, GreatAxe)
│ ├── armors (Armor abstract → KnightArmor, LeatherArmor, Robe)
│ └── consumables (Consumable abstract → Flask, ManaPotion)
├── location
│ └── Location.java // a place that spawns random enemies
└── util
├── ConsoleColors.java // ANSI colour helpers
└── Dice.java // random-number helpers
```
---
## OOP Principles Used
This project was designed around the seven principles the assignment asks for:
- **Encapsulation** all fields are `private`/`protected` with getters. HP, Mana
and XP can only be changed through methods like `takeDamage`, `heal` and
`gainXP`, which enforce their own rules (clamping to max, capping at zero,
leveling up).
- **Inheritance** shared logic lives in abstract base classes so it isn't
duplicated. `Player` holds the HP/Mana bars, leveling, inventory and four of
the five actions; `Knight`, `Wizard` and `Assassin` only add what's unique.
Same idea for `Enemy` → its four monster subclasses, and for
`Weapon`/`Armor`/`Consumable` → their concrete items.
- **Interfaces** `Entity` is the contract every combatant obeys, which is what
lets the combat loop treat a Knight and a Dragon identically. `ICombatActions`
guarantees every player class implements exactly the five required actions.
`Item` unifies weapons, armor and consumables so the merchant can sell any of
them.
- **Abstract classes** `Player`, `Enemy`, `Weapon`, `Armor` and `Consumable`
are all abstract: they provide shared state/behaviour but can't be instantiated
on their own, forcing subclasses to fill in the specifics (e.g.
`Player.specialAbility` is abstract).
- **Polymorphism** the whole game loop is polymorphic. `Game` only ever calls
`Player`/`Enemy`/`Entity` methods; the correct `specialAbility`, `attack` or
`takeDamage` runs depending on the real object. Each enemy overrides `attack`
to add its signature move.
- **Overriding** subclasses override base behaviour, e.g. `Skeleton` overrides
`takeDamage` to resurrect, `Vampire`/`Goblin`/`Dragon` override `attack`, and
every player class overrides `specialAbility`.
- **Overloading** `takeDamage(int)` vs `takeDamage(int, boolean)` in `Player`.
The second, overloaded version ignores defenses and is how the Dragon's breath
bypasses armor and shields. The `Sword` also overloads its constructor.
---
## Bonus Features
- **Coins & Merchant system** enemies drop coins; the Merchant sells Health
Flasks, Mana Potions, a stronger **Great Axe**, and can **repair** armor.
- **Inventory & consumables** potions can be bought, stored and used mid-combat
(action 6).
- **Durable armor** armor loses durability as it absorbs hits and eventually
breaks, until repaired at the merchant.
- **Colourful narrative console** ANSI colours (red for damage, blue for mana,
green for healing) make the combat log easy to read.
---
*Born of God and Void. You shall seal the blinding light that plagues their
dreams. You are the Vessel. You are the Java Knight.*