diff --git a/src/main/java/Combat/HasConditions.java b/src/main/java/Combat/HasConditions.java new file mode 100644 index 0000000..0ae5145 --- /dev/null +++ b/src/main/java/Combat/HasConditions.java @@ -0,0 +1,9 @@ +package Combat; + +import java.util.List; + +public interface HasConditions { + void addCondition(String condition); + void removeCondition(String condition); + List getConditions(); +} diff --git a/src/main/java/Combat/OffensiveDamageSpell.java b/src/main/java/Combat/OffensiveDamageSpell.java index 05bea11..43ed65c 100644 --- a/src/main/java/Combat/OffensiveDamageSpell.java +++ b/src/main/java/Combat/OffensiveDamageSpell.java @@ -3,9 +3,11 @@ package Combat; import Entity.Entity; public class OffensiveDamageSpell extends Spell { + private final int potency; - public OffensiveDamageSpell(String spellName, int cost, int potency) { - super(spellName, cost, potency); + public OffensiveDamageSpell(String spellName, int cost, int range, int potency) { + super(spellName, cost, range); + this.potency = potency; } @Override @@ -15,4 +17,6 @@ public class OffensiveDamageSpell extends Spell { health.setHealth(health.getHealth() - this.getPotency()); } } + + public int getPotency() {return potency;} } diff --git a/src/main/java/Combat/OffensiveStatusSpell.java b/src/main/java/Combat/OffensiveStatusSpell.java new file mode 100644 index 0000000..9f0ab27 --- /dev/null +++ b/src/main/java/Combat/OffensiveStatusSpell.java @@ -0,0 +1,22 @@ +package Combat; + +import Entity.Entity; + +public class OffensiveStatusSpell extends Spell { + + private final String status; + + public OffensiveStatusSpell(String spellName, int cost, int range, String status) { + super(spellName, cost, range); + this.status = status; + } + + public void cast(Entity source, Entity target) { + if(source instanceof HasMana mana && target instanceof HasConditions conditions) { + mana.setMana(mana.getMana() - this.getCost()); + conditions.addCondition(this.getStatus()); + } + } + + public String getStatus() {return status;} +} diff --git a/src/main/java/Combat/Spell.java b/src/main/java/Combat/Spell.java index 927442b..c675c26 100644 --- a/src/main/java/Combat/Spell.java +++ b/src/main/java/Combat/Spell.java @@ -4,13 +4,13 @@ import Entity.Entity; public abstract class Spell { private final String spellName; - private int cost; - private int potency; + private final int cost; + private final int range; - public Spell(String spellName, int cost, int potency) { + public Spell(String spellName, int cost, int range) { this.spellName = spellName; this.cost = cost; - this.potency = potency; + this.range = range; } public String getSpellName() { @@ -21,9 +21,7 @@ public abstract class Spell { return cost; } - public int getPotency() { - return potency; - } + public int getRange() {return range;} public abstract void cast(Entity source, Entity target); @@ -35,7 +33,7 @@ public abstract class Spell { Spell spell = (Spell) o; if (cost != spell.cost) return false; - if (potency != spell.potency) return false; + if (range != spell.range) return false; return spellName.equals(spell.spellName); } @@ -43,12 +41,12 @@ public abstract class Spell { public int hashCode() { int result = spellName.hashCode(); result = 31 * result + cost; - result = 31 * result + potency; + result = 31 * result + range; return result; } @Override public String toString() { - return spellName + " (Cost: " + cost + ", Potency: " + potency + ")"; + return spellName + " (Cost: " + cost + ", Range: " + range + ")"; } } \ No newline at end of file diff --git a/src/main/java/Entity/Entity.java b/src/main/java/Entity/Entity.java index 5492543..bfb22a5 100644 --- a/src/main/java/Entity/Entity.java +++ b/src/main/java/Entity/Entity.java @@ -1,13 +1,39 @@ package Entity; +import java.util.ArrayList; +import java.util.List; + public abstract class Entity implements HasPosition { protected String name; protected Position position; - + private static final List entities = new ArrayList(); public Entity(String name) { this.name = name; + entities.add(this); } + public static List getEntities() { + return entities; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + + Entity entity = (Entity) obj; + + return name.equals(entity.name); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override public String toString() { + return name; + } } diff --git a/src/main/java/Entity/Player.java b/src/main/java/Entity/Player.java index a7cb7f3..c621511 100644 --- a/src/main/java/Entity/Player.java +++ b/src/main/java/Entity/Player.java @@ -2,6 +2,7 @@ package Entity; import Action.Action; import Action.Actor; +import Combat.HasConditions; import Combat.HasHealth; import Combat.HasMana; import Combat.Spell; @@ -14,13 +15,14 @@ import Inventory.HasSpellBook; import java.util.LinkedList; import java.util.List; -public class Player extends Entity implements Movable, Actor, HasInventory, HasSpellBook, HasJob, HasHealth, HasMana { +public class Player extends Entity implements Movable, Actor, HasInventory, HasSpellBook, HasJob, HasHealth, HasMana, HasConditions { protected int health; protected int mana; protected Job job; protected Position position = new Position(0,0); protected Inventory inventory= new Inventory(); protected List spells = new LinkedList<>(); + protected List conditions = new LinkedList<>(); public Player(String name, Job job) { super(name); this.job = job; @@ -57,6 +59,15 @@ public class Player extends Entity implements Movable, Actor, HasInventory, HasS public List getSpellBook() {return spells;} + @Override + public List getConditions() {return conditions;} + + @Override + public void addCondition(String condition) {this.conditions.add(condition);} + + @Override + public void removeCondition(String condition) {this.conditions.remove(condition);} + @Override public void performAction(Action action) { action.execute(this); diff --git a/src/main/java/Job/Wizard.java b/src/main/java/Job/Wizard.java index db06bf4..1f7ea33 100644 --- a/src/main/java/Job/Wizard.java +++ b/src/main/java/Job/Wizard.java @@ -6,7 +6,10 @@ import Combat.OffensiveDamageSpell; import Entity.Entity; import Inventory.HasSpellBook; import Combat.Spell; +import Entity.Position; +import java.util.LinkedList; +import java.util.List; import java.util.Scanner; public class Wizard extends Job { @@ -22,7 +25,7 @@ public class Wizard extends Job { public void learnSpell(Actor actor) { if(actor instanceof HasSpellBook a ) { - OffensiveDamageSpell defaultSpell = new OffensiveDamageSpell("fireball", 20, 20); + OffensiveDamageSpell defaultSpell = new OffensiveDamageSpell("fireball", 20, 1,20); a.getSpellBook().add(defaultSpell); } } @@ -48,9 +51,10 @@ public class Wizard extends Job { } Spell spell = spellbook.getSpellBook().get(spellIndex - 1); + Entity target = selectSpellTarget(spell, entity); if (mana.getMana() >= spell.getCost()){ - spell.cast(entity, entity); + spell.cast(entity, target); } else{ System.out.println("Not enough mana!"); @@ -58,6 +62,36 @@ public class Wizard extends Job { } } + public Entity selectSpellTarget(Spell spell, Entity caster) { + int range = spell.getRange(); + Position position = caster.getPosition(); + int x = position.x(); + int y = position.y(); + List acceptableTargets = new LinkedList<>(); + for(Entity entity : Entity.getEntities()) { + if(x + range >= entity.getPosition().x() && x - range <= entity.getPosition().x()) { + if(y + range >= entity.getPosition().y() && y - range <= entity.getPosition().y()) { + acceptableTargets.add(entity); + } + } + } + + System.out.println("Who do you want to target with the spell?"); + for(int i = 0; i < acceptableTargets.size(); i++){ + System.out.println((i + 1) + ". " + acceptableTargets.get(i).toString()); + } + + int EntityIndex = scanner.nextInt(); + scanner.nextLine(); + + if(EntityIndex < 1 || EntityIndex > acceptableTargets.size()) { + System.out.println("Invalid choice!"); + return null; + } + + return acceptableTargets.get(EntityIndex - 1); + } + @Override public int getExperience() { return experience; diff --git a/src/test/java/InterestingTests.java b/src/test/java/InterestingTests.java index 365a456..2a83676 100644 --- a/src/test/java/InterestingTests.java +++ b/src/test/java/InterestingTests.java @@ -1,4 +1,9 @@ import Combat.OffensiveDamageSpell; + +import Combat.OffensiveStatusSpell; + +import Entity.Position; +import Entity.Entity; import Entity.Player; import Job.Wizard; import org.junit.jupiter.api.BeforeEach; @@ -10,6 +15,9 @@ import static org.hamcrest.Matchers.*; import static org.hamcrest.MatcherAssert.assertThat; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import static org.junit.jupiter.api.Assertions.*; public class InterestingTests { @@ -20,9 +28,14 @@ public class InterestingTests { wizard = new Wizard(); } + @BeforeEach + public void cleanup() { + Entity.getEntities().clear(); + } + @Test public void testCastSpell_successfulCast() { - Scanner testScanner = new Scanner(new ByteArrayInputStream("1\n".getBytes())); + Scanner testScanner = new Scanner(new ByteArrayInputStream("1\n1\n".getBytes())); wizard = new Wizard(testScanner); Player player = new Player("Gandalf", wizard); @@ -30,36 +43,92 @@ public class InterestingTests { player.setMana(50); player.setHealth(100); - OffensiveDamageSpell fireball = new OffensiveDamageSpell("Fireball", 20, 15); + OffensiveDamageSpell fireball = new OffensiveDamageSpell("Fireball", 20, 1,15); player.getSpellBook().add(fireball); int initialMana = player.getMana(); - int initialHealth = player.getHealth(); wizard.castSpell(player); assertThat(player.getMana(), is(initialMana - fireball.getCost())); - assertThat(player.getHealth(), is(initialHealth - fireball.getPotency())); } @Test public void testCastSpell_notEnoughMana() { - Scanner testScanner = new Scanner(new ByteArrayInputStream("1\n".getBytes())); + Scanner testScanner = new Scanner(new ByteArrayInputStream("1\n1\n".getBytes())); wizard = new Wizard(testScanner); Player player = new Player("Merlin", wizard); player.setMana(10); player.setHealth(100); - OffensiveDamageSpell fireball = new OffensiveDamageSpell("Fireball", 20, 15); + OffensiveDamageSpell fireball = new OffensiveDamageSpell("Fireball", 20, 1,15); player.getSpellBook().add(fireball); int initialMana = player.getMana(); - int initialHealth = player.getHealth(); wizard.castSpell(player); assertThat(player.getMana(), is(initialMana)); - assertThat(player.getHealth(),is(initialHealth)); + } + + @Test + public void testCastSpell_indexOutOfBounds() { + Scanner testScanner = new Scanner(new ByteArrayInputStream("2\n".getBytes())); + wizard = new Wizard(testScanner); + + Player player = new Player("Brick", wizard); + player.setMana(50); + player.setHealth(100); + + OffensiveDamageSpell fireball = new OffensiveDamageSpell("Fireball", 20, 1, 15); + player.getSpellBook().add(fireball); + + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + PrintStream originalOut = System.out; + System.setOut(new PrintStream(outContent)); + + try { + wizard.castSpell(player); + String output = outContent.toString(); + assertTrue(output.contains("Invalid choice!")); + } finally { + System.setOut(originalOut); + } + + } + + @Test + public void condition_spell_adds_condition() { + Scanner testScanner = new Scanner(new ByteArrayInputStream("1\n1\n".getBytes())); + wizard = new Wizard(testScanner); + + Player player = new Player("Alfon", wizard); + player.setMana(50); + + OffensiveStatusSpell poisonSpray = new OffensiveStatusSpell("poisonSpray", 20, 1, "Poison"); + player.getSpellBook().add(poisonSpray); + + wizard.castSpell(player); + assertThat(player.getConditions().contains("Poison"), is(true)); + } + + @Test + public void select_spell_target_returns_correct_target() { + Scanner testScanner = new Scanner(new ByteArrayInputStream("2\n".getBytes())); + wizard = new Wizard(testScanner); + Position position = new Position(1,1); + + Player player = new Player("Alfon", wizard); + Player player2 = new Player("Bob", wizard); + player.setMana(50); + player2.moveTo(position); + + OffensiveDamageSpell fireball = new OffensiveDamageSpell("Fireball", 20, 1, 20); + player.getSpellBook().add(fireball); + + Entity target = wizard.selectSpellTarget(fireball, player); + + assertThat(target, is(player2)); } } \ No newline at end of file diff --git a/src/test/java/MagicSystemTest.java b/src/test/java/MagicSystemTest.java index 852daa2..d9aae78 100644 --- a/src/test/java/MagicSystemTest.java +++ b/src/test/java/MagicSystemTest.java @@ -4,6 +4,10 @@ import Combat.OffensiveDamageSpell; import Entity.Player; import Job.Wizard; import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + import static org.junit.jupiter.api.Assertions.*; public class MagicSystemTest { @@ -34,7 +38,7 @@ public class MagicSystemTest { } @Test void damage_spell_damages_target(){ - var defaultSpell = new OffensiveDamageSpell("fireball", 20, 20); + var defaultSpell = new OffensiveDamageSpell("fireball", 20, 1, 20); var p = defaultPlayer(); p.setMana(30); p.setHealth(30); @@ -43,7 +47,7 @@ public class MagicSystemTest { } @Test void damage_spell_drains_mana_from_caster(){ - var defaultSpell = new OffensiveDamageSpell("fireball", 20, 20); + var defaultSpell = new OffensiveDamageSpell("fireball", 20, 1, 20); var p = defaultPlayer(); p.setMana(30); p.setHealth(30); @@ -52,10 +56,22 @@ public class MagicSystemTest { } @Test void cant_cast_spell_with_empty_spellbook(){ - var p = defaultPlayer(); - var job = new Wizard(); - p.learnJob(job); - p.performAction(new CastAction()); + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + PrintStream OriginalOut = System.out; + System.setOut(new PrintStream(outContent)); + try { + var p = defaultPlayer(); + var job = new Wizard(); + p.learnJob(job); + + p.performAction(new CastAction()); + + String output = outContent.toString(); + assertTrue(output.contains("You haven't learned any spells")); + } finally { + System.setOut(OriginalOut); + } } -} + +} \ No newline at end of file diff --git a/src/test/java/PlayerTest.java b/src/test/java/PlayerTest.java index 970f0f9..8e9488f 100644 --- a/src/test/java/PlayerTest.java +++ b/src/test/java/PlayerTest.java @@ -21,18 +21,35 @@ class PlayerTest { assertFalse(p.isAlive()); } - @Test void get_health_returns_health() { + @Test + void get_health_returns_health() { var p = defaultPlayer(); p.setHealth(10); assertEquals(10, p.getHealth()); } - @Test void get_mana_returns_mana() { + @Test + void get_mana_returns_mana() { var p = defaultPlayer(); p.setMana(10); assertEquals(10, p.getMana()); } + @Test + void get_conditions_returns_conditions() { + var p = defaultPlayer(); + p.addCondition("Poison"); + assertTrue(p.getConditions().contains("Poison")); + } + + @Test + void remove_condition_removes_condition() { + var p = defaultPlayer(); + p.addCondition("Poison"); + p.removeCondition("Poison"); + assertFalse(p.getConditions().contains("Poison")); + } + @Test public void can_change_position() { var p = defaultPlayer(); @@ -62,7 +79,7 @@ class PlayerTest { void wizard_can_learn_spell() { var p = new Player("Bob"); var job = new Wizard(); - var defaultSpell = new OffensiveDamageSpell("fireball", 20, 20); + var defaultSpell = new OffensiveDamageSpell("fireball", 20, 1, 20); p.learnJob(job); p.performAction(new LearnSpellAction()); System.out.println(p.getSpellBook()); diff --git a/src/test/java/SpellTest.java b/src/test/java/SpellTest.java index 9ed92f4..2df4128 100644 --- a/src/test/java/SpellTest.java +++ b/src/test/java/SpellTest.java @@ -1,4 +1,5 @@ import Combat.OffensiveDamageSpell; +import Combat.OffensiveStatusSpell; import Combat.Spell; import org.junit.jupiter.api.Test; @@ -7,8 +8,9 @@ import static org.junit.jupiter.api.Assertions.*; public class SpellTest { private Spell defaultSpell() { - return new OffensiveDamageSpell("fireball", 20, 40); + return new OffensiveDamageSpell("fireball", 20, 1, 40); } + private Spell statusSpell() {return new OffensiveStatusSpell("poisonSpray", 20, 1, "Poison");} @Test void setSpellNameOnCreation(){ @@ -25,6 +27,12 @@ public class SpellTest { @Test void setPotencyOnCreation() { var spell = defaultSpell(); - assertEquals(40, spell.getPotency(), "spell potency should have been set"); + assertEquals(40, ((OffensiveDamageSpell) spell).getPotency(), "spell potency should have been set"); + } + + @Test + void setConditionOnCreation() { + var spell = statusSpell(); + assertEquals("Poison", ((OffensiveStatusSpell) spell).getStatus(), "spell status should have been set"); } }