19 Commits
Author SHA1 Message Date
mohammadreza e6dec6d0e8 add BurnEffect.java FreezeEffect.java PoisonEffect.java StatusEffect.java 2026-05-17 08:54:56 -07:00
mohammadreza 2d2f969fc9 add all managers 2026-05-17 08:53:37 -07:00
mohammadreza ab0e9cb3a4 add Dagger.java 2026-05-17 08:52:47 -07:00
mohammadreza 59c7671ca8 add ManaFlask.java 2026-05-17 08:52:06 -07:00
mohammadreza 42a1a97cab add combat 2026-05-17 08:51:14 -07:00
mohammadreza 4bd9823445 add GameLoop.java 2026-05-17 06:39:28 -07:00
mohammadreza e2f6bf8e27 implement Weapon.java 2026-05-17 06:37:15 -07:00
mohammadreza fc67dbb4f9 implement Sword.java 2026-05-17 06:36:03 -07:00
mohammadreza 74ae9dfc5b implement Location.java 2026-05-17 06:35:18 -07:00
mohammadreza 3cca5e91a8 implement Flask.java (renamed to HealFlask.java) 2026-05-17 06:34:06 -07:00
mohammadreza 1f187ff4d8 debug Consumable.java 2026-05-17 06:30:08 -07:00
mohammadreza 3ca0ce99db add abilities 2026-05-17 06:23:39 -07:00
mohammadreza 07fd0bad33 debug Main.java 2026-05-17 06:21:52 -07:00
mohammadreza 6a68d82f7a debug Item.java 2026-05-17 06:18:43 -07:00
mohammadreza 43421d5f25 debug Entity.java 2026-05-17 06:17:48 -07:00
mohammadreza 32f93927c8 add AssassinArmor.java DragonArmor.java GoblinArmor.java SkeletonArmor.java VampireArmor.java WizardArmor.java 2026-05-17 06:16:30 -07:00
mohammadreza 011526da36 add Assassin.java Wizard.java Knight.java Player.java 2026-05-17 06:13:28 -07:00
mohammadreza e3d7d1d554 add Dragon.java Enemy.java Goblin.java Skeleton.java Vampire.java 2026-05-17 06:11:19 -07:00
mohammadreza b25cbc6ede add Colors.java 2026-05-17 06:07:46 -07:00
48 changed files with 3039 additions and 157 deletions
@@ -0,0 +1,15 @@
package org.project;
public class Colors {
public static final String RESET = "\u001B[0m";
public static final String RED = "\u001B[31m";
public static final String GREEN = "\u001B[32m";
public static final String YELLOW = "\u001B[33m";
public static final String RED_BRIGHT = "\u001B[91m";
public static final String CYAN = "\u001B[36m";
}
@@ -0,0 +1,312 @@
package org.project;
import org.project.combat.*;
import org.project.entity.enemies.*;
import org.project.entity.players.*;
import org.project.location.Location;
import org.project.managers.*;
import java.util.*;
public class GameLoop {
private final Scanner scanner = new Scanner(System.in);
private final ActionDecisionManager actionManager = new ActionDecisionManager();
private final StatusEffectManager statusManager = new StatusEffectManager();
private final SpecialAbilityManager abilityManager = new SpecialAbilityManager();
private final ManaCostManager manaManager = new ManaCostManager();
private final TotalAttackCalculator attackCalculator =
new TotalAttackCalculator(statusManager, abilityManager, manaManager);
private Player player;
private Enemy currentEnemy;
private boolean gameRunning = true;
private boolean hasGoblinKey;
private boolean hasSkeletonKey;
private boolean hasVampireKey;
private Location currentLocation;
private final List<Location> locations = new ArrayList<>();
public GameLoop() {
initializeLocations();
}
private void initializeLocations() {
Location valhalla = new Location("Valhalla");
Location elysium = new Location("Elysium");
Location niflheim = new Location("Niflheim");
Location castle = new Location("Castle");
valhalla.connect(elysium);
valhalla.connect(niflheim);
elysium.connect(niflheim);
niflheim.connect(castle);
locations.add(valhalla);
locations.add(elysium);
locations.add(niflheim);
locations.add(castle);
currentLocation = valhalla;
}
public void start() {
System.out.println("====== JAVA KNIGHT ======");
chooseClass();
spawnEnemy();
while (gameRunning) {
showMenu();
}
System.out.println("Game Ended.");
}
private void chooseClass() {
System.out.println("""
Choose class:
1. Knight (HP:150 MP:80 DMG:12)
2. Wizard (HP:80 MP:200 DMG:10)
3. Assassin (HP:90 MP:120 DMG:15)
""");
int choice = scanner.nextInt();
switch (choice) {
case 2 -> player = new Wizard("Merlin");
case 3 -> player = new Assassin("Shadow");
default -> player = new Knight("Sir Duncan");
}
}
private void showMenu() {
System.out.println("====" + Colors.YELLOW + " GAME MENU " + Colors.RESET + "====");
System.out.println("Location: " + currentLocation.getName());
if (currentEnemy != null)
System.out.println("Enemy: " + currentEnemy);
System.out.println("""
\n1. Fight
2. Inventory
3. Move
0. Exit
""");
if (hasAllKeys())
System.out.println("4. Fight Dragon");
int choice = scanner.nextInt();
switch (choice) {
case 1 -> startCombat();
case 2 -> new InventoryManager().displayInventory(player);
case 3 -> move();
case 4 -> {
if (hasAllKeys())
fightDragon();
}
case 0 -> gameRunning = false;
}
}
private void move() {
List<Location> connected = currentLocation.getConnectedLocations();
if (connected.isEmpty()) {
System.out.println("No paths from here.");
return;
}
System.out.println("Choose destination:");
for (int i = 0; i < connected.size(); i++)
System.out.println((i + 1) + ". " + connected.get(i).getName());
int choice = scanner.nextInt();
if (choice < 1 || choice > connected.size())
return;
currentLocation = connected.get(choice - 1);
spawnEnemy();
}
private void spawnEnemy() {
Enemy[] enemies = {
new Goblin(),
new Skeleton(),
new Vampire()
};
currentEnemy = enemies[(int) (Math.random() * enemies.length)];
}
private void startCombat() {
if (currentEnemy == null) {
System.out.println("No enemy here.");
return;
}
System.out.println(Colors.RED_BRIGHT + "⚔ COMBAT STARTED! ⚔" + Colors.RESET);
while (player.isLive() && currentEnemy.isLive()) {
statusManager.tick(player);
statusManager.tick(currentEnemy);
abilityManager.tick(currentEnemy, player);
abilityManager.tick(player, currentEnemy);
if (!player.isLive() || !currentEnemy.isLive())
break;
playerTurn();
currentEnemy.resetTurnState();
if (currentEnemy.isLive())
enemyTurn();
player.resetTurnState();
}
if (player.isLive())
victory();
else
gameRunning = false;
}
private void playerTurn() {
System.out.println("====" + Colors.YELLOW + " YOUR TURN " + Colors.RESET + "====");
System.out.println(player.getName() + "-> HP: " + player.getHp() + " | MP: " + player.getMp() + " | level: " + player.getLevel() + " | XP: " + player.getXp());
System.out.println(currentEnemy.getName() + "-> HP: " + currentEnemy.getHp() + " | MP: " + currentEnemy.getMp());
System.out.println("\n");
var action = actionManager.userChooseAction();
AttackResult result = attackCalculator.calculate(player, currentEnemy, action);
int totalDamage = result.getDamageToTarget();
int healAmount = result.getHealSelf();
boolean isDefend = result.isDefended();
if (totalDamage > 0) {
System.out.println(currentEnemy.getName() + " got " + totalDamage + " damage");
currentEnemy.takeDamage(totalDamage);
}
if (healAmount > 0) {
player.heal(healAmount);
if (player.getHp() < player.getMaxHP())
System.out.println(player.getName() + "healed " + healAmount + " HP");
}
if (isDefend) {
player.defend();
System.out.println(player.getName() + " will defend (50% damage)");
}
System.out.println("\n");
}
private void enemyTurn() {
System.out.println("====" + Colors.YELLOW + " ENEMY TURN " + Colors.RESET + "====\n");
var action = actionManager.botChooseAction();
System.out.println("enemy random choose action: " + Colors.RED + action + Colors.RESET);
AttackResult result = attackCalculator.calculate(currentEnemy, player, action);
int totalDamage = result.getDamageToTarget();
int healAmount = result.getHealSelf();
boolean isDefend = result.isDefended();
if (totalDamage > 0) {
System.out.println(player.getName() + " got " + totalDamage + " damage");
player.takeDamage(totalDamage);
}
if (healAmount > 0) {
currentEnemy.heal(healAmount);
if (currentEnemy.getHp() < currentEnemy.getMaxHP())
System.out.println(currentEnemy.getName() + " healed " + healAmount + " HP");
}
if (isDefend) {
currentEnemy.defend();
System.out.println(currentEnemy.getName() + " will defend (50% damage)");
}
System.out.println("\n");
}
private void victory() {
System.out.println(Colors.GREEN + "Victory!" + Colors.RESET);
currentEnemy.rewardXp(player);
checkKeyDrop();
player.restore();
currentEnemy = null;
}
private void checkKeyDrop() {
if (Math.random() * 100 > 20)
return;
if (currentEnemy instanceof Goblin && !hasGoblinKey) {
hasGoblinKey = true;
System.out.println("Goblin Key obtained!");
}
else if (currentEnemy instanceof Skeleton && ! hasSkeletonKey) {
hasSkeletonKey = true;
System.out.println("Skeleton Key obtained!");
}
else if (currentEnemy instanceof Vampire && !hasVampireKey) {
hasVampireKey = true;
System.out.println("Vampire Key obtained!");
}
}
private boolean hasAllKeys() {
return hasGoblinKey && hasSkeletonKey && hasVampireKey;
}
private void fightDragon() {
currentEnemy = new Dragon();
System.out.println("The Dragon Appears!");
startCombat();
if (player.isLive())
System.out.println("YOU SAVED JAVANEST!");
else
System.out.println("The Dragon has defeated you...");
}
}
@@ -1,15 +1,11 @@
package org.project; package org.project;
import org.project.location.Location;
import java.util.ArrayList;
import java.util.List;
public class Main { public class Main {
public static void main(String[] args) { public static void main(String[] args) {
// TODO: ADD LOCATIONS TO YOUR GAME
List<Location> locations = new ArrayList<>();
// TODO: IMPLEMENT GAMEPLAY GameLoop game = new GameLoop();
game.start();
} }
} }
@@ -0,0 +1,34 @@
package org.project.abilities;
import org.project.entity.Entity;
public class ArcaneStorm extends SpecialAbility{
/*
Wizard use this special ability
it Becomes invisible
no longer gets damage
*/
public ArcaneStorm() {
super("ArcaneStorm",25, 3, AbilityTarget.TARGET);
}
@Override
public void onApply(Entity target) {
super.onApply(target);
}
@Override
public void onTick(Entity target) {
target.freeze();
System.out.println(target.getName() + " is steel Frozen!");
reduceDuration();
}
@Override
public void onExpire(Entity self) {
System.out.println(self.getName() + "'s special ability onExpired");
}
}
@@ -0,0 +1,35 @@
package org.project.abilities;
import org.project.entity.Entity;
public class BoneStrike extends SpecialAbility{
/*
Skeleton use this special ability
its throws bones and damage enemies
*/
private final int damage = 5;
public BoneStrike() {
super("BoneThrow",10, 3, AbilityTarget.TARGET);
}
@Override
public void onApply(Entity target) {
super.onApply(target);
}
@Override
public void onTick(Entity target) {
target.takeDamage(damage);
System.out.println(target.getName() + " suffers from " + getName());
reduceDuration();
}
@Override
public void onExpire(Entity self) {
System.out.println(self.getName() + "'s special ability onExpired");
}
}
@@ -0,0 +1,38 @@
package org.project.abilities;
import org.project.entity.Entity;
public class GuardianOath extends SpecialAbility{
/*
Knight use this special ability
The first damage and the knight is completely restrained
its gains some health
*/
public GuardianOath() {
super("GuardianOath",15, 1, AbilityTarget.SELF);
}
@Override
public void onApply(Entity target) {
super.onApply(target);
}
@Override
public void onTick(Entity self) {
self.heal(5);
self.defend();
System.out.println("Guardian Oath empowers Sir Duncan: +5 HP and 50% Decreased damage.\n ");
reduceDuration();
}
@Override
public void onExpire(Entity self) {
System.out.println(self.getName() + "'s special ability onExpired");
}
}
@@ -0,0 +1,37 @@
package org.project.abilities;
import org.project.entity.Entity;
public class InfernoBreath extends SpecialAbility{
/*
Dragon use this special ability
its fiery breath deals huge damage to the enemy
*/
private final int breathDamage = 20;
public InfernoBreath() {
super("InfernoBreath",25, 1,AbilityTarget.TARGET);
}
@Override
public void onApply(Entity target) {
super.onApply(target);
}
@Override
public void onTick(Entity target) {
target.takeDamage(breathDamage);
System.out.println("ooooh! " + getName() + " impacted with " + target.getName());
reduceDuration();
}
@Override
public void onExpire(Entity self) {
super.onExpire(self);
}
}
@@ -0,0 +1,38 @@
package org.project.abilities;
import org.project.entity.Entity;
public class LifeSteal extends SpecialAbility{
/*
vampire use this special ability
its bite's the enemy's nek
*/
private final int healAmount = 15;
public LifeSteal() {
super("SuckingBlood",15, 1,AbilityTarget.SELF);
}
@Override
public void onApply(Entity target) {
super.onApply(target);
}
@Override
public void onTick(Entity self) {
self.heal(healAmount);
System.out.println(self.getName() + " healed for " + healAmount + " (LifeSteal)");
reduceDuration();
}
@Override
public void onExpire(Entity self) {
System.out.println(self.getName() + "'s special ability onExpired");
}
}
@@ -0,0 +1,42 @@
package org.project.abilities;
import org.project.entity.Entity;
import org.project.item.weapons.Dagger;
import org.project.weaponEffects.PoisonEffect;
import org.w3c.dom.ls.LSOutput;
public class PoisonDagger extends SpecialAbility{
/*
Goblin use this special ability
applies poison effect on goblin's weapon
*/
private final int poisonDamage = 5;
public PoisonDagger() {
super("poisonDagger",15,3,AbilityTarget.SELF);
}
@Override
public void onApply(Entity target) {
super.onApply(target);
target.setWeapon(new Dagger(new PoisonEffect()));
}
@Override
public void onTick(Entity self) {
System.out.println(self.getName() + " used Poisonous Dagger ");
reduceDuration();
}
@Override
public void onExpire(Entity target) {
target.setWeapon(new Dagger());
System.out.println(target.getName() + " no longer has poisonous Dagger");
}
}
@@ -0,0 +1,48 @@
package org.project.abilities;
import org.project.entity.Entity;
public abstract class SpecialAbility {
public enum AbilityTarget {
SELF,
TARGET
}
protected String name;
protected int manaCost;
protected int duration;
private final AbilityTarget target;
public SpecialAbility(String name,int manaCost, int duration, AbilityTarget target) {
this.name = name;
this.manaCost = manaCost;
this.duration = duration;
this.target = target;
}
public AbilityTarget getTarget() {
return target;
}
public String getName() {
return name;
}
public int getManaCost() {return manaCost;}
public int getDuration() {
return duration;
}
public void reduceDuration() {duration--;}
public void onApply(Entity target) {System.out.println(target.getName() + " activated " + name);}
public abstract void onTick(Entity target);
public void onExpire(Entity target) {}
}
@@ -0,0 +1,18 @@
package org.project.combat;
public class AttackResult {
private int damageToTarget;
private int healSelf;
private boolean defended;
public AttackResult(int damageToTarget, int healSelf, boolean defended) {
this.damageToTarget = damageToTarget;
this.healSelf = healSelf;
this.defended = defended;
}
public int getDamageToTarget() { return damageToTarget; }
public int getHealSelf() { return healSelf; }
public boolean isDefended() { return defended; }
}
@@ -0,0 +1,198 @@
package org.project.combat;
import org.project.abilities.SpecialAbility;
import org.project.entity.Entity;
import org.project.entity.players.Player;
import org.project.item.armors.Armor;
import org.project.item.weapons.Weapon;
import org.project.managers.ActionDecisionManager;
import org.project.managers.ManaCostManager;
import org.project.managers.SpecialAbilityManager;
import org.project.managers.StatusEffectManager;
public class TotalAttackCalculator {
private final StatusEffectManager statusEffectManager;
private final SpecialAbilityManager specialAbilityManager;
private final ManaCostManager manaCostManager;
private static final int HEAL_AMOUNT = 25;
private static final int SHIELD_BASH_BASE_DAMAGE = 15;
private static final int SHIELD_BASH_STUN_CHANCE = 30;
public TotalAttackCalculator(
StatusEffectManager statusEffectManager,
SpecialAbilityManager specialAbilityManager,
ManaCostManager manaCostManager
) {
this.statusEffectManager = statusEffectManager;
this.specialAbilityManager = specialAbilityManager;
this.manaCostManager = manaCostManager;
}
public AttackResult calculate(
Entity attacker,
Entity defender,
ActionDecisionManager.actionsType action
) {
switch (action) {
case lightAttack:
return lightAttack(attacker, defender);
case heavyAttack:
return heavyAttack(attacker, defender);
case defend:
return defend(attacker);
case heal:
return heal(attacker);
case ability:
return ability(attacker, defender);
case shiedbash:
return shieldBash(attacker, defender);
}
return new AttackResult(0,0,false);
}
// --------------------------------
// LIGHT ATTACK
// --------------------------------
private AttackResult lightAttack(Entity attacker, Entity defender) {
int damage = attacker.getBaseDamage();
Weapon weapon = attacker.getWeapon();
if (weapon != null) {
damage += weapon.getLightAttackDamage();
if (weapon.getEffect() != null)
statusEffectManager.addEffect(weapon.getEffect(), defender);
}
damage = applyArmor(defender, damage);
if (defender.isDefending())
damage /= 2;
return new AttackResult(damage,0,false);
}
// --------------------------------
// HEAVY ATTACK
// --------------------------------
private AttackResult heavyAttack(Entity attacker, Entity defender) {
if (!manaCostManager.useHeavyAttack( attacker))
return new AttackResult(0,0,false);
int damage = attacker.getBaseDamage() * 2;
Weapon weapon = attacker.getWeapon();
if (weapon != null) {
damage += weapon.getHeavyAttackDamage();
if (weapon.getEffect() != null)
statusEffectManager.addEffect(weapon.getEffect(), defender);
}
damage = applyArmor(defender, damage);
if (defender.isDefending())
damage /= 2;
return new AttackResult(damage,0,false);
}
// --------------------------------
// DEFEND
// --------------------------------
private AttackResult defend(Entity attacker) {
if (!manaCostManager.useHeavyAttack( attacker))
return new AttackResult(0,0,false);
return new AttackResult(0,0,true);
}
// --------------------------------
// HEAL
// --------------------------------
private AttackResult heal(Entity attacker) {
if (!manaCostManager.useHeavyAttack( attacker))
return new AttackResult(0,0,false);
return new AttackResult(0,HEAL_AMOUNT,false);
}
// --------------------------------
// SPECIAL ABILITY
// --------------------------------
private AttackResult ability(Entity attacker, Entity defender) {
SpecialAbility ability = attacker.getSpacialAbility();
if (ability == null)
return new AttackResult(0,0,false);
if (attacker instanceof Player && !manaCostManager.useSpecialAbility((Player) attacker))
return new AttackResult(0,0,false);
Entity target =
ability.getTarget() == SpecialAbility.AbilityTarget.SELF
? attacker
: defender;
specialAbilityManager.addAbility(ability, target);
return new AttackResult(0,0,false);
}
// --------------------------------
// SHIELD BASH
// --------------------------------
private AttackResult shieldBash(Entity attacker, Entity defender) {
if (!manaCostManager.useHeavyAttack( attacker))
return new AttackResult(0,0,false);
Armor armor = attacker.getArmor();
if (armor == null)
return new AttackResult(0,0,false);
if (armor.getType() != Armor.ArmorType.HEAVY)
return new AttackResult(0,0,false);
int damage = SHIELD_BASH_BASE_DAMAGE + armor.getDefense() / 2;
damage = applyArmor(defender, damage);
if (Math.random() * 100 < SHIELD_BASH_STUN_CHANCE)
defender.stun();
return new AttackResult(damage,0,false);
}
// --------------------------------
// ARMOR REDUCTION
// --------------------------------
private int applyArmor(Entity defender, int rawDamage) {
Armor armor = defender.getArmor();
if (armor == null)
return rawDamage;
return armor.reduceDamage(rawDamage);
}
}
@@ -1,21 +1,90 @@
package org.project.entity; package org.project.entity;
import org.project.abilities.SpecialAbility;
import org.project.item.armors.Armor;
import org.project.item.weapons.Weapon;
import org.project.managers.StatusEffectManager;
import org.project.weaponEffects.StatusEffect;
public interface Entity { public interface Entity {
void attack(Entity target);
// =========================================================
// IDENTITY
// =========================================================
String getName();
// =========================================================
// STATS
// =========================================================
int getHp();
int getMp();
int getMaxHP();
int getMaxMP();
void useMana(int amount);
int getBaseDamage();
// =========================================================
// EQUIPMENT
// =========================================================
Weapon getWeapon();
Armor getArmor();
void setWeapon(Weapon weapon);
void setArmor(Armor armor);
Armor getPersonalArmor();
// =========================================================
// ABILITIES
// =========================================================
SpecialAbility getSpacialAbility();
void addAbilityEffect(SpecialAbility ability, Entity target);
void tickAbilityEffects(Entity target);
// =========================================================
// STATUS EFFECTS
// =========================================================
void heal(int amount);
void freeze();
void stun();
void addStatusEffect(StatusEffect effect);
void tickStatusEffects();
StatusEffectManager getEffectManager();
// // =========================================================
// // RESOURCE MANAGEMENT
// // =========================================================
//
// void useMana(int amount);
// =========================================================
// COMBAT
// =========================================================
void takeDamage(int amount);
// =========================================================
// STATES
// =========================================================
void defend(); void defend();
boolean isDefending();
boolean isFrozen();
boolean isStunned();
void resetTurnState();
void heal(int health);
void fillMana(int mana); // =========================================================
// INTERNAL SETTERS
// =========================================================
void takeDamage(int damage); void setHp(int value);
void setMp(int value);
int getMaxHP();
int getMaxMP();
/*
TODO: ADD OTHER REQUIRED AND BONUS METHODS
*/
} }
@@ -0,0 +1,47 @@
package org.project.entity.enemies;
import org.project.abilities.InfernoBreath;
import org.project.item.armors.Armor;
import org.project.item.armors.DragonArmor;
import org.project.item.weapons.Sword;
public class Dragon extends Enemy {
private static final String NAME = "Dragon";
private static final int MAX_HP = 300;
private static final int MAX_MP = 150;
private static final int XP_REWARD = 500;
private static final int BASE_DAMAGE = 30;
private final Armor personalArmor = new DragonArmor();
public Dragon() {
super(
NAME,
MAX_HP,
MAX_MP,
XP_REWARD,
BASE_DAMAGE,
null,
new Sword(),
new InfernoBreath()
);
}
@Override
public Armor getPersonalArmor() {
return personalArmor;
}
@Override
public String toString() {
return "Dragon{" +
"MAX_HP : 300 | " +
"MAX_MP : 150 | " +
"XP_REWARD : 500 | " +
"BASE_DAMAGE : 30 | " +
"personalArmor = " + personalArmor +
'}';
}
}
@@ -1,34 +1,322 @@
package org.project.entity.enemies; package org.project.entity.enemies;
import org.project.abilities.SpecialAbility;
import org.project.entity.Entity;
import org.project.entity.players.Player;
import org.project.item.armors.Armor;
import org.project.item.weapons.Weapon; import org.project.item.weapons.Weapon;
import org.project.managers.SpecialAbilityManager;
import org.project.managers.StatusEffectManager;
import org.project.weaponEffects.StatusEffect;
// TODO: UPDATE IMPLEMENTATION public abstract class Enemy implements Entity {
public abstract class Enemy {
Weapon weapon; // =========================================================
// BASIC INFO
// =========================================================
private final String name;
// =========================================================
// STATS
// =========================================================
private int xpReward;
private int maxHp;
private int hp; private int hp;
private int maxMp;
private int mp; private int mp;
public Enemy(int hp, int mp, Weapon weapon) { private int baseDamage;
this.hp = hp;
this.mp = mp;
// =========================================================
// EQUIPMENT
// =========================================================
private Armor armor;
private Weapon weapon;
// =========================================================
// ABILITIES
// =========================================================
private final SpecialAbility specialAbility;
private final StatusEffectManager effectManager;
private final SpecialAbilityManager abilityManager;
// =========================================================
// STATES
// =========================================================
private boolean defending;
private boolean frozen;
private boolean stunned;
private boolean live;
// =========================================================
// CONSTRUCTOR
// =========================================================
public Enemy(
String name,
int maxHp,
int maxMp,
int xpReward,
int baseDamage,
Armor armor,
Weapon weapon,
SpecialAbility specialAbility
) {
this.name = name;
this.maxHp = maxHp;
this.hp = maxHp;
this.maxMp = maxMp;
this.mp = maxMp;
this.xpReward = xpReward;
this.baseDamage = baseDamage;
this.armor = armor;
this.weapon = weapon; this.weapon = weapon;
this.specialAbility = specialAbility;
this.effectManager = new StatusEffectManager();
this.abilityManager = new SpecialAbilityManager();
this.live = true;
}
// =========================================================
// XP REWARD
// =========================================================
public void rewardXp(Player player) {
if (player == null) {
return;
}
player.gainXp(xpReward);
System.out.println(
player.getName() +
" gained " +
xpReward +
" XP from defeating " +
name
);
}
// =========================================================
// STATUS EFFECTS
// =========================================================
@Override
public void addStatusEffect(StatusEffect effect) {
effectManager.addEffect(effect, this);
} }
@Override @Override
public void takeDamage(int damage) { public void tickStatusEffects() {
hp -= damage; effectManager.tick(this);
} }
@Override
public StatusEffectManager getEffectManager() {
return effectManager;
}
// =========================================================
// ABILITIES
// =========================================================
@Override
public void addAbilityEffect(SpecialAbility ability, Entity target) {
abilityManager.addAbility(ability, target);
}
@Override
public void tickAbilityEffects(Entity target) {
abilityManager.tick(this, target);
}
@Override
public SpecialAbility getSpacialAbility() {
return specialAbility;
}
// =========================================================
// COMBAT
// =========================================================
@Override
public void takeDamage(int amount) {
int finalDamage = Math.max(0, amount);
hp -= finalDamage;
if (hp <= 0) {
hp = 0;
live = false;
}
}
@Override
public void heal(int amount) {
if (!live) {
return;
}
hp += amount;
if (hp > maxHp) {
hp = maxHp;
System.out.println("HP reached maximum amount " + maxHp);
}
}
@Override
public void useMana(int amount) {
if (amount <= 0) {
return;
}
if (mp < amount) {
System.out.println(name + " doesn't have enough mana!");
return;
}
mp -= amount;
}
@Override
public void defend() {
defending = true;
}
// =========================================================
// STATES
// =========================================================
@Override
public boolean isDefending() {
return defending;
}
@Override
public boolean isFrozen() {
return frozen;
}
public boolean isStunned() {return stunned;}
@Override
public void freeze() {
frozen = true;
}
public void stun() {
stunned = true;
}
@Override
public void resetTurnState() {
defending = false;
frozen = false;
stunned = false;
}
// =========================================================
// GETTERS
// =========================================================
@Override
public String getName() {
return name;
}
@Override
public int getHp() { public int getHp() {
return hp; return hp;
} }
@Override
public int getMp() { public int getMp() {
return mp; return mp;
} }
@Override
public int getMaxHP() {
return maxHp;
}
@Override
public int getMaxMP() {
return maxMp;
}
@Override
public int getBaseDamage() {
return baseDamage;
}
@Override
public Weapon getWeapon() { public Weapon getWeapon() {
return weapon; return weapon;
} }
@Override
public Armor getArmor() {
return armor;
}
@Override
public Armor getPersonalArmor() {
return armor;
}
public boolean isLive() {
return live;
}
public int getXpReward() {
return xpReward;
}
// =========================================================
// SETTERS
// =========================================================
@Override
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
@Override
public void setArmor(Armor armor) {
this.armor = armor;
}
@Override
public void setHp(int value) {
hp = Math.max(0, Math.min(value, maxHp));
}
@Override
public void setMp(int value) {
mp = Math.max(0, Math.min(value, maxMp));
}
} }
@@ -0,0 +1,47 @@
package org.project.entity.enemies;
import org.project.abilities.PoisonDagger;
import org.project.item.armors.Armor;
import org.project.item.armors.GoblinArmor;
import org.project.item.weapons.Dagger;
public class Goblin extends Enemy {
private static final String NAME = "Goblin";
private static final int MAX_HP = 45;
private static final int MAX_MP = 50;
private static final int XP_REWARD = 30;
private static final int BASE_DAMAGE = 5;
private final Armor personalArmor = new GoblinArmor();
public Goblin() {
super(
NAME,
MAX_HP,
MAX_MP,
XP_REWARD,
BASE_DAMAGE,
null,
new Dagger(),
new PoisonDagger()
);
}
@Override
public Armor getPersonalArmor() {
return personalArmor;
}
@Override
public String toString() {
return "Goblin{" +
"MAX_HP : 45 | " +
"MAX_MP : 50 | " +
"XP_REWARD : 30 | " +
"BASE_DAMAGE : 5 | " +
"personalArmor = " + personalArmor +
'}';
}
}
@@ -1,6 +1,47 @@
package org.project.entity.enemies; package org.project.entity.enemies;
// TODO: UPDATE IMPLEMENTATION import org.project.abilities.BoneStrike;
public class Skeleton { import org.project.item.armors.Armor;
// TODO: DESIGN ENEMY AND IMPLEMENT THE CONSTRUCTOR import org.project.item.armors.SkeletonArmor;
import org.project.item.weapons.Sword;
public class Skeleton extends Enemy {
private static final String NAME = "Skeleton";
private static final int MAX_HP = 40;
private static final int MAX_MP = 30;
private static final int XP_REWARD = 25;
private static final int BASE_DAMAGE = 7;
private final Armor personalArmor = new SkeletonArmor();
public Skeleton() {
super(
NAME,
MAX_HP,
MAX_MP,
XP_REWARD,
BASE_DAMAGE,
null,
new Sword(),
new BoneStrike()
);
}
@Override
public Armor getPersonalArmor() {
return personalArmor;
}
@Override
public String toString() {
return "Skeleton{" +
"MAX_HP : 40 | " +
"MAX_MP : 30 | " +
"XP_REWARD : 25 | " +
"BASE_DAMAGE : 7 | " +
"personalArmor = " + personalArmor +
'}';
}
} }
@@ -0,0 +1,47 @@
package org.project.entity.enemies;
import org.project.abilities.LifeSteal;
import org.project.item.armors.Armor;
import org.project.item.armors.VampireArmor;
import org.project.item.weapons.Dagger;
public class Vampire extends Enemy {
private static final String NAME = "Vampire";
private static final int MAX_HP = 90;
private static final int MAX_MP = 80;
private static final int XP_REWARD = 80;
private static final int BASE_DAMAGE = 12;
private final Armor personalArmor = new VampireArmor();
public Vampire() {
super(
NAME,
MAX_HP,
MAX_MP,
XP_REWARD,
BASE_DAMAGE,
null,
new Dagger(),
new LifeSteal()
);
}
@Override
public Armor getPersonalArmor() {
return personalArmor;
}
@Override
public String toString() {
return "vampire{" +
"MAX_HP : 90 | " +
"MAX_MP : 80 | " +
"XP_REWARD : 80 | " +
"BASE_DAMAGE : 12 | " +
"personalArmor = " + personalArmor +
'}';
}
}
@@ -0,0 +1,38 @@
package org.project.entity.players;
import org.project.abilities.ArcaneStorm;
import org.project.item.armors.Armor;
import org.project.item.armors.AssassinArmor;
import org.project.item.weapons.Dagger;
public class Assassin extends Player {
private static final int MAX_HP = 90;
private static final int MAX_MP = 120;
private static final int LEVEL = 1;
private static final int XP = 0;
private static final int BASE_DAMAGE = 15;
private final Armor personalArmor =
new AssassinArmor();
public Assassin(String name) {
super(
name,
MAX_HP,
MAX_MP,
LEVEL,
XP,
null,
BASE_DAMAGE,
new Dagger(),
new ArcaneStorm()
);
}
@Override
public Armor getPersonalArmor() {
return personalArmor;
}
}
@@ -1,6 +1,38 @@
package org.project.entity.players; package org.project.entity.players;
// TODO: UPDATE IMPLEMENTATION import org.project.abilities.GuardianOath;
public class Knight { import org.project.item.armors.Armor;
// TODO: DESIGN KNIGHT'S WEAPON AND ARMOR AND IMPLEMENT THE CONSTRUCTOR import org.project.item.armors.KnightArmor;
import org.project.item.weapons.Sword;
public class Knight extends Player {
private static final int MAX_HP = 150;
private static final int MAX_MP = 80;
private static final int LEVEL = 1;
private static final int XP = 0;
private static final int BASE_DAMAGE = 12;
private final Armor personalArmor =
new KnightArmor();
public Knight(String name) {
super(
name,
MAX_HP,
MAX_MP,
LEVEL,
XP,
null,
BASE_DAMAGE,
new Sword(),
new GuardianOath()
);
}
@Override
public Armor getPersonalArmor() {
return personalArmor;
}
} }
@@ -1,89 +1,359 @@
package org.project.entity.players; package org.project.entity.players;
import org.project.abilities.SpecialAbility;
import org.project.entity.Entity; import org.project.entity.Entity;
import org.project.item.armors.Armor; import org.project.item.armors.Armor;
import org.project.item.weapons.Weapon; import org.project.item.weapons.Weapon;
import org.project.managers.SpecialAbilityManager;
import org.project.managers.StatusEffectManager;
import org.project.weaponEffects.StatusEffect;
// TODO: UPDATE IMPLEMENTATION public abstract class Player implements Entity {
public abstract class Player {
protected String name; // =========================================================
Weapon weapon; // BASIC INFO
Armor armor; // =========================================================
private final String name;
private int level;
private int xp;
// =========================================================
// STATS
// =========================================================
private int maxHp;
private int hp; private int hp;
private int maxHP;
private int maxMp;
private int mp; private int mp;
private int maxMP;
public Player(String name, int hp, int mp, Weapon weapon, Armor armor) { private int baseDamage;
// =========================================================
// EQUIPMENT
// =========================================================
private Armor armor;
private Weapon weapon;
// =========================================================
// ABILITIES
// =========================================================
protected SpecialAbility specialAbility;
private final StatusEffectManager effectManager;
private final SpecialAbilityManager abilityManager;
// =========================================================
// STATES
// =========================================================
private boolean defending;
private boolean frozen;
private boolean stunned;
private boolean live;
// =========================================================
// CONSTRUCTOR
// =========================================================
public Player(
String name,
int maxHp,
int maxMp,
int level,
int xp,
Armor armor,
int baseDamage,
Weapon weapon,
SpecialAbility specialAbility
) {
this.name = name; this.name = name;
this.hp = hp;
this.mp = mp;
this.weapon = weapon; this.maxHp = maxHp;
this.hp = maxHp;
this.maxMp = maxMp;
this.mp = maxMp;
this.level = level;
this.xp = xp;
this.armor = armor; this.armor = armor;
this.baseDamage = baseDamage;
this.weapon = weapon;
this.specialAbility = specialAbility;
this.effectManager = new StatusEffectManager();
this.abilityManager = new SpecialAbilityManager();
this.defending = false;
this.frozen = false;
this.stunned = false;
this.live = true;
}
// =========================================================
// STATUS EFFECTS
// =========================================================
@Override
public void addStatusEffect(StatusEffect effect) {
effectManager.addEffect(effect, this);
} }
@Override @Override
public void attack(Entity target) { public void tickStatusEffects() {
target.takeDamage(weapon.getDamage()); effectManager.tick(this);
} }
@Override @Override
public StatusEffectManager getEffectManager() {
return effectManager;
}
// =========================================================
// ABILITIES
// =========================================================
@Override
public void addAbilityEffect(SpecialAbility ability, Entity target) {
abilityManager.addAbility(ability, target);
}
@Override
public void tickAbilityEffects(Entity target) {
abilityManager.tick(this, target);
}
@Override
public SpecialAbility getSpacialAbility() {
return specialAbility;
}
// =========================================================
// COMBAT
// =========================================================
@Override
public void takeDamage(int amount) {
int finalDamage = Math.max(0, amount);
hp -= finalDamage;
if (hp <= 0) {
hp = 0;
live = false;
}
}
public void heal(int amount) {
if (!live) {
return;
}
hp += amount;
if (hp > maxHp) {
hp = maxHp;
}
}
public void useMana(int amount) {
if (amount <= 0) {
return;
}
if (mp < amount) {
System.out.println(name + " doesn't have enough mana!");
return;
}
mp -= amount;
}
public void restoreMana(int amount) {
mp += amount;
if (mp > maxMp) {
mp = maxMp;
}
}
// =========================================================
// STATES
// =========================================================
public void defend() { public void defend() {
// TODO defending = true;
} }
public void freeze() {
frozen = true;
}
@Override public void stun() {
public void takeDamage(int damage) { stunned = true;
hp -= damage - armor.getDefense();
} }
@Override @Override
public void heal(int health) { public void resetTurnState() {
hp += health;
if (hp > maxHP) { defending = false;
hp = maxHP; frozen = false;
stunned = false;
}
public void restore() {
hp = maxHp;
mp = maxMp;
System.out.println(name + " fully restored!");
System.out.println(" HP: " + hp + "/" + maxHp + " | MP: " + mp + "/" + maxMp + "\n");
}
// =========================================================
// LEVEL SYSTEM
// =========================================================
public void gainXp(int amount) {
xp += amount;
while (xp >= level * 100) {
xp -= level * 100;
levelUp();
} }
} }
@Override public void levelUp() {
public void fillMana(int mana) {
mp += mana; level++;
if (mp > maxMP) {
mp = maxMP; maxHp += 20;
} maxMp += 10;
baseDamage += 5;
hp = maxHp;
mp = maxMp;
System.out.println(name + " leveled up!");
System.out.println("Current Level: " + level);
} }
// =========================================================
// GETTERS
// =========================================================
@Override
public String getName() { public String getName() {
return name; return name;
} }
@Override
public int getHp() { public int getHp() {
return hp; return hp;
} }
@Override @Override
public int getMaxHP() {
return maxHP;
}
public int getMp() { public int getMp() {
return mp; return mp;
} }
public int getLevel() {
return level;
}
public int getXp() {
return xp;
}
@Override
public int getMaxHP() {
return maxHp;
}
@Override @Override
public int getMaxMP() { public int getMaxMP() {
return maxMP; return maxMp;
} }
public Weapon getWeapon() { @Override
return weapon; public int getBaseDamage() {
return baseDamage;
} }
@Override
public Armor getArmor() { public Armor getArmor() {
return armor; return armor;
} }
@Override
public Weapon getWeapon() {
return weapon;
}
@Override
public Armor getPersonalArmor() {
return armor;
}
public boolean isDefending() {
return defending;
}
public boolean isFrozen() {
return frozen;
}
public boolean isStunned() {
return stunned;
}
public boolean isLive() {
return live;
}
// =========================================================
// SETTERS
// =========================================================
@Override
public void setHp(int value) {
hp = Math.max(0, Math.min(value, maxHp));
}
@Override
public void setMp(int value) {
mp = Math.max(0, Math.min(value, maxMp));
}
public void setArmor(Armor armor) {
this.armor = armor;
}
@Override
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
} }
@@ -0,0 +1,38 @@
package org.project.entity.players;
import org.project.abilities.ArcaneStorm;
import org.project.item.armors.Armor;
import org.project.item.armors.WizardArmor;
import org.project.item.weapons.Sword;
public class Wizard extends Player {
private static final int MAX_HP = 80;
private static final int MAX_MP = 200;
private static final int LEVEL = 1;
private static final int XP = 0;
private static final int BASE_DAMAGE = 10;
private final Armor personalArmor =
new WizardArmor();
public Wizard(String name) {
super(
name,
MAX_HP,
MAX_MP,
LEVEL,
XP,
null,
BASE_DAMAGE,
new Sword(),
new ArcaneStorm()
);
}
@Override
public Armor getPersonalArmor() {
return personalArmor;
}
}
@@ -3,9 +3,7 @@ package org.project.item;
import org.project.entity.Entity; import org.project.entity.Entity;
public interface Item { public interface Item {
void use(Entity target);
/* String getName();
TODO: ADD OTHER REQUIRED AND BONUS METHODS
*/
} }
@@ -1,31 +1,77 @@
package org.project.item.armors;
// TODO: UPDATE IMPLEMENTATION package org.project.item.armors;
public abstract class Armor { public class Armor {
public enum ArmorType {
LIGHT,
MEDIUM,
HEAVY
}
private String name;
private ArmorType type;
private int defense; private int defense;
private int maxDefense; private int maxDefense;
private int durability; private int durability;
private int maxDurability; private int maxDurability;
private boolean isBroke; private boolean isBroken;
public Armor(int defense, int durability) { // Constructor
this.defense = defense; public Armor(String name, ArmorType type, int maxDefense, int maxDurability) {
this.durability = durability; this.name = name;
this.type = type;
this.maxDefense = maxDefense;
this.defense = maxDefense;
this.maxDurability = maxDurability;
this.durability = maxDurability;
this.isBroken = false;
} }
public void checkBreak() {
public int reduceDamage(int damage) {
if (isBroken) {
return damage;
}
int reducedDamage = damage - defense;
if (reducedDamage < 0) {
reducedDamage = 0;
}
reduceDurability(1);
return reducedDamage;
}
public void reduceDurability(int amount) {
durability -= amount;
if (durability <= 0) { if (durability <= 0) {
isBroke = true; durability = 0;
defense = 0; breakArmor();
} }
} }
// TODO: (BONUS) UPDATE THE REPAIR METHOD // شکستن زره
public void repair() { private void breakArmor() {
isBroke = false; isBroken = true;
defense = maxDefense; defense = 0;
durability = maxDurability; }
// ===== Getters =====
public String getName() {
return name;
}
public ArmorType getType() {
return type;
} }
public int getDefense() { public int getDefense() {
@@ -36,7 +82,19 @@ public abstract class Armor {
return durability; return durability;
} }
public boolean isBroke() { public int getMaxDurability() {
return isBroke; return maxDurability;
}
public boolean isBroken() {
return isBroken;
}
@Override
public String toString() {
return name + " | Type: " + type +
" | Defense: " + defense +
" | Durability: " + durability + "/" + maxDurability +
(isBroken ? " (BROKEN)" : "");
} }
} }
@@ -0,0 +1,17 @@
package org.project.item.armors;
public class AssassinArmor extends Armor {
private static final String NAME = "wizard Robe";
private static final ArmorType ARMOR_TYPE = ArmorType.HEAVY;
private static final int MAX_DEFENSE = 35;
private static final int MAX_DURABILITY = 60;
public AssassinArmor() {
super(NAME,
ARMOR_TYPE,
MAX_DEFENSE,
MAX_DURABILITY
);
}
}
@@ -0,0 +1,17 @@
package org.project.item.armors;
public class DragonArmor extends Armor {
private static final String NAME = "Dragon scale armor";
private static final ArmorType ARMOR_TYPE = ArmorType.HEAVY;
private static final int MAX_DEFENSE = 40;
private static final int MAX_DURABILITY = 60;
public DragonArmor() {
super(NAME,
ARMOR_TYPE,
MAX_DEFENSE,
MAX_DURABILITY
);
}
}
@@ -0,0 +1,17 @@
package org.project.item.armors;
public class GoblinArmor extends Armor {
private static final String NAME = "goblin Robe";
private static final ArmorType ARMOR_TYPE = ArmorType.LIGHT;
private static final int MAX_DEFENSE = 5;
private static final int MAX_DURABILITY = 15;
public GoblinArmor() {
super(NAME,
ARMOR_TYPE,
MAX_DEFENSE,
MAX_DURABILITY
);
}
}
@@ -1,6 +1,17 @@
package org.project.item.armors; package org.project.item.armors;
// TODO: UPDATE IMPLEMENTATION public class KnightArmor extends Armor {
public class KnightArmor {
// TODO: DESIGN ARMOR'S ATTRIBUTES IMPLEMENT THE CONSTRUCTOR private static final String NAME = "knight armor";
} private static final ArmorType ARMOR_TYPE = ArmorType.HEAVY;
private static final int MAX_DEFENSE = 35;
private static final int MAX_DURABILITY = 60;
public KnightArmor() {
super(NAME,
ARMOR_TYPE,
MAX_DEFENSE,
MAX_DURABILITY
);
}
}
@@ -0,0 +1,17 @@
package org.project.item.armors;
public class SkeletonArmor extends Armor {
private static final String NAME = "skeleton armor";
private static final ArmorType ARMOR_TYPE = ArmorType.LIGHT;
private static final int MAX_DEFENSE = 15;
private static final int MAX_DURABILITY = 20;
public SkeletonArmor() {
super(NAME,
ARMOR_TYPE,
MAX_DEFENSE,
MAX_DURABILITY
);
}
}
@@ -0,0 +1,17 @@
package org.project.item.armors;
public class VampireArmor extends Armor {
private static final String NAME = "vampire armor";
private static final ArmorType ARMOR_TYPE = ArmorType.MEDIUM;
private static final int MAX_DEFENSE = 16;
private static final int MAX_DURABILITY = 30;
public VampireArmor() {
super(NAME,
ARMOR_TYPE,
MAX_DEFENSE,
MAX_DURABILITY
);
}
}
@@ -0,0 +1,17 @@
package org.project.item.armors;
public class WizardArmor extends Armor {
private static final String NAME = "wizard Robe";
private static final ArmorType ARMOR_TYPE = ArmorType.MEDIUM;
private static final int MAX_DEFENSE = 20;
private static final int MAX_DURABILITY = 20;
public WizardArmor() {
super(NAME,
ARMOR_TYPE,
MAX_DEFENSE,
MAX_DURABILITY
);
}
}
@@ -1,8 +1,40 @@
package org.project.item.consumables; package org.project.item.consumables;
import org.project.entity.players.Player;
// TODO: UPDATE IMPLEMENTATION // TODO: UPDATE IMPLEMENTATION
public abstract class Consumable { public abstract class Consumable {
/* /*
TODO: ADD OTHER REQUIRED AND BONUS METHODS TODO: ADD OTHER REQUIRED AND BONUS METHODS
*/ */
private String name;
private int healAmount;
private int charges;
public Consumable(String name, int healAmount, int charges) {
this.name = name;
this.healAmount = healAmount;
this.charges = charges;
}
public void use(Player target) {
if (charges <= 0) {
System.out.println("The flask is empty!");
return;
}
target.heal(healAmount);
charges--;
}
public int getCharges() {
return charges;
}
public String getName() {
return name;
}
} }
@@ -1,16 +0,0 @@
package org.project.item.consumables;
import org.project.entity.Entity;
// TODO: UPDATE IMPLEMENTATION
public class Flask {
/*
THIS IS AN EXAMPLE OF A CONSUMABLE DESIGN.
*/
// TODO: UPDATE USE METHOD
@Override
public void use(Entity target) {
target.heal(target.getMaxHP() / 10);
}
}
@@ -0,0 +1,24 @@
package org.project.item.consumables;
import org.project.entity.Entity;
import org.project.entity.players.Player;
import org.project.item.Item;
public class HealFlask extends Consumable {
private int healAmount;
public HealFlask(String name, int healAmount, int charges) {
super(name, healAmount, charges);
}
public void use(Player target) {
super.use(target);
System.out.println(target.getName() + " healed for " + healAmount);
}
}
@@ -0,0 +1,23 @@
package org.project.item.consumables;
import org.project.entity.Entity;
import org.project.entity.players.Player;
import org.project.item.Item;
public class ManaFlask extends Consumable {
private int manaAmount;
public ManaFlask(String name, int manaAmount, int charges) {
super(name, manaAmount, charges);
}
public void use(Player target) {
super.use(target);
System.out.println(target.getName() + " got " + manaAmount + " mana");
}
}
@@ -0,0 +1,26 @@
package org.project.item.weapons;
import org.project.weaponEffects.StatusEffect;
public class Dagger extends Weapon {
private static final String NAME = "Sword";
private static final int LIGHT_DAMAGE = 10;
private static final int HEAVY_DAMAGE = 5;
private static final int DURABILITY = 4;
public Dagger() {
this(null);
}
public Dagger(StatusEffect weaponEffect) {
super(
NAME,
LIGHT_DAMAGE,
HEAVY_DAMAGE,
weaponEffect,
DURABILITY
);
}
}
@@ -1,26 +1,26 @@
package org.project.item.weapons; package org.project.item.weapons;
import org.project.entity.Entity; import org.project.weaponEffects.StatusEffect;
import java.util.ArrayList; public class Sword extends Weapon {
// TODO: UPDATE IMPLEMENTATION private static final String NAME = "Sword";
public class Sword { private static final int LIGHT_DAMAGE = 10;
/* private static final int HEAVY_DAMAGE = 5;
THIS IS AN EXAMPLE OF A WEAPON DESIGN. private static final int DURABILITY = 4;
*/
int abilityCharge;
public Sword() { public Sword() {
// TODO: DESIGN SWORD'S ATTRIBUTES IMPLEMENT THE CONSTRUCTOR this(null);
} }
// TODO: (BONUS) UPDATE THE UNIQUE ABILITY public Sword(StatusEffect weaponEffect) {
public void uniqueAbility(ArrayList<Entity> targets) {
abilityCharge += 2; super(
for (Entity target : targets) { NAME,
target.takeDamage(getDamage()); LIGHT_DAMAGE,
} HEAVY_DAMAGE,
weaponEffect,
DURABILITY
);
} }
} }
@@ -1,35 +1,48 @@
package org.project.item.weapons; package org.project.item.weapons;
import org.project.entity.Entity; import org.project.weaponEffects.StatusEffect;
import org.project.item.Item;
// TODO: UPDATE IMPLEMENTATION // TODO: UPDATE IMPLEMENTATION
public abstract class Weapon { public abstract class Weapon implements Item {
private int damage;
private int manaCost;
/* private String name;
TODO: ADD OTHER REQUIRED AND BONUS ATTRIBUTES private StatusEffect effect;
*/ private int lightAttackDamage;
private int heavyAttackDamage;
private int equipManaCost;
public Weapon(int damage, int manaCost) {
this.damage = damage; public Weapon(String name,int heavyAttackDamage,int lightAttackDamage, StatusEffect statusEffect, int equipManaCost) {
this.manaCost = manaCost; this.name = name;
this.lightAttackDamage = lightAttackDamage;
this.heavyAttackDamage = heavyAttackDamage;
this.effect = statusEffect;
this.equipManaCost = equipManaCost;
} }
public int getHeavyAttackDamage() {
return heavyAttackDamage;
}
public int getLightAttackDamage() {
return lightAttackDamage;
}
public StatusEffect getEffect() {
return effect;
}
public void setEffect(StatusEffect effect) {
this.effect = effect;
}
@Override @Override
public void use(Entity target) { public String getName() {
target.takeDamage(damage); return name;
} }
public int getDamage() {
return damage;
}
public int getManaCost() {
return manaCost;
}
/*
TODO: ADD OTHER REQUIRED AND BONUS METHODS
*/
} }
@@ -3,26 +3,75 @@ package org.project.location;
import org.project.entity.enemies.Enemy; import org.project.entity.enemies.Enemy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Location { public class Location {
private String name;
private ArrayList<Enemy> enemies; private final String name;
public Location(ArrayList<Location> locations, ArrayList<Enemy> enemies) { private final List<Location> connectedLocations;
this.locations = locations; private final List<Enemy> enemies;
this.enemies = enemies;
public Location(String name) {
this.name = name;
this.connectedLocations = new ArrayList<>();
this.enemies = new ArrayList<>();
}
public Location(String name, List<Location> connectedLocations, List<Enemy> enemies) {
this.name = name;
this.connectedLocations =
connectedLocations != null ? new ArrayList<>(connectedLocations) : new ArrayList<>();
this.enemies =
enemies != null ? new ArrayList<>(enemies) : new ArrayList<>();
} }
public String getName() { public String getName() {
return name; return name;
} }
public ArrayList<Location> getLocations() { public List<Location> getConnectedLocations() {
return locations; return Collections.unmodifiableList(connectedLocations);
} }
public ArrayList<Enemy> getEnemies() { public List<Enemy> getEnemies() {
return enemies; return Collections.unmodifiableList(enemies);
}
// ------------------------------------
// ADD / REMOVE LOCATIONS
// ------------------------------------location
public void connect(Location other) {
if (other == null || other == this) return;
if (!connectedLocations.contains(other)) {
connectedLocations.add(other);
}
if (!other.connectedLocations.contains(this)) {
other.connectedLocations.add(this);
}
}
public void removeLocation(Location location) {
connectedLocations.remove(location);
}
// ------------------------------------
// ADD / REMOVE ENEMIES
// ------------------------------------
public void addEnemy(Enemy enemy) {
if (enemy != null) {
enemies.add(enemy);
}
}
public void removeEnemy(Enemy enemy) {
enemies.remove(enemy);
} }
} }
@@ -0,0 +1,74 @@
package org.project.managers;
import java.util.Random;
import java.util.Scanner;
public class ActionDecisionManager {
public enum actionsType {
lightAttack,
heavyAttack,
defend,
heal,
ability,
shiedbash,
inventory
}
private Random random = new Random();
public actionsType userChooseAction() {
actionsType res = null;
while (true) {
System.out.println("Choose attack type:\n");
System.out.println("1.lightAttack");
System.out.println("2.heavyAttack");
System.out.println("3.heal");
System.out.println("4.defend");
System.out.println("5.ability");
System.out.println("6.shielBash");
System.out.println("7.inventory");
int choice = new Scanner(System.in).nextInt();
switch (choice) {
case 1:
return actionsType.lightAttack;
case 2:
return actionsType.heavyAttack;
case 3:
return actionsType.heal;
case 4:
return actionsType.defend;
case 5:
return actionsType.ability;
case 6:
return actionsType.shiedbash;
case 7:
return actionsType.inventory;
default:
return actionsType.lightAttack;
}
}
}
public actionsType botChooseAction() {
actionsType[] possibleActions = {
actionsType.lightAttack,
actionsType.heavyAttack,
actionsType.defend,
actionsType.heal
};
return possibleActions[random.nextInt(possibleActions.length)];
}
}
@@ -0,0 +1,234 @@
package org.project.managers;
import org.project.Colors;
import org.project.entity.players.Player;
import org.project.item.consumables.HealFlask;
import org.project.item.consumables.ManaFlask;
import org.project.item.weapons.Dagger;
import org.project.item.weapons.Sword;
import org.project.weaponEffects.BurnEffect;
import org.project.weaponEffects.FreezeEffect;
import org.project.weaponEffects.PoisonEffect;
import java.awt.*;
import java.util.Scanner;
public class InventoryManager {
private final HealFlask healFlask = new HealFlask("Heal Flask", 30, 3);
private final ManaFlask manaFlask = new ManaFlask("Mana Flask", 20, 2);
private final Scanner scanner = new Scanner(System.in);
private final ManaCostManager manager = new ManaCostManager();
public void displayInventory(Player player) {
while (true) {
System.out.println("\n========" + Colors.YELLOW + " INVENTORY " + Colors.RESET + "========");
System.out.println("""
1. Equip Armor
2. Equip / Change Weapon
3. Equip / Change Weapon Effect
4. Use Flask
0. Exit
""");
int input = scanner.nextInt();
if (input < 0 || input > 4) {
System.out.println("Enter a number between [0 - 3]");
continue;
}
switch (input) {
// =========================
// Exit
// =========================
case 0:
System.out.println("Closing inventory...");
return;
// =========================
// Armor
// =========================
case 1:
if (player.getArmor() != null) {
System.out.println(
player.getName() +
Color.GREEN+
" already has armor: " +
Colors.RESET +
player.getArmor().getName()
);
} else {
manager.equipArmor(player, player.getPersonalArmor());
}
break;
// =========================
// Weapon
// =========================
case 2:
System.out.println("\n---" + Colors.YELLOW + " Weapons " + Colors.RESET + "---");
System.out.println("""
1. Sword
2. Dagger
0. Back
""");
int choice = scanner.nextInt();
if (choice < 0 || choice > 2) {
System.out.println("Enter a number between [0 - 2]");
continue;
}
switch (choice) {
case 0:
System.out.println("Coming back...");
break;
case 1:
manager.equipWeapon(
player,
new Sword(null)
);
break;
case 2:
manager.equipWeapon(player, new Dagger(null));
break;
}
break;
// =========================
// Weapon Effects
// =========================
case 3:
if (player.getWeapon() == null) {
System.out.println(Colors.RED + "Equip a weapon first!" + Colors.RESET);
break;
}
System.out.println("\n---" + Colors.YELLOW + " Weapon Effects " + Colors.RESET + "---");
System.out.println("""
1. Poison Effect
2. Freeze Effect
3. Burn Effect
0. Back
""");
int choice2 = scanner.nextInt();
if (choice2 < 0 || choice2 > 3) {
System.out.println("Enter a number between [0 - 4]");
continue;
}
switch (choice2) {
case 0:
System.out.println("Coming back...");
break;
case 1:
manager.equipStatusEffect(player, new PoisonEffect());
break;
case 2:
manager.equipStatusEffect(player, new FreezeEffect());
break;
case 3:
manager.equipStatusEffect(player, new BurnEffect());
break;
}
break;
case 4:
System.out.println("\n---" + Colors.YELLOW + " Flasks " + Colors.RESET + "---");
System.out.println("1. Heal Flask (" + healFlask.getCharges() + ")");
System.out.println("2. Mana Flask (" + manaFlask.getCharges() + ")");
System.out.println("0. Back");
int flaskChoice = scanner.nextInt();
if (flaskChoice < 0 || flaskChoice > 2) {
System.out.println("Enter a number between [0 - 2]");
continue;
}
switch (flaskChoice) {
case 0:
System.out.println("Coming back...");
break;
case 1:
if (healFlask.getCharges() <= 0) {
System.out.println(Colors.RED + "No Heal Flask charges left!" + Colors.RESET);
break;
}
healFlask.use(player);
System.out.println(
Colors.GREEN +
"Heal Flask used! Charges left: " +
healFlask.getCharges() +
Colors.RESET
);
break;
case 2:
if (manaFlask.getCharges() <= 0) {
System.out.println(Colors.RED + "No Mana Flask charges left!" + Colors.RESET);
break;
}
manaFlask.use(player);
System.out.println(
Colors.CYAN +
"Mana Flask used! Charges left: " +
manaFlask.getCharges() +
Colors.RESET
);
break;
}
break;
}
}
}
}
@@ -0,0 +1,248 @@
package org.project.managers;
import org.project.Colors;
import org.project.abilities.SpecialAbility;
import org.project.entity.Entity;
import org.project.entity.players.Player;
import org.project.item.armors.Armor;
import org.project.item.weapons.Weapon;
import org.project.weaponEffects.StatusEffect;
public class ManaCostManager {
private final int heavyAttackManaCost = 8;
private final int defendManaCost = 9;
private final int healManaCost = 12;
private final int shieldBashManaCost = 15;
// =========================
// Weapon
// =========================
public void equipWeapon(Player player, Weapon weapon) {
int manaCost = getWeaponEquipCost(weapon);
if (player.getMp() < manaCost) {
System.out.println("Not enough mana to equip weapon!");
return;
}
player.useMana(manaCost);
player.setWeapon(weapon);
System.out.println(
player.getName() +
" equipped weapon: " +
weapon.getName()
);
}
// =========================
// Armor
// =========================
public void equipArmor(Player player, Armor armor) {
int manaCost = getArmorEquipCost(armor);
if (player.getMp() < manaCost) {
System.out.println(Colors.RED + "Not enough mana to equip armor!" + Colors.RESET);
return;
}
player.useMana(manaCost);
player.setArmor(armor);
System.out.println(
player.getName() +
Colors.GREEN +
" equipped armor: " +
Colors.RESET +
armor.getName()
);
}
// =========================
// Status Effect
// =========================
public void equipStatusEffect(Player player,
StatusEffect equippedEffect) {
Weapon weapon = player.getWeapon();
if (weapon == null) {
System.out.println(Colors.RED + "Equip a weapon first!" + Colors.RESET);
return;
}
int manaCost = equippedEffect.getEquipManaCost();
if (player.getMp() < manaCost) {
System.out.println(Colors.RED + "Not enough mana to equip this effect!" + Colors.RESET);
return;
}
player.useMana(manaCost);
weapon.setEffect(equippedEffect);
System.out.println(
player.getName() +
Colors.GREEN +
" equipped effect: " +
Colors.RESET +
equippedEffect.getName()
);
}
// =========================
// Special Ability
// =========================
public boolean useSpecialAbility(Entity entity) {
SpecialAbility ability = entity.getSpacialAbility();
if (ability == null) {
System.out.println(Colors.RED + "No special ability equipped!" + Colors.RESET);
return false;
}
int manaCost = ability.getManaCost();
if (entity.getMp() < manaCost) {
System.out.println(Colors.RED + "Not enough mana to use special ability!" + Colors.RESET);
return false;
}
entity.useMana(manaCost);
return true;
}
// =========================
// Heavy Attack
// =========================
public boolean useHeavyAttack(Entity entity) {
if (entity.getMp() < heavyAttackManaCost) {
System.out.println(Colors.RED + "Not enough mana!" + Colors.RESET);
return false;
}
entity.useMana(heavyAttackManaCost);
return true;
}
// =========================
// Defend
// =========================
public boolean useDefend(Entity entity) {
if (entity.getMp() < defendManaCost) {
System.out.println(Colors.RED + "Not enough mana!" + Colors.RESET);
return false;
}
entity.useMana(defendManaCost);
return true;
}
// =========================
// Heal
// =========================
public boolean useHeal(Entity entity) {
if (entity.getMp() < healManaCost) {
System.out.println(Colors.RED + "Not enough mana!" + Colors.RESET);
return false;
}
entity.useMana(healManaCost);
return true;
}
// =========================
// Shield Bash
// =========================
public boolean useShieldBash(Player player) {
Armor armor = player.getArmor();
if (armor == null) {
System.out.println(Colors.RED + "You need armor to use Shield Bash!" + Colors.RESET);
return false;
}
if (armor.getType() != Armor.ArmorType.HEAVY) {
System.out.println(Colors.RED + "Shield Bash requires HEAVY armor!" + Colors.RESET);
return false;
}
if (player.getMp() < shieldBashManaCost) {
System.out.println(Colors.RED + "Not enough mana!" + Colors.RESET);
return false;
}
player.useMana(shieldBashManaCost);
return true;
}
// =========================
// Mana Costs
// =========================
private int getArmorEquipCost(Armor armor) {
return switch (armor.getType()) {
case LIGHT -> 3;
case MEDIUM -> 6;
case HEAVY -> 10;
};
}
private int getWeaponEquipCost(Weapon weapon) {
int damage = weapon.getLightAttackDamage();
if (damage <= 10) {
return 3;
}
if (damage <= 20) {
return 6;
}
return 10;
}
}
@@ -0,0 +1,77 @@
package org.project.managers;
import org.project.abilities.*;
import org.project.entity.Entity;
import org.project.item.armors.GoblinArmor;
import javax.swing.text.Position;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class SpecialAbilityManager {
private final Map<Entity, List<SpecialAbility>> activeAbilities =
new HashMap<>();
// =========================
// Add Ability
// =========================
public void addAbility(SpecialAbility ability, Entity target) {
if (ability == null || target == null) {
return;
}
activeAbilities.putIfAbsent(target, new ArrayList<>());
ability.onApply(target);
activeAbilities.get(target).add(ability);
}
// =========================
// Update Ability Effects
// =========================
public void tick(Entity abilityUser, Entity target) {
List<SpecialAbility> abilities = activeAbilities.get(abilityUser);
if (abilities == null || abilities.isEmpty()) {
return;
}
Iterator<SpecialAbility> iterator = abilities.iterator();
while (iterator.hasNext()) {
SpecialAbility ability = iterator.next();
if (ability instanceof GuardianOath || ability instanceof PoisonDagger || ability instanceof LifeSteal)
ability.onTick(abilityUser);
if (ability instanceof InfernoBreath || ability instanceof BoneStrike || ability instanceof ArcaneStorm)
ability.onTick(target);
ability.reduceDuration();
if (ability.getDuration() <= 0) {
ability.onExpire(abilityUser);
iterator.remove();
}
}
// Cleanup empty list
if (abilities.isEmpty()) {
activeAbilities.remove(target);
}
}
}
@@ -0,0 +1,81 @@
package org.project.managers;
import org.project.entity.Entity;
import org.project.weaponEffects.StatusEffect;
import java.util.*;
public class StatusEffectManager {
private Map<Entity, List<StatusEffect>> activeEffects = new HashMap<>();
public void addEffect(StatusEffect newEffect, Entity target) {
if (newEffect == null) return;
activeEffects.putIfAbsent(target, new ArrayList<>());
List<StatusEffect> effects = activeEffects.get(target);
for (StatusEffect existing : effects) {
if (existing.getName().equals(newEffect.getName())) {
if (existing.getStackType() == null) {
return;
} else if (existing.getStackType() == StatusEffect.StackType.duration) {
existing.setDuration(existing.getDuration() + newEffect.getDuration());
} else if (existing.getStackType() == StatusEffect.StackType.damage) {
existing.setDamage(existing.getDamage()+ newEffect.getDamage());
} else if (existing.getStackType() == StatusEffect.StackType.both) {
existing.setDamage(existing.getDamage()+ newEffect.getDamage());
existing.setDuration(existing.getDuration() + newEffect.getDuration());
}
return;
}
}
effects.add(newEffect);
newEffect.onApply(target);
}
public void tick(Entity target) {
List<StatusEffect> effects = activeEffects.get(target);
if (effects == null) return;
Iterator<StatusEffect> iterator = effects.iterator();
while (iterator.hasNext()) {
StatusEffect effect = iterator.next();
effect.onTick(target);
effect.reduceDuration();
if (effect.getDuration() <= 0) {
effect.onExpire(target);
iterator.remove();
}
}
}
public boolean hasEffect(Entity target, String name) {
List<StatusEffect> effects = activeEffects.get(target);
if (effects == null) return false;
for (StatusEffect effect : effects) {
if (effect.getName().equals(name))
return true;
}
return false;
}
}
@@ -0,0 +1,16 @@
package org.project.weaponEffects;
import org.project.entity.Entity;
public class BurnEffect extends StatusEffect{
public BurnEffect() {
super("Burn", 10,5 , 3, StackType.damage);
}
@Override
public void onApply(Entity target) {
System.out.println(target.getName() + " is burned!");
}
}
@@ -0,0 +1,22 @@
package org.project.weaponEffects;
import org.project.entity.Entity;
public class FreezeEffect extends StatusEffect{
public FreezeEffect() {
super("Freeze",1,5 , 1, StatusEffect.StackType.damage);
}
@Override
public void onTick(Entity target) {
target.freeze();
super.onTick(target);
}
@Override
public void onExpire(Entity target) {
System.out.println(target.getName() + " is Frozen!");
}
}
@@ -0,0 +1,17 @@
package org.project.weaponEffects;
import org.project.entity.Entity;
public class PoisonEffect extends StatusEffect{
public PoisonEffect() {
super("Poison",10,5 , 3, StackType.damage);
}
@Override
public void onApply(Entity target) {
System.out.println(target.getName() + " is poisoned!");
}
}
@@ -0,0 +1,65 @@
package org.project.weaponEffects;
import org.project.entity.Entity;
public abstract class StatusEffect {
public enum StackType {
none, // this effect is not stackable
duration, // in duplication, just duration increases
damage,// in duplication, just damage increases
both // increases duration and damage
}
protected String name;
private int duration;
private int equipManaCost;
protected int damage;
protected StackType stackType;
public StatusEffect(String name, int damage, int equipManaCost, int duration, StackType stackType) {
this.name = name;
this.damage = damage;
this.equipManaCost = equipManaCost;
this.duration = duration;
this.stackType = stackType;
}
public String getName() { return name; }
public int getDamage() {
return damage;
}
public void setDamage(int damage) {
this.damage = damage;
}
public int getDuration() { return duration; }
public void setDuration(int duration) {
this.duration = duration;
}
public StackType getStackType() { return stackType; }
public int getEquipManaCost() {
return equipManaCost;
}
public void reduceDuration() {
duration--;
}
public void onApply(Entity target) {}
public void onTick(Entity target) {
target.takeDamage(damage);
System.out.println(target.getName() + " suffers " + damage + " damage form " + name);
reduceDuration();
}
public void onExpire(Entity target) {System.out.println(target.getName() + " is no longer suffering form " + name);}
}