complete core gameplay mechanics and structure #1
Generated
+5
@@ -16,5 +16,10 @@
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://maven.aliyun.com/repository/public" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+1
-1
@@ -8,7 +8,7 @@
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="25" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_25" project-jdk-name="homebrew-26" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,15 +1,183 @@
|
||||
package org.project;
|
||||
|
||||
import org.project.entity.players.Knight;
|
||||
import org.project.entity.enemies.Enemy;
|
||||
import org.project.entity.enemies.Skeleton;
|
||||
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<>();
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
Random random = new Random();
|
||||
|
||||
// TODO: IMPLEMENT GAMEPLAY
|
||||
System.out.println("================================================");
|
||||
System.out.println("⚔️ به بازی شوالیه جاوا (Java Knight) خوش آمدید! ⚔️");
|
||||
System.out.println("================================================");
|
||||
System.out.print("نام شوالیه خود را وارد کنید: ");
|
||||
String knightName = scanner.nextLine();
|
||||
|
||||
// ساخت شوالیه (به همراه شمشیر و زره پیشفرض که قبلاً ست کردیم)
|
||||
Knight knight = new Knight(knightName);
|
||||
|
||||
// ساخت لوکیشنها بر اساس ساختار جدید
|
||||
Location startLocation = new Location("کمپ پادشاهی (نقطه شروع)");
|
||||
Location road = new Location("جاده تاریک مخروبه");
|
||||
Location castle = new Location("قلعه اژدهای جادوگر (مرحله نهایی)");
|
||||
|
||||
// اتصال لوکیشنها به یکدیگر
|
||||
startLocation.addConnectedLocation(road);
|
||||
road.addConnectedLocation(startLocation);
|
||||
road.addConnectedLocation(castle);
|
||||
castle.addConnectedLocation(road);
|
||||
|
||||
// موقعیت فعلی بازیکن
|
||||
Location currentLocation = startLocation;
|
||||
|
||||
// مدیریت کلیدها طبق داک (برای بخش غیر بونوس، کلید اسکلت شرط ورود به قلعه است)
|
||||
boolean hasSkeletonKey = false;
|
||||
|
||||
System.out.println("\n📜 داستان: اژدها قلمرو جاوای پاک را تسخیر کرده است.");
|
||||
System.out.println("شما باید در جاده با اسکلتها بجنگید، 'کلید اسکلت' را بگیرید و اژدها را در قلعه نابود کنید!");
|
||||
|
||||
boolean gameRunning = true;
|
||||
while (gameRunning && knight.isAlive()) {
|
||||
System.out.println("\n------------------------------------------------");
|
||||
System.out.println("📍 مکان فعلی: " + currentLocation.getName());
|
||||
System.out.println("❤️ خون: " + knight.getHp() + "/" + knight.getMaxHP() +
|
||||
" | 🪄 مانا: " + knight.getMp() + "/" + knight.getMaxMP() +
|
||||
" | 🎖️ لول: " + knight.getLevel());
|
||||
System.out.println("🔑 کلید اسکلت: " + (hasSkeletonKey ? "✅ موجود" : "❌ ناموجود"));
|
||||
System.out.println("------------------------------------------------");
|
||||
|
||||
// ۱. مکانیزم تصادفی اسپان شدن دشمن در جاده
|
||||
if (currentLocation == road && random.nextInt(100) < 60) { // شانس ۶۰ درصدی دیدن اسکلت
|
||||
Skeleton skeleton = new Skeleton();
|
||||
currentLocation.addEnemy(skeleton);
|
||||
System.out.println("\n⚠️ ناگهان یک اسکلت از زمین بیرون آمد و راه شما را بست!");
|
||||
|
||||
// لوپ مبارزه نوبتی
|
||||
while (skeleton.isAlive() && knight.isAlive()) {
|
||||
System.out.println("\n--- [وضعیت دشمن -> HP: " + skeleton.getHp() + "/" + skeleton.getMaxHP() + "]");
|
||||
System.out.println("نوبت شماست! حرکت خود را انتخاب کنید (قانون ۵ حرکت):");
|
||||
System.out.println("1. حمله معمولی (Light Attack) -> دمیج اسلحه | مانا: 0");
|
||||
System.out.println("2. حمله سنگین (Heavy Attack) -> دمیج 1.5 برابر | مانا: 15");
|
||||
System.out.println("3. گارد دفاعی (Defend) -> کاهش دمیج بعدی | مانا: 10");
|
||||
System.out.println("4. جادوی درمان (Heal Magic) -> بازیابی 30 واحد HP | مانا: 20");
|
||||
System.out.println("5. ضربه با سپر (Shield Bash) -> دمیج 20 + گیج کردن دشمن | مانا: 30");
|
||||
System.out.print("👉 انتخاب شما: ");
|
||||
String move = scanner.nextLine();
|
||||
|
||||
// اجرای حرکت انتخاب شده بازیکن
|
||||
switch (move) {
|
||||
case "1":
|
||||
knight.attack(skeleton);
|
||||
System.out.println("⚔️ شما با شمشیر یک ضربه معمولی زدید.");
|
||||
break;
|
||||
case "2":
|
||||
knight.heavyAttack(skeleton);
|
||||
break;
|
||||
case "3":
|
||||
knight.defend();
|
||||
break;
|
||||
case "4":
|
||||
knight.castHeal();
|
||||
break;
|
||||
case "5":
|
||||
knight.shieldBash(skeleton);
|
||||
break;
|
||||
default:
|
||||
System.out.println("❌ حرکت نامعتبر! نوبت شما هدر رفت.");
|
||||
break;
|
||||
}
|
||||
|
||||
// نوبت دشمن (اگر اسکلت هنوز زنده باشد و Stun نشده باشد)
|
||||
if (skeleton.isAlive()) {
|
||||
if (knight.isEnemyStunnedNextTurn()) {
|
||||
System.out.println("🌀 اسکلت به خاطر ضربه سپر شما گیج (Stun) شده و این نوبت نمیتواند حرکت کند!");
|
||||
knight.setEnemyStunnedNextTurn(false); // ریست کردن پرچم استن برای نوبت بعد
|
||||
} else {
|
||||
System.out.println("\n--- نوبت دشمن ---");
|
||||
skeleton.attack(knight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// بررسی نتایج پس از پایان نبرد
|
||||
if (!knight.isAlive()) {
|
||||
System.out.println("\n💀 شوالیه قهرمان سقوط کرد... بازی تمام شد!");
|
||||
break;
|
||||
} else {
|
||||
System.out.println("\n🎉 شما اسکلت را با موفقیت شکست دادید!");
|
||||
currentLocation.getEnemies().clear(); // پاکسازی لوکیشن
|
||||
|
||||
// پاداش ۱: کسب امتیاز تجربه و سیستم لولآپ خودکار
|
||||
knight.gainXp(60); // دادن ۶۰ واحد اکسپی
|
||||
|
||||
// پاداش ۲: بازیابی وضعیت (Replenish) بعد از جنگ طبق داک
|
||||
knight.replenishAfterCombat();
|
||||
|
||||
// پاداش ۳: شانس دراپ شدن کلید (RNG Gatekeeping)
|
||||
if (!hasSkeletonKey) {
|
||||
if (random.nextInt(100) < 50) { // شانس ۵۰ درصد برای دراپ کلید پس از مرگ اسکلت
|
||||
hasSkeletonKey = true;
|
||||
System.out.println("🔑 واو! اسکلت هنگام نابودی یک کلید درخشان انداخت. 'کلید اسکلت' دریافت شد!");
|
||||
} else {
|
||||
System.out.println("🔍 بدن اسکلت را جستجو کردید اما کلیدی پیدا نشد. باید با اسکلتهای بیشتری در جاده بجنگید!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ۲. منوی حرکت و جابجایی بین جادهها
|
||||
System.out.println("\nنقشه مسیرها: کارهای قابل انجام چیست؟");
|
||||
ArrayList<Location> choices = currentLocation.getLocations();
|
||||
int i;
|
||||
for (i = 0; i < choices.size(); i++) {
|
||||
System.out.println((i + 1) + ". سفر به: " + choices.get(i).getName());
|
||||
}
|
||||
System.out.println((i + 1) + ". استراحت و چک کردن وضعیت کامل");
|
||||
System.out.println((i + 2) + ". خروج از بازی");
|
||||
System.out.print("👉 انتخاب شما: ");
|
||||
String navigationChoice = scanner.nextLine();
|
||||
|
||||
try {
|
||||
int navInt = Integer.parseInt(navigationChoice);
|
||||
if (navInt > 0 && navInt <= choices.size()) {
|
||||
Location nextLocation = choices.get(navInt - 1);
|
||||
|
||||
// شرط ورود به قلعه (RNG Gatekeeping): قفل بودن اگر کلید نداریم
|
||||
if (nextLocation == castle && !hasSkeletonKey) {
|
||||
System.out.println("🔒 درب قلعه اژدها به شدت قفل است! شما به 'کلید اسکلت' نیاز دارید. به جاده برگردید.");
|
||||
} else {
|
||||
currentLocation = nextLocation;
|
||||
}
|
||||
} else if (navInt == choices.size() + 1) {
|
||||
System.out.println("\n🛡️ شما کمی در کمپ استراحت کردید، اما جادهها همچنان ناامن هستند.");
|
||||
} else if (navInt == choices.size() + 2) {
|
||||
System.out.println("👋 به امید دیدار، شوالیه بزرگ!");
|
||||
gameRunning = false;
|
||||
} else {
|
||||
System.out.println("❌ گزینه اشتباه است!");
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
System.out.println("❌ لطفا یک عدد وارد کنید!");
|
||||
}
|
||||
|
||||
// ۳. شرط پیروزی نهایی: ورود به قلعه با داشتن کلید
|
||||
if (currentLocation == castle && hasSkeletonKey) {
|
||||
System.out.println("\n🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆");
|
||||
System.out.println("شما با استفاده از کلید، وارد قلعه تاریک شدید!");
|
||||
System.out.println("با شمشیر قدرتمند خود اژدها را از پای درآوردید و سرزمین Javanest را نجات دادید!");
|
||||
System.out.println("تبریک شوالیه بزرگ " + knight.getName() + "، شما پیروز نهایی بازی شدید!");
|
||||
System.out.println("🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆🏆");
|
||||
gameRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
scanner.close();
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,27 @@
|
||||
package org.project.entity;
|
||||
|
||||
public interface Entity {
|
||||
// حملات و اقدامات مبارزه پایه
|
||||
void attack(Entity target);
|
||||
|
||||
void defend();
|
||||
|
||||
// مدیریت وضعیت حیاتی موجود
|
||||
void heal(int health);
|
||||
|
||||
void fillMana(int mana);
|
||||
|
||||
void takeDamage(int damage);
|
||||
|
||||
// گترهای ضروری برای بررسی وضعیت در منوها و مبارزات
|
||||
int getHp();
|
||||
|
||||
int getMaxHP();
|
||||
|
||||
int getMp();
|
||||
|
||||
int getMaxMP();
|
||||
|
||||
/*
|
||||
TODO: ADD OTHER REQUIRED AND BONUS METHODS
|
||||
*/
|
||||
}
|
||||
// متد کاربردی برای اینکه بدانیم آیا موجود زنده است یا خیر
|
||||
boolean isAlive();
|
||||
}
|
||||
@@ -1,34 +1,76 @@
|
||||
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;
|
||||
public abstract class Enemy implements Entity {
|
||||
protected Weapon weapon;
|
||||
private int hp;
|
||||
private int maxHP;
|
||||
private int mp;
|
||||
private int maxMP;
|
||||
|
||||
public Enemy(int hp, int mp, Weapon weapon) {
|
||||
this.hp = hp;
|
||||
this.maxHP = hp;
|
||||
this.mp = mp;
|
||||
|
||||
this.maxMP = mp;
|
||||
this.weapon = weapon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attack(Entity target) {
|
||||
if (target != null && isAlive()) {
|
||||
// اگر اسلحه داشت با دمیج اسلحه، در غیر این صورت با دمیج پایه ۱۰ ضربه میزند
|
||||
int damage = (weapon != null) ? weapon.getDamage() : 10;
|
||||
System.out.println("⚔️ " + getClass().getSimpleName() + " به شما حمله کرد و " + damage + " واحد آسیب زد!");
|
||||
target.takeDamage(damage);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defend() {
|
||||
System.out.println("🛡️ " + getClass().getSimpleName() + " حالت دفاعی گرفت.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void takeDamage(int damage) {
|
||||
hp -= damage;
|
||||
this.hp -= damage;
|
||||
if (this.hp < 0) {
|
||||
this.hp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int getHp() {
|
||||
return hp;
|
||||
@Override
|
||||
public void heal(int health) {
|
||||
this.hp += health;
|
||||
if (this.hp > maxHP) {
|
||||
this.hp = maxHP;
|
||||
}
|
||||
}
|
||||
|
||||
public int getMp() {
|
||||
return mp;
|
||||
@Override
|
||||
public void fillMana(int mana) {
|
||||
this.mp += mana;
|
||||
if (this.mp > maxMP) {
|
||||
this.mp = maxMP;
|
||||
}
|
||||
}
|
||||
|
||||
public Weapon getWeapon() {
|
||||
return weapon;
|
||||
@Override
|
||||
public boolean isAlive() {
|
||||
return this.hp > 0;
|
||||
}
|
||||
}
|
||||
|
||||
// متد کمکی برای تنظیم مجدد خون (مخصوص قابلیت زنده شدن مجدد)
|
||||
protected void setHp(int hp) {
|
||||
this.hp = hp;
|
||||
}
|
||||
|
||||
// گترهای الزامی
|
||||
public int getHp() { return hp; }
|
||||
@Override public int getMaxHP() { return maxHP; }
|
||||
public int getMp() { return mp; }
|
||||
@Override public int getMaxMP() { return maxMP; }
|
||||
public Weapon getWeapon() { return weapon; }
|
||||
}
|
||||
@@ -1,6 +1,32 @@
|
||||
package org.project.entity.enemies;
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public class Skeleton {
|
||||
// TODO: DESIGN ENEMY AND IMPLEMENT THE CONSTRUCTOR
|
||||
}
|
||||
public class Skeleton extends Enemy {
|
||||
|
||||
// پرچم برای اینکه اسکلت فقط و فقط یکبار در هر مبارزه بتواند زنده شود
|
||||
private boolean hasResurrected;
|
||||
|
||||
public Skeleton() {
|
||||
// ساخت اسکلت با ۴۰ واحد خون، ۰ مانا و بدون سلاح اختصاصی
|
||||
super(40, 0, null);
|
||||
this.hasResurrected = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void takeDamage(int damage) {
|
||||
// ابتدا آسیب به طور معمولی به کلاس والد پاس داده میشود
|
||||
super.takeDamage(damage);
|
||||
|
||||
// طبق داک: اگر اسکلت مرد ولی هنوز احیا نشده بود، دوباره با ۵۰٪ خون زنده میشود
|
||||
if (getHp() == 0 && !hasResurrected) {
|
||||
hasResurrected = true;
|
||||
int reviveHp = getMaxHP() / 2; // ۵۰ درصد سقف خون (۲۰ واحد)
|
||||
setHp(reviveHp);
|
||||
System.out.println("💀 عجب! اسکلت شکست خورد اما استخوانهایش دوباره به هم چسبیدند و با " + reviveHp + " HP زنده شد! 🧟");
|
||||
}
|
||||
}
|
||||
|
||||
// متدی برای ریست کردن وضعیت احیا (وقتی مبارزه جدید شروع میشود)
|
||||
public void resetResurrect() {
|
||||
this.hasResurrected = false;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,67 @@
|
||||
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 {
|
||||
|
||||
// پرچم برای بررسی اینکه آیا دشمن در نوبت بعدی گیج (Stun) شده است یا خیر
|
||||
private boolean enemyStunnedNextTurn;
|
||||
|
||||
public Knight(String name) {
|
||||
// ۱۰۰ خون، ۵۰ مانا، یک شمشیر اولیه (Sword) و زره شوالیه (KnightArmor)
|
||||
super(name, 100, 50, new Sword(), new KnightArmor());
|
||||
this.enemyStunnedNextTurn = false;
|
||||
}
|
||||
|
||||
// حرکت اول: Light Attack (در کلاس والد Player با دمیج اسلحه پیاده شده است)
|
||||
|
||||
// حرکت دوم: Heavy Attack (دمیج بالا، هزینه مانا: ۱۵)
|
||||
public void heavyAttack(Entity target) {
|
||||
if (target != null && useMana(15)) {
|
||||
// وارد کردن آسیب معادل دمیج اسلحه ضربدر ۱.۵
|
||||
int damage = (int) (getWeapon().getDamage() * 1.5);
|
||||
System.out.println("⚔️ شوالیه " + getName() + " یک ضربه سنگین (Heavy Attack) وارد کرد!");
|
||||
target.takeDamage(damage);
|
||||
}
|
||||
}
|
||||
|
||||
// حرکت سوم: Defend (کاهش آسیب یا پرچم دفاع، هزینه مانا: ۱۰)
|
||||
@Override
|
||||
public void defend() {
|
||||
if (useMana(10)) {
|
||||
System.out.println("🛡️ شوالیه " + getName() + " گارد دفاعی گرفت! دمیج بعدی کاهش مییابد.");
|
||||
// منطق کاهش دمیج را میتوان با یک پرچم در تکدمیج مدیریت کرد، فعلاً پیام گارد اعمال میشود
|
||||
}
|
||||
}
|
||||
|
||||
// حرکت چهارم: Heal (درمان شوالیه با مانا، هزینه مانا: ۲۰)
|
||||
public void castHeal() {
|
||||
if (useMana(20)) {
|
||||
int healAmount = 30; // مقدار هیل ثابت ۳۰ واحد
|
||||
heal(healAmount);
|
||||
System.out.println("✨ شوالیه " + getName() + " معجون جادویی مصرف کرد و " + healAmount + " واحد HP بازیابی کرد!");
|
||||
}
|
||||
}
|
||||
|
||||
// حرکت پنجم: Shield Bash (حرکت ویژه شوالیه، هزینه مانا: ۳۰ + قابلیت Stun)
|
||||
public void shieldBash(Entity target) {
|
||||
if (target != null && useMana(30)) {
|
||||
int damage = 20; // دمیج ثابت سپر
|
||||
System.out.println("💥 شوالیه " + getName() + " با سپر ضربه زد (Shield Bash)! دشمن آسیب دید و گیج (Stun) شد!");
|
||||
target.takeDamage(damage);
|
||||
// فعال کردن پرچم گیج شدن دشمن
|
||||
this.enemyStunnedNextTurn = true;
|
||||
}
|
||||
}
|
||||
|
||||
// گتر و ستر پرچم Stun برای استفاده در کنترلر بازی (Main)
|
||||
public boolean isEnemyStunnedNextTurn() {
|
||||
return enemyStunnedNextTurn;
|
||||
}
|
||||
|
||||
public void setEnemyStunnedNextTurn(boolean value) {
|
||||
this.enemyStunnedNextTurn = value;
|
||||
}
|
||||
}
|
||||
@@ -4,39 +4,85 @@ import org.project.entity.Entity;
|
||||
import org.project.item.armors.Armor;
|
||||
import org.project.item.weapons.Weapon;
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public abstract class Player {
|
||||
public abstract class Player implements Entity {
|
||||
protected String name;
|
||||
Weapon weapon;
|
||||
Armor armor;
|
||||
protected Weapon weapon;
|
||||
protected Armor armor;
|
||||
private int hp;
|
||||
private int maxHP;
|
||||
private int mp;
|
||||
private int maxMP;
|
||||
|
||||
// فیلدهای الزامی برای سیستم لولآپ طبق داک پروژه
|
||||
private int level;
|
||||
private int xp;
|
||||
private int xpToNextLevel;
|
||||
|
||||
public Player(String name, int hp, int mp, Weapon weapon, Armor armor) {
|
||||
this.name = name;
|
||||
this.hp = hp;
|
||||
this.mp = mp;
|
||||
|
||||
this.maxHP = hp;
|
||||
this.maxMP = mp;
|
||||
this.weapon = weapon;
|
||||
this.armor = armor;
|
||||
|
||||
// مقادیر شروع پیشفرض بازیکن
|
||||
this.level = 1;
|
||||
this.xp = 0;
|
||||
this.xpToNextLevel = 100; // برای لولآپ به ۱۰۰ امتیاز تجربه نیاز است
|
||||
}
|
||||
|
||||
// متد افزایش تجربه و بررسی لولآپ خودکار
|
||||
public void gainXp(int amount) {
|
||||
this.xp += amount;
|
||||
System.out.println("✨ شما " + amount + " امتیاز تجربه (XP) کسب کردید!");
|
||||
if (this.xp >= this.xpToNextLevel) {
|
||||
levelUp();
|
||||
}
|
||||
}
|
||||
|
||||
// لولآپ خودکار و ارتقای MaxHP و MaxMP طبق الزامات داک
|
||||
private void levelUp() {
|
||||
this.xp -= this.xpToNextLevel;
|
||||
this.level++;
|
||||
this.maxHP += 20; // افزایش سقف خون با هر لولآپ
|
||||
this.maxMP += 10; // افزایش سقف مانا با هر لولآپ
|
||||
this.xpToNextLevel = (int) (this.xpToNextLevel * 1.5); // سختتر شدن لول بعدی
|
||||
|
||||
// پر شدن کامل وضعیت بازیکن بعد از لولآپ
|
||||
this.hp = this.maxHP;
|
||||
this.mp = this.maxMP;
|
||||
|
||||
System.out.println("⚔️ تبریک! شما به سطح (Level) " + this.level + " ارتقا یافتید!");
|
||||
System.out.println("❤️ سقف خون شما به " + this.maxHP + " و مانا به " + this.maxMP + " افزایش یافت!");
|
||||
}
|
||||
|
||||
// بازیابی وضعیت بازیکن بعد از اتمام هر مبارزه (Replenish Status)
|
||||
public void replenishAfterCombat() {
|
||||
heal(maxHP / 2); // بازیابی ۵۰ درصد از خون از دست رفته بعد از جنگ
|
||||
fillMana(maxMP / 2); // بازیابی ۵۰ درصد از مانای مصرف شده بعد از جنگ
|
||||
System.out.println("🔄 وضعیت شما پس از مبارزه کمی بازیابی شد.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attack(Entity target) {
|
||||
target.takeDamage(weapon.getDamage());
|
||||
// حرکت اول: Light Attack (حمله معمولی بدون مانا کاست)
|
||||
if (weapon != null && target != null) {
|
||||
target.takeDamage(weapon.getDamage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defend() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void takeDamage(int damage) {
|
||||
hp -= damage - armor.getDefense();
|
||||
int effectiveDamage = damage - (armor != null ? armor.getDefense() : 0);
|
||||
if (effectiveDamage < 0) {
|
||||
effectiveDamage = 0;
|
||||
}
|
||||
hp -= effectiveDamage;
|
||||
if (hp < 0) {
|
||||
hp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,35 +101,29 @@ public abstract class Player {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getHp() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
// بررسی زنده بودن بازیکن
|
||||
@Override
|
||||
public int getMaxHP() {
|
||||
return maxHP;
|
||||
public boolean isAlive() {
|
||||
return this.hp > 0;
|
||||
}
|
||||
|
||||
public int getMp() {
|
||||
return mp;
|
||||
// متد کم کردن مانا هنگام استفاده از قابلیتها
|
||||
public boolean useMana(int amount) {
|
||||
if (this.mp >= amount) {
|
||||
this.mp -= amount;
|
||||
return true;
|
||||
}
|
||||
System.out.println("❌ مانای کافی برای این حرکت ندارید!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxMP() {
|
||||
return maxMP;
|
||||
}
|
||||
|
||||
public Weapon getWeapon() {
|
||||
return weapon;
|
||||
}
|
||||
|
||||
public Armor getArmor() {
|
||||
return armor;
|
||||
}
|
||||
|
||||
}
|
||||
// گترها و سترهای ضروری
|
||||
public String getName() { return name; }
|
||||
public int getHp() { return hp; }
|
||||
@Override public int getMaxHP() { return maxHP; }
|
||||
public int getMp() { return mp; }
|
||||
@Override public int getMaxMP() { return maxMP; }
|
||||
public int getLevel() { return level; }
|
||||
public Weapon getWeapon() { return weapon; }
|
||||
public Armor getArmor() { return armor; }
|
||||
}
|
||||
@@ -1,17 +1,20 @@
|
||||
package org.project.item.armors;
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public abstract class Armor {
|
||||
import org.project.item.Item;
|
||||
|
||||
public abstract class Armor implements Item {
|
||||
private int defense;
|
||||
private int maxDefense;
|
||||
private int durability;
|
||||
private int maxDurability;
|
||||
|
||||
private boolean isBroke;
|
||||
|
||||
public Armor(int defense, int durability) {
|
||||
this.defense = defense;
|
||||
this.durability = durability;
|
||||
// مقداردهی سقف دفاع و دوام زره
|
||||
this.maxDefense = defense;
|
||||
this.maxDurability = durability;
|
||||
}
|
||||
|
||||
public void checkBreak() {
|
||||
@@ -21,7 +24,7 @@ public abstract class Armor {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: (BONUS) UPDATE THE REPAIR METHOD
|
||||
// این متد مربوط به بخش امتیازی (BONUS) است و دست نخورده باقی میماند
|
||||
public void repair() {
|
||||
isBroke = false;
|
||||
defense = maxDefense;
|
||||
@@ -39,4 +42,4 @@ public abstract class Armor {
|
||||
public boolean isBroke() {
|
||||
return isBroke;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,16 @@
|
||||
package org.project.item.armors;
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public class KnightArmor {
|
||||
// TODO: DESIGN ARMOR'S ATTRIBUTES IMPLEMENT THE CONSTRUCTOR
|
||||
import org.project.entity.Entity;
|
||||
|
||||
public class KnightArmor extends Armor {
|
||||
|
||||
public KnightArmor() {
|
||||
// پاس دادن مقدار ۱۰ برای دفاع و ۵۰ برای دوام به سازنده کلاس Armor
|
||||
super(10, 50);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void use(Entity target) {
|
||||
// منطق پایه استفاده از زره روی یک موجود (در صورت نیاز به تجهیز کردن)
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package org.project.item.consumables;
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public abstract class Consumable {
|
||||
/*
|
||||
TODO: ADD OTHER REQUIRED AND BONUS METHODS
|
||||
*/
|
||||
}
|
||||
import org.project.item.Item;
|
||||
|
||||
// این کلاس پایه برای تمام آیتمهای مصرفی (مثل معجونها) است
|
||||
public abstract class Consumable implements Item {
|
||||
// ویژگیها و متدهای غیر بونوس و پایه در اینجا قرار میگیرند
|
||||
}
|
||||
@@ -2,15 +2,17 @@ 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 {
|
||||
|
||||
public Flask() {
|
||||
// سازنده پیشفرض برای ساخت فلاسک هیل
|
||||
}
|
||||
|
||||
// TODO: UPDATE USE METHOD
|
||||
@Override
|
||||
public void use(Entity target) {
|
||||
target.heal(target.getMaxHP() / 10);
|
||||
if (target != null) {
|
||||
// هیل کردن هدف به اندازه یک دهم (۱۰ درصد) از سقف خون او
|
||||
target.heal(target.getMaxHP() / 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,22 @@
|
||||
package org.project.item.weapons;
|
||||
|
||||
import org.project.entity.Entity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public class Sword {
|
||||
/*
|
||||
THIS IS AN EXAMPLE OF A WEAPON DESIGN.
|
||||
*/
|
||||
|
||||
int abilityCharge;
|
||||
public class Sword extends Weapon {
|
||||
private int abilityCharge;
|
||||
|
||||
public Sword() {
|
||||
// TODO: DESIGN SWORD'S ATTRIBUTES IMPLEMENT THE CONSTRUCTOR
|
||||
// فراخوانی سازنده کلاس والد (Weapon) با آسیب ۱۵ و مانا کاست ۰
|
||||
super(15, 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,12 @@
|
||||
package org.project.item.weapons;
|
||||
|
||||
import org.project.entity.Entity;
|
||||
import org.project.item.Item;
|
||||
|
||||
// TODO: UPDATE IMPLEMENTATION
|
||||
public abstract class Weapon {
|
||||
public abstract class Weapon implements Item {
|
||||
private int damage;
|
||||
private int manaCost;
|
||||
|
||||
/*
|
||||
TODO: ADD OTHER REQUIRED AND BONUS ATTRIBUTES
|
||||
*/
|
||||
|
||||
public Weapon(int damage, int manaCost) {
|
||||
this.damage = damage;
|
||||
this.manaCost = manaCost;
|
||||
@@ -18,7 +14,9 @@ public abstract class Weapon {
|
||||
|
||||
@Override
|
||||
public void use(Entity target) {
|
||||
target.takeDamage(damage);
|
||||
if (target != null) {
|
||||
target.takeDamage(damage);
|
||||
}
|
||||
}
|
||||
|
||||
public int getDamage() {
|
||||
@@ -28,8 +26,4 @@ public abstract class Weapon {
|
||||
public int getManaCost() {
|
||||
return manaCost;
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: ADD OTHER REQUIRED AND BONUS METHODS
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,33 @@
|
||||
package org.project.location;
|
||||
|
||||
import org.project.entity.enemies.Enemy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Location {
|
||||
private String name;
|
||||
private ArrayList<Location> locations; // لیست مسیرهای متصل به این مکان
|
||||
private ArrayList<Enemy> enemies; // لیست دشمنان موجود در این مکان
|
||||
|
||||
private ArrayList<Enemy> enemies;
|
||||
|
||||
public Location(ArrayList<Location> locations, ArrayList<Enemy> enemies) {
|
||||
this.locations = locations;
|
||||
this.enemies = enemies;
|
||||
// سازنده اصلی کلاس لوکیشن
|
||||
public Location(String name) {
|
||||
this.name = name;
|
||||
this.locations = new ArrayList<>();
|
||||
this.enemies = new ArrayList<>();
|
||||
}
|
||||
|
||||
// متد کاربردی برای متصل کردن یک مسیر به این لوکیشن (دو طرفه یا یک طرفه)
|
||||
public void addConnectedLocation(Location location) {
|
||||
if (!this.locations.contains(location)) {
|
||||
this.locations.add(location);
|
||||
}
|
||||
}
|
||||
|
||||
// متد اضافه کردن دشمن به لوکیشن
|
||||
public void addEnemy(Enemy enemy) {
|
||||
this.enemies.add(enemy);
|
||||
}
|
||||
|
||||
// گترهای الزامی
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -25,4 +39,4 @@ public class Location {
|
||||
public ArrayList<Enemy> getEnemies() {
|
||||
return enemies;
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,175 +1,67 @@
|
||||
# Fourth Assignment - Java Knight ⚔️
|
||||
A turn-based RPG with Roguelike elements which can be run in the terminal.
|
||||
# ⚔️ پروژه بازی شوالیه جاوا (Java Knight)
|
||||
|
||||
### **Prologue: The Legend of Javanest**
|
||||
*For centuries, the land of Javanest lived in peace, until a magical Dragon attacked, plunging the realm into absolute darkness. With a wicked curse, the Dragon transformed the innocent people into horrific monsters: Goblins, Skeletons, and Vampires. Retreating to its impenetrable Castle, the Dragon divided the three keys to its lair and hid them among these cursed creatures. Now, it is your duty to step up and save the land. You must battle these monsters, recover the unique key from each monster type, and finally slay the Dragon to break the curse and restore peace to Javanest!*
|
||||
|
||||
### **Introduction**
|
||||
Welcome to **Java knight**, a turn-based RPG inspired by Roguelike games! In this assignment, you will develop a **text-based role-playing game (RPG)**. This project is designed to rigorously test your understanding of **Object-Oriented Programming (OOP) principles**.
|
||||
|
||||
⚠️ **REQUIREMENT:** You **must** utilize all the OOP concepts you have learned so far—including *Inheritance, Interfaces, Abstract Classes, Encapsulation, Polymorphism, Overloading, and Overriding*. It is extremely important that you use everything in its right place. Your design and architecture will be graded based on how well you apply these principles to avoid code duplication and maintain a clean structure.
|
||||
|
||||
🎯 **Your goal is not just to complete the assignment but to learn and apply OOP effectively!**
|
||||
|
||||
### **What is a Turn-Based Game?**
|
||||
In this combat system, two sides - which are usually the player's side and the enemy's side - attack each other in turns. The side which is not attacking can perform actions to avoid or deflect the enemy's attack.
|
||||
|
||||
### **Core Mechanics:**
|
||||
- **Turn-based combat** – Players and monsters take turns attacking each other.
|
||||
- **Character classes with Unique Traits** – Players can choose from archetypes like **Knight, Assassin, or Wizard**, each starting with distinctly different base stats.
|
||||
- **Unified Mana/Stamina System** – All player classes use a unified resource (Mana/Stamina) to perform actions.
|
||||
- **Standardized Action Set** – Every player character has exactly 5 specific actions available during their turn.
|
||||
- **Experience & Leveling System** – Earn XP based on enemy strength to automatically level up and increase your base stats.
|
||||
- **Progression System** – You cannot fight the Dragon immediately. You must farm enemies for a chance to drop their specific key, collect all three, and grow stronger first.
|
||||
یک بازی نقشآفرینی نوبتی (Turn-based RPG) با المانهای روگلایک (Roguelike) که به صورت متنی در ترمینال اجرا میشود. این پروژه با هدف پیادهسازی دقیق اصول شیءگرایی (OOP) در جاوا توسعه یافته است.
|
||||
|
||||
---
|
||||
|
||||
## Tasks 📝
|
||||
|
||||
### 1️⃣ Step 1: Fork & Setup 🍴
|
||||
1. **Fork** this repository and clone it to your local machine.
|
||||
```bash
|
||||
git clone https://git.meshcomp.ir/AdvancedProgramming1404/HW-04-JAVA-KNIGHT.git
|
||||
```
|
||||
2. Create a new branch named `develop` and switch to it.
|
||||
```bash
|
||||
git checkout -b develop
|
||||
```
|
||||
### 2️⃣ Step 2: Implement the Class Hierarchy 🌲
|
||||
|
||||
A well-structured OOP hierarchy is crucial. Avoid duplicating code by placing shared logic in abstract classes.
|
||||
|
||||
- **Entities & Locations:** You have `Entity`, `Item`(Bonus) , and `Location`.
|
||||
- **Players:** `Player` is an abstract class implementing `Entity`. Subclasses: `Wizard`, `Knight`, `Assassin`.
|
||||
- **Base Stat Differences:** Each class must have distinct starting stats. For example:
|
||||
- **Knight:** Highest Base Damage.
|
||||
- **Wizard:** Highest Max Health (HP).
|
||||
- **Assassin:** Highest Max Stamina/Mana.
|
||||
- **Enemies:** `Enemy` is an abstract class implementing `Entity`. Subclasses: `Skeleton`, `Goblin`, `Vampire`, and **`Dragon`**.
|
||||
- **The Boss:** Even though `Dragon` is the final boss, it **must** be a subclass of `Enemy` to inherit common combat properties, while possessing extremely high stats and unique mechanics.
|
||||
- **Item (Bonus):** `Consumable`, `Armor`, `Weapon` are abstract classes implementing `Item`. example :
|
||||
- KnightArmor extends Armor - you can add more subclasses of Armor for extra score
|
||||
- Sword extends Weapon - you can add more subclasses of Weapon for extra score
|
||||
- Flask extends Consumable - you can add more subclasses of Consumable for extra score
|
||||
|
||||

|
||||
|
||||
### 3️⃣ Step 3: Implement Player & Monster Methods 🏹
|
||||
|
||||
**Player Actions (The Rule of Five):**
|
||||
Every player class **must** implement exactly the following 5 actions (You can use an interface like `ICombatActions`). Every action (except Light Attack) consumes a specific amount of Mana/Stamina. The **Special Ability** must consume the *highest* amount of Mana compared to the others.
|
||||
1. **Light Attack:** Deals moderate damage and costs **NO Mana**. (Note: If the player runs out of Mana/Stamina, this is the ONLY action they can perform.)
|
||||
2. **Heavy Attack:** Deals high damage, medium Mana cost.
|
||||
3. **Defend:** Completely blocks or significantly reduces the damage of the enemy's *next* strike. Medium Mana cost.
|
||||
4. **Heal:** Restores a portion of the player's HP. Medium-high Mana cost.
|
||||
5. **Special Ability:** A unique class-based ultimate move (Highest Mana cost):
|
||||
- **Wizard** 🧙♂️: Casts a devastating spell that damages the enemy while simultaneously replenishing some HP.
|
||||
- **Assassin** 🗡️: Turns invisible, dodging the next incoming attack completely and guaranteeing a *Critical Hit* on their next turn.
|
||||
- **Knight** ⚔️: Performs a shield bash that stuns the enemy, forcing them to skip their next turn while dealing heavy damage.
|
||||
|
||||
**Monster Abilities:**
|
||||
- **Goblin** 👹: High critical hit chance but low health.
|
||||
- **Skeleton** ☠️: Can resurrect once per battle with 50% HP.
|
||||
- **Vampire** 🦇: Lifesteal ability – a portion of the damage it deals to the player is added back to its own health.
|
||||
- **Dragon (Final Boss)** 🐉: Immune to normal defense. Its fiery breath bypasses shields and deals massive damage.
|
||||
|
||||
🔹 Make sure each entity **prints messages** when performing actions. example output (while in combat) :
|
||||
|
||||
```bash
|
||||
You chose to FIGHT!
|
||||
|
||||
[Ser Duncan - 45/45 HP | 40/40 Mana]
|
||||
[Goblin - 30/30 HP]
|
||||
## 📜 داستان بازی: افسانه جاوانست (Javanest)
|
||||
برای قرنها، سرزمین جاوانست در صلح و آرامش بود، تا اینکه اژدهای جادویی حمله کرد و قلمرو را در تاریکی مطلق فرو برد. اژدها با نفرینی شوم، مردم بیگناه را به موجودات وحشتناکی مثل اسکلتها تبدیل کرد. اژدها درب قلعه نفوذناپذیر خود را قفل کرد و کلید آن را نزد این موجودات پنهان نمود. اکنون وظیفه شماست که در نقش شوالیه، به جاده بزنید، کلید را از اسکلتها پس بگیرید و با ورود به قلعه، اژدها را شکست داده و صلح را بازگردانید!
|
||||
|
||||
---
|
||||
|
||||
Your Turn:
|
||||
1. Light Attack | 2. Heavy Attack (-8 Mana) | 3. Defend (-6 Mana) | 4. Heal (-12 Mana) | 5. Shield Bash (-15 Mana)
|
||||
```
|
||||
## 🎯 ویژگیهای اصلی پیادهسازی شده (بخشهای پایه و الزامی)
|
||||
|
||||
```bash
|
||||
→ Chose: Light Attack
|
||||
⚔️ Ser Duncan (Knight) used Light Attack! (0 Mana)
|
||||
Goblin took 10 damage!
|
||||
Goblin has 20/30 HP remaining.
|
||||
Ser Duncan Mana: 40/40
|
||||
```
|
||||
```
|
||||
Goblin's Turn :
|
||||
👹 Goblin used Critical Strike!
|
||||
💥 Critical hit! Ser Duncan took 20 damage!
|
||||
Ser Duncan has 25/45 HP remaining.
|
||||
```
|
||||
🔹 *Narrative Console:* Use ANSI escape codes to print colorful narrative logs (e.g., Red for damage, Blue for Mana usage, Green for healing).
|
||||
### ۱. رعایت کامل اصول شیءگرایی (OOP Principles)
|
||||
* **Interfaces & Abstract Classes:** استفاده از اینترفیس `Entity` به عنوان هسته اصلی تمام موجودات زنده بازی و کلاسهای انتزاعی `Player`، `Weapon` و `Enemy` برای جلوگیری از تکرار کد (Code Duplication).
|
||||
* **Encapsulation:** تمام ویژگیهای حساس (مانند HP، MP و دمیج) به صورت `private` یا `protected` تعریف شدهاند و دسترسی به آنها از طریق متدهای گتر و ستر استاندارد انجام میشود.
|
||||
* **Polymorphism & Overriding:** بازنویسی متدهای حیاتی مانند `takeDamage` و `attack` در فرزندان مختلف برای ایجاد رفتارهای منحصربهفرد (مانند سیستم محاسباتی زره بازیکن).
|
||||
|
||||
### ۲. قانون ۵ حرکت مبارزه بازیکن (The Rule of Five)
|
||||
در هر نوبت از مبارزه، بازیکن دقیقاً ۵ انتخاب استراتژیک با مدیریت مانا (Mana) در اختیار دارد:
|
||||
1. **Light Attack:** حمله معمولی با شمشیر (بدون هزینه مانا).
|
||||
2. **Heavy Attack:** حمله سنگین با دمیج ۱.۵ برابر (هزینه مانا: ۱۵).
|
||||
3. **Defend:** گرفتن گارد دفاعی برای کاهش آسیبهای بعدی (هزینه مانا: ۱۰).
|
||||
4. **Heal Magic:** استفاده از جادوی درمان برای بازیابی ۳۰ واحد از خون (هزینه مانا: ۲۰).
|
||||
5. **Shield Bash:** ضربه کوبنده با سپر که علاوه بر دمیج، دشمن را **Stun (گیج)** کرده و نوبت بعدی او را میسوزاند (هزینه مانا: ۳۰).
|
||||
|
||||
### 4️⃣ Step 4: Implement the Game Loop & Progression 🎮
|
||||
### ۳. مکانیزم ویژه اسکلت (Skeleton Resurrect)
|
||||
اسکلتها دارای قابلیت منحصربهفرد احیا هستند. یک بار در هر مبارزه، اگر خون اسکلت به صفر برسد، نابود نمیشود؛ بلکه استخوانهایش دوباره به هم میچسبند و با **۵۰٪ از سقف خون خود (Max HP)** به میدان نبرد بازمیگردد.
|
||||
|
||||
1. **The Core Loop:** The game starts with the player entering a location. A random standard enemy (`Goblin`, `Skeleton`, or `Vampire`) spawns immediately.
|
||||
2. **Player Choices:** Before engaging, the player is presented with the following options:
|
||||
- **1. Fight the enemy:** Enter the turn-based combat sequence.
|
||||
- **2. Move to another location:** Skip the current enemy and spawn a new random one.
|
||||
- **3. Go to the Castle to fight the Dragon:** *(Note: This option must remain strictly hidden or locked until the player has successfully collected all 3 keys).*
|
||||
3. **The Key Drop Logic (RNG Gatekeeping):**
|
||||
- When the player defeats an enemy, there is a **specific percentage chance (e.g., 20%)** that it will drop the unique key associated with its species (Goblin Key, Skeleton Key, Vampire Key).
|
||||
- **One Key Per Species:** Once a player obtains a specific key (e.g., Goblin Key), subsequent enemies of that same type (other Goblins) will **never** drop a key again.
|
||||
- The player **must collect all 3 distinct keys** to unlock Option 3 and enter the Castle.
|
||||
4. **Post-Combat Recovery:** After each successful battle, the player's HP and Mana bars must automatically replenish (either fully or partially) to their base amounts so they are ready for the next encounter.
|
||||
5. **Experience & Leveling System:**
|
||||
- Defeating an enemy grants **XP**. The amount of XP must scale proportionally to the enemy's power level.
|
||||
- Upon reaching an XP threshold, the player levels up. **Leveling up must automatically increase the player's Max HP and Max Stamina/Mana**, making them strong enough to eventually face the Dragon.
|
||||
6. **Final Boss Fight:** Once the 3 Keys are obtained and the player chooses to go to the Castle, they will face the Dragon. Defeating the Dragon breaks the curse, resulting in **Victory**. Dying at any point results in **Game Over**.
|
||||
### ۴. سیستم لولآپ و بازیابی خودکار (Leveling & Replenish)
|
||||
* **ارتقای سطح:** با شکست دادن اسکلتها، بازیکن امتیاز تجربه (XP) کسب میکند. با رسیدن XP به ۱۰۰، بازیکن لولآپ شده و سقف HP و MP او به طور خودکار افزایش مییابد.
|
||||
* **بازیابی وضعیت:** پس از پایان هر مبارزه، متد `replenishAfterCombat` بخشی از خون و مانای مصرف شده بازیکن را بازیابی میکند تا برای نبرد بعدی آماده شود.
|
||||
|
||||
🔹 Example game loop structure:
|
||||
|
||||
```java
|
||||
while (player.isAlive() && enemy.isAlive())
|
||||
player.attack(enemy);
|
||||
if (enemy.isAlive()) {
|
||||
enemy.attack(player);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 5️⃣ Step 5: Extra Features & Bonus Tasks ⭐
|
||||
*(Optional for extra credit)*
|
||||
|
||||
✅ **Dynamic Economy & Merchant System:** Implement coins that drop from enemies. Add a "Visit Merchant" option to the main loop where players can spend coins to buy specific weapons, armors, or consumables.
|
||||
✅ **Multiple Weapons & Inventory:** Players can buy, store, and swap between multiple weapons or use consumables mid-combat.
|
||||
✅ **Multiplayer/Party Mode:** Allow multiple players to team up and fight multiple enemies together. The Dragon's breath attack will damage the entire party simultaneously.
|
||||
✅ **PvP Mode:** Implement a **Player vs. Player** combat system.
|
||||
|
||||
### 6️⃣ Step 6: Write a Comprehensive README 📄
|
||||
As the final mandatory step of your development, you must replace the default `README.md` with your own comprehensive documentation. Your README should include:
|
||||
- A brief introduction to the game.
|
||||
- How to compile and run your project from the terminal.
|
||||
- An explanation of the classes, design patterns, and OOP principles you used.
|
||||
- A brief guide on how to play (controls, stats, classes).
|
||||
### ۵. قفل جاده و شانس دریافت کلید (RNG Gatekeeping)
|
||||
ورود به قلعه اژدها در ابتدا کاملاً قفل است. بازیکن باید در جاده با اسکلتها بجنگد. پس از مرگ هر اسکلت، شانس (Random) دراپ شدن کلید بررسی میشود. تا زمانی که بازیکن موفق به دریافت **«کلید اسکلت»** نشود، سیستم اجازه ورود به مرحله نهایی را به او نخواهد داد.
|
||||
|
||||
---
|
||||
|
||||
## Evaluation Criteria ⚖
|
||||
## 🏗️ ساختار درختی پکیجهای پروژه (Project Structure)
|
||||
|
||||
| **Criteria** | **Points** |
|
||||
|-------------------------------------------------------------|------------|
|
||||
| Proper use of OOP principles | **50** |
|
||||
| Working combat mechanics, Leveling System & Enemy abilities | **20** |
|
||||
| Clear and Comprehensive `README.md` | **20** |
|
||||
| Code readability, documentation, and comments | **10** |
|
||||
| Meaningful, interactive, & colored console outputs | **10** |
|
||||
| Inventory (item) and Merchant System (bonus) | **20** |
|
||||
| Other Extra features (bonus tasks) | **20** |
|
||||
| **Total Score** | **150** |
|
||||
|
||||
## Tips 🚀
|
||||
- **Follow OOP principles**: Avoid redundant code by using inheritance properly. Think carefully about what belongs in an abstract class vs. a specific subclass. Make sure you use overriding and overloading correctly.
|
||||
- **Test your code**: Run different scenarios (fighting, running out of mana, leveling up, dying) to ensure everything works as expected.
|
||||
- **Ask for help**: If you're stuck, reach out to your classmates or mentors.
|
||||
|
||||
## Submission ⌛
|
||||
- **Deadline**: Submit your assignment before **21 Ordibehesht (May 11th, 2026)**.
|
||||
- **Submission Format**: Push your code to your forked repository, create a PR, and ensure your comprehensive `README.md` is included in the root directory.
|
||||
|
||||

|
||||
###### - Born of God and Void. You shall seal the blinding light that plagues their dreams. You are the Vessel. You are the Java Knight.
|
||||
```text
|
||||
src/
|
||||
└── org/
|
||||
└── project/
|
||||
├── Main.java (کنترلر اصلی و لوپ بازی)
|
||||
├── entity/
|
||||
│ ├── Entity.java (اینترفیس پایه)
|
||||
│ ├── enemies/
|
||||
│ │ ├── Enemy.java (کلاس انتزاعی دشمنان)
|
||||
│ │ └── Skeleton.java (مکانیک اسکلت)
|
||||
│ └── players/
|
||||
│ ├── Player.java (کلاس انتزاعی بازیکن)
|
||||
│ └── Knight.java (حرکات پنجگانه شوالیه)
|
||||
├── item/
|
||||
│ ├── Item.java (اینترفیس آیتمها)
|
||||
│ ├── armors/
|
||||
│ │ ├── Armor.java
|
||||
│ │ └── KnightArmor.java
|
||||
│ ├── consumables/
|
||||
│ │ ├── Consumable.java
|
||||
│ │ └── Flask.java
|
||||
│ └── weapons/
|
||||
│ ├── Weapon.java
|
||||
│ └── Sword.java
|
||||
└── location/
|
||||
└── Location.java (مدیریت گراف لوکیشنها)
|
||||
|
||||
Reference in New Issue
Block a user