From 7546876335c57240f63f638fb4830addda3ba50f Mon Sep 17 00:00:00 2001 From: zhaoan12 Date: Thu, 24 Nov 2022 18:36:19 -0500 Subject: [PATCH 01/22] Made a new class for a window for the tutorial. The text only starts changing after the map is generated and the user clicks any button. Moved the timer out of main as well. --- src/main/java/com/mg105/Main.java | 43 ++++------ .../controllers/TutorialTextController.java | 16 +++- .../java/com/mg105/entities/GiveTutorial.java | 2 +- .../mg105/entities/items/HealthPotion.java | 2 +- .../com/mg105/entities/items/MegaPotion.java | 2 +- .../mg105/entities/items/UpgradeToken.java | 2 +- .../items}/utils/ItemConstants.java | 2 +- .../items}/utils/MapConstants.java | 2 +- .../items}/utils/PartyConstants.java | 2 +- .../items}/utils/TutorialTexts.java | 3 +- .../interface_adapters/InputInterpreter.java | 8 +- .../interface_adapters/RoomInterpreter.java | 2 +- .../com/mg105/use_cases/CharacterMover.java | 2 +- .../Inventory/InventoryInteractor.java | 4 +- .../use_cases/Inventory/ItemFactory.java | 2 +- .../mg105/use_cases/PlayerGetsTutorial.java | 6 +- .../com/mg105/user_interface/MapDrawer.java | 2 +- .../user_interface/MapGeneratorButton.java | 1 + .../user_interface/TutorialTextDisplay.java | 6 +- .../user_interface/TutorialTextWindow.java | 78 +++++++++++++++++++ .../java/com/mg105/entities/ChestTest.java | 3 +- .../com/mg105/entities/InventoryTest.java | 7 +- .../Inventory/InventoryInteractorTest.java | 3 +- .../use_cases/Tutorial}/TutorialTest.java | 4 +- 24 files changed, 138 insertions(+), 66 deletions(-) rename src/main/java/com/mg105/{ => entities/items}/utils/ItemConstants.java (96%) rename src/main/java/com/mg105/{ => entities/items}/utils/MapConstants.java (86%) rename src/main/java/com/mg105/{ => entities/items}/utils/PartyConstants.java (82%) rename src/main/java/com/mg105/{ => entities/items}/utils/TutorialTexts.java (95%) create mode 100644 src/main/java/com/mg105/user_interface/TutorialTextWindow.java rename src/test/java/{ => com/mg105/use_cases/Tutorial}/TutorialTest.java (96%) diff --git a/src/main/java/com/mg105/Main.java b/src/main/java/com/mg105/Main.java index 9c1b5bbb..cf73c2dc 100644 --- a/src/main/java/com/mg105/Main.java +++ b/src/main/java/com/mg105/Main.java @@ -1,5 +1,6 @@ package com.mg105; +import com.mg105.controllers.TutorialTextController; import com.mg105.entities.*; import com.mg105.interface_adapters.InputInterpreter; import com.mg105.interface_adapters.MapGeneratorInterpreter; @@ -23,9 +24,6 @@ * The main class that sets up the clean architecture mountain group 105 game! */ public class Main extends Application { - private final TutorialTextDisplay tutorialDisplay = new TutorialTextDisplay(); - private Label bottomText; - /** * The main method. See Main.start(). * @@ -85,8 +83,10 @@ public void start(Stage primaryStage) { drawableComponents.put(Toggler.ToggleableComponent.MAIN_MENU, mainMenu); drawableComponents.put(Toggler.ToggleableComponent.MAP, mapDrawer); + TutorialTextController textChanger = new TutorialTextController(false); + CharacterMover characterMover = new CharacterMover(state, mapDrawer); - InputInterpreter inputInterpreter = new InputInterpreter(characterMover, sceneController); + InputInterpreter inputInterpreter = new InputInterpreter(characterMover, sceneController, textChanger); InputListener inputListener = new InputListener(inputInterpreter); primaryStage.addEventFilter(KeyEvent.KEY_TYPED, inputListener); @@ -94,33 +94,16 @@ public void start(Stage primaryStage) { primaryStage.setTitle("Mountain Group 105"); primaryStage.setResizable(false); primaryStage.show(); - } - - private class TutorialTimer extends AnimationTimer { - private long prevTime = 0; - - /** - * This method needs to be overridden by extending classes. It is going to - * be called in every frame while the {@code AnimationTimer} is active. - * - * @param now The timestamp of the current frame given in nanoseconds. This - * value will be the same for all {@code AnimationTimers} called - * during one frame. - */ - @Override - public void handle(long now) { - long timeChange = now - prevTime; - - // 5e9 is 5 seconds - if (timeChange > 4e9) { - prevTime = now; - tutorialDisplay.getController().nextPhase(); - int phase_num = tutorialDisplay.getController().getTutorial().currentPhase(); - String tutorialText = tutorialDisplay.getController().getTutorial().allPhases().get(phase_num); - bottomText.setText(tutorialDisplay.showBottomText(tutorialText)); - - } + // make new window for tutorial + if (state.isCurrentRoomFirstRoom()) { + TutorialTextWindow tutorialWindow = new TutorialTextWindow(textChanger); + Stage tutorialStage = new Stage(); + tutorialStage.setX(660); + tutorialStage.setY(780); + tutorialWindow.start(tutorialStage); } + } + } diff --git a/src/main/java/com/mg105/controllers/TutorialTextController.java b/src/main/java/com/mg105/controllers/TutorialTextController.java index a5c4401b..7fabdc9f 100644 --- a/src/main/java/com/mg105/controllers/TutorialTextController.java +++ b/src/main/java/com/mg105/controllers/TutorialTextController.java @@ -2,13 +2,15 @@ import com.mg105.entities.GiveTutorial; import com.mg105.use_cases.PlayerGetsTutorial; -import com.mg105.utils.TutorialTexts; +import com.mg105.entities.items.utils.TutorialTexts; public class TutorialTextController { private final PlayerGetsTutorial tutorial = new PlayerGetsTutorial(TutorialTexts.PHASES, 0, new GiveTutorial(false, false, false)); + private boolean changeText; - public TutorialTextController() { + public TutorialTextController(boolean changeText) { + this.changeText = changeText; } /** @@ -25,6 +27,16 @@ public String bottomText() { */ public void nextPhase() { this.tutorial.nextPhase(); } + /** + * Return if text should start changing + */ + public void setChangeText() { this.changeText = true; } + + /** + * Return if text should start changing + */ + public boolean changeText() { return this.changeText; } + /** * Get an instance of the PlayerGetsTutorial use case * diff --git a/src/main/java/com/mg105/entities/GiveTutorial.java b/src/main/java/com/mg105/entities/GiveTutorial.java index 2d4fea22..d4aa8b0c 100644 --- a/src/main/java/com/mg105/entities/GiveTutorial.java +++ b/src/main/java/com/mg105/entities/GiveTutorial.java @@ -1,7 +1,7 @@ package com.mg105.entities; -import com.mg105.utils.TutorialTexts; +import com.mg105.entities.items.utils.TutorialTexts; public class GiveTutorial { diff --git a/src/main/java/com/mg105/entities/items/HealthPotion.java b/src/main/java/com/mg105/entities/items/HealthPotion.java index bc6d5bf8..e49afa51 100644 --- a/src/main/java/com/mg105/entities/items/HealthPotion.java +++ b/src/main/java/com/mg105/entities/items/HealthPotion.java @@ -3,7 +3,7 @@ import com.mg105.entities.BattleCharacter; import com.mg105.entities.Consumable; import com.mg105.entities.Item; -import com.mg105.utils.ItemConstants; +import com.mg105.entities.items.utils.ItemConstants; /** * A health potion is an item that can be used to heal a character by a certain amount of points. diff --git a/src/main/java/com/mg105/entities/items/MegaPotion.java b/src/main/java/com/mg105/entities/items/MegaPotion.java index 1ceb7cf0..f1083ba4 100644 --- a/src/main/java/com/mg105/entities/items/MegaPotion.java +++ b/src/main/java/com/mg105/entities/items/MegaPotion.java @@ -3,7 +3,7 @@ import com.mg105.entities.BattleCharacter; import com.mg105.entities.Consumable; import com.mg105.entities.Item; -import com.mg105.utils.ItemConstants; +import com.mg105.entities.items.utils.ItemConstants; /** * A mega health potion is larger health potion that can be used to heal a character by a greater number of points. diff --git a/src/main/java/com/mg105/entities/items/UpgradeToken.java b/src/main/java/com/mg105/entities/items/UpgradeToken.java index 260f9e7d..7e586f9c 100644 --- a/src/main/java/com/mg105/entities/items/UpgradeToken.java +++ b/src/main/java/com/mg105/entities/items/UpgradeToken.java @@ -3,7 +3,7 @@ import com.mg105.entities.BattleCharacter; import com.mg105.entities.Consumable; import com.mg105.entities.Item; -import com.mg105.utils.ItemConstants; +import com.mg105.entities.items.utils.ItemConstants; /** * An item that is used upgrade a characters stat diff --git a/src/main/java/com/mg105/utils/ItemConstants.java b/src/main/java/com/mg105/entities/items/utils/ItemConstants.java similarity index 96% rename from src/main/java/com/mg105/utils/ItemConstants.java rename to src/main/java/com/mg105/entities/items/utils/ItemConstants.java index 69c43290..b47ac445 100644 --- a/src/main/java/com/mg105/utils/ItemConstants.java +++ b/src/main/java/com/mg105/entities/items/utils/ItemConstants.java @@ -1,4 +1,4 @@ -package com.mg105.utils; +package com.mg105.entities.items.utils; import com.mg105.entities.items.HealthPotion; diff --git a/src/main/java/com/mg105/utils/MapConstants.java b/src/main/java/com/mg105/entities/items/utils/MapConstants.java similarity index 86% rename from src/main/java/com/mg105/utils/MapConstants.java rename to src/main/java/com/mg105/entities/items/utils/MapConstants.java index 77672fb0..40314e6f 100644 --- a/src/main/java/com/mg105/utils/MapConstants.java +++ b/src/main/java/com/mg105/entities/items/utils/MapConstants.java @@ -1,4 +1,4 @@ -package com.mg105.utils; +package com.mg105.entities.items.utils; /** * Constants used in the map. diff --git a/src/main/java/com/mg105/utils/PartyConstants.java b/src/main/java/com/mg105/entities/items/utils/PartyConstants.java similarity index 82% rename from src/main/java/com/mg105/utils/PartyConstants.java rename to src/main/java/com/mg105/entities/items/utils/PartyConstants.java index 9dbfb3cb..46c26979 100644 --- a/src/main/java/com/mg105/utils/PartyConstants.java +++ b/src/main/java/com/mg105/entities/items/utils/PartyConstants.java @@ -1,4 +1,4 @@ -package com.mg105.utils; +package com.mg105.entities.items.utils; public class PartyConstants { diff --git a/src/main/java/com/mg105/utils/TutorialTexts.java b/src/main/java/com/mg105/entities/items/utils/TutorialTexts.java similarity index 95% rename from src/main/java/com/mg105/utils/TutorialTexts.java rename to src/main/java/com/mg105/entities/items/utils/TutorialTexts.java index 1d1ff3fb..296e5ff1 100644 --- a/src/main/java/com/mg105/utils/TutorialTexts.java +++ b/src/main/java/com/mg105/entities/items/utils/TutorialTexts.java @@ -1,8 +1,7 @@ -package com.mg105.utils; +package com.mg105.entities.items.utils; import java.util.Arrays; import java.util.List; -import java.util.concurrent.Phaser; public class TutorialTexts { public static final String moved = "moved"; diff --git a/src/main/java/com/mg105/interface_adapters/InputInterpreter.java b/src/main/java/com/mg105/interface_adapters/InputInterpreter.java index d28a79d6..c7ae7b45 100644 --- a/src/main/java/com/mg105/interface_adapters/InputInterpreter.java +++ b/src/main/java/com/mg105/interface_adapters/InputInterpreter.java @@ -1,5 +1,6 @@ package com.mg105.interface_adapters; +import com.mg105.controllers.TutorialTextController; import com.mg105.use_cases.CharacterMover; import org.jetbrains.annotations.NotNull; @@ -12,14 +13,17 @@ public class InputInterpreter { private final @NotNull CharacterMover mover; private final @NotNull Toggler toggler; + private final @NotNull TutorialTextController textChanger; + /** * Create a new InputInterpreter that translates keyboard inputs to appropriate function invocations. * * @param mover the character mover. */ - public InputInterpreter(@NotNull CharacterMover mover, @NotNull Toggler toggler) { + public InputInterpreter(@NotNull CharacterMover mover, @NotNull Toggler toggler, @NotNull TutorialTextController textChanger) { this.mover = mover; this.toggler = toggler; + this.textChanger = textChanger; } /** @@ -30,6 +34,8 @@ public InputInterpreter(@NotNull CharacterMover mover, @NotNull Toggler toggler) public void interpret(String key) { switch (toggler.getCurrentComponent()) { case MAP -> { + textChanger.setChangeText(); // start displaying tutorial if they click any button + switch (key) { case "w" -> mover.generateMapMoveBy(new Point(0, -1)); case "a" -> mover.generateMapMoveBy(new Point(-1, 0)); diff --git a/src/main/java/com/mg105/interface_adapters/RoomInterpreter.java b/src/main/java/com/mg105/interface_adapters/RoomInterpreter.java index b36f9b47..fe4f0cad 100644 --- a/src/main/java/com/mg105/interface_adapters/RoomInterpreter.java +++ b/src/main/java/com/mg105/interface_adapters/RoomInterpreter.java @@ -5,7 +5,7 @@ import com.mg105.entities.Room; import com.mg105.entities.TreasureChest; import com.mg105.use_cases.RoomGetter; -import com.mg105.utils.MapConstants; +import com.mg105.entities.items.utils.MapConstants; import org.jetbrains.annotations.NotNull; import java.awt.*; diff --git a/src/main/java/com/mg105/use_cases/CharacterMover.java b/src/main/java/com/mg105/use_cases/CharacterMover.java index 95612c71..4b89271b 100644 --- a/src/main/java/com/mg105/use_cases/CharacterMover.java +++ b/src/main/java/com/mg105/use_cases/CharacterMover.java @@ -1,7 +1,7 @@ package com.mg105.use_cases; import com.mg105.entities.*; -import com.mg105.utils.MapConstants; +import com.mg105.entities.items.utils.MapConstants; import org.jetbrains.annotations.NotNull; import java.awt.*; diff --git a/src/main/java/com/mg105/use_cases/Inventory/InventoryInteractor.java b/src/main/java/com/mg105/use_cases/Inventory/InventoryInteractor.java index 7e799c79..0615b63e 100644 --- a/src/main/java/com/mg105/use_cases/Inventory/InventoryInteractor.java +++ b/src/main/java/com/mg105/use_cases/Inventory/InventoryInteractor.java @@ -4,8 +4,8 @@ import com.mg105.entities.GameState; import com.mg105.outputds.ItemDetails; import com.mg105.presenter_interfaces.InventoryPresenterInterface; -import com.mg105.utils.ItemConstants; -import com.mg105.utils.PartyConstants; +import com.mg105.entities.items.utils.ItemConstants; +import com.mg105.entities.items.utils.PartyConstants; /** * This class is the only class that should directly interact with the inventory diff --git a/src/main/java/com/mg105/use_cases/Inventory/ItemFactory.java b/src/main/java/com/mg105/use_cases/Inventory/ItemFactory.java index 629cdc02..57fce75c 100644 --- a/src/main/java/com/mg105/use_cases/Inventory/ItemFactory.java +++ b/src/main/java/com/mg105/use_cases/Inventory/ItemFactory.java @@ -1,7 +1,7 @@ package com.mg105.use_cases.Inventory; import com.mg105.entities.items.*; import com.mg105.entities.Item; -import com.mg105.utils.ItemConstants; +import com.mg105.entities.items.utils.ItemConstants; import java.util.NoSuchElementException; diff --git a/src/main/java/com/mg105/use_cases/PlayerGetsTutorial.java b/src/main/java/com/mg105/use_cases/PlayerGetsTutorial.java index dff70b78..bc86669f 100644 --- a/src/main/java/com/mg105/use_cases/PlayerGetsTutorial.java +++ b/src/main/java/com/mg105/use_cases/PlayerGetsTutorial.java @@ -1,15 +1,15 @@ package com.mg105.use_cases; import com.mg105.entities.GiveTutorial; -import com.mg105.utils.TutorialTexts; +import com.mg105.entities.items.utils.TutorialTexts; import java.util.List; public class PlayerGetsTutorial { - private List tutorialPhases; // Go through multiple phases of tutorial in order + private final List tutorialPhases; // Go through multiple phases of tutorial in order private int currentPhase; - private GiveTutorial tutorial; + private final GiveTutorial tutorial; public PlayerGetsTutorial(List tutorialPhases, int currentPhase, GiveTutorial tutorial) { this.tutorialPhases = tutorialPhases; diff --git a/src/main/java/com/mg105/user_interface/MapDrawer.java b/src/main/java/com/mg105/user_interface/MapDrawer.java index 2bb30599..c57658f0 100644 --- a/src/main/java/com/mg105/user_interface/MapDrawer.java +++ b/src/main/java/com/mg105/user_interface/MapDrawer.java @@ -3,7 +3,7 @@ import com.mg105.interface_adapters.RoomInterpreter; import com.mg105.interface_adapters.TileType; import com.mg105.use_cases.RoomUpdater; -import com.mg105.utils.MapConstants; +import com.mg105.entities.items.utils.MapConstants; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.image.Image; diff --git a/src/main/java/com/mg105/user_interface/MapGeneratorButton.java b/src/main/java/com/mg105/user_interface/MapGeneratorButton.java index 819bd815..444de45d 100644 --- a/src/main/java/com/mg105/user_interface/MapGeneratorButton.java +++ b/src/main/java/com/mg105/user_interface/MapGeneratorButton.java @@ -13,6 +13,7 @@ public class MapGeneratorButton implements EventHandler { private final @NotNull MapGeneratorInterpreter interpreter; private final @NotNull Toggler toggler; + /** * Create a new MapGeneratorButton. * diff --git a/src/main/java/com/mg105/user_interface/TutorialTextDisplay.java b/src/main/java/com/mg105/user_interface/TutorialTextDisplay.java index 8f5cb1ea..b2084f0b 100644 --- a/src/main/java/com/mg105/user_interface/TutorialTextDisplay.java +++ b/src/main/java/com/mg105/user_interface/TutorialTextDisplay.java @@ -1,15 +1,13 @@ package com.mg105.user_interface; import com.mg105.controllers.TutorialTextController; -import com.mg105.utils.TutorialTexts; +import com.mg105.entities.items.utils.TutorialTexts; import javafx.scene.control.Label; import javafx.scene.text.Font; -import java.awt.*; - public class TutorialTextDisplay { - private final TutorialTextController tutorialControl = new TutorialTextController(); + private final TutorialTextController tutorialControl = new TutorialTextController(false); public TutorialTextDisplay() { } diff --git a/src/main/java/com/mg105/user_interface/TutorialTextWindow.java b/src/main/java/com/mg105/user_interface/TutorialTextWindow.java new file mode 100644 index 00000000..768a1753 --- /dev/null +++ b/src/main/java/com/mg105/user_interface/TutorialTextWindow.java @@ -0,0 +1,78 @@ +package com.mg105.user_interface; + +import com.mg105.controllers.TutorialTextController; +import com.mg105.interface_adapters.InputInterpreter; +import javafx.animation.AnimationTimer; +import javafx.application.Application; +import javafx.scene.Group; +import javafx.scene.Scene; +import javafx.scene.control.Label; +import javafx.scene.layout.Pane; +import javafx.scene.text.Font; +import javafx.stage.Stage; + +import javax.swing.plaf.ColorUIResource; +import java.awt.*; +import java.text.BreakIterator; + +public class TutorialTextWindow extends Application { + TutorialTextDisplay tutorialDisplay = new TutorialTextDisplay(); + Label bottomText = new Label(); + TutorialTextController textController; + + public TutorialTextWindow(TutorialTextController textController){ + this.textController = textController; + } + + + public static void main(String[] args) { + launch(args); + } + + @Override + public void start(Stage tutorialStage) { + Group tutorialWindow = new Group(); + Pane tutorialPane = new Pane(); + + bottomText = tutorialDisplay.tutorialLabel(); + bottomText.setFont(Font.font("Courier", 16)); + tutorialPane.getChildren().add(bottomText); + + Scene tutorialScene = new Scene(tutorialPane,550, 70); + + AnimationTimer timer = new TutorialTimer(); + timer.start(); + + tutorialStage.setScene(tutorialScene); + tutorialStage.show(); + } + private class TutorialTimer extends AnimationTimer { + private long prevTime = 0; + + /** + * This method needs to be overridden by extending classes. It is going to + * be called in every frame while the {@code AnimationTimer} is active. + * + * @param now The timestamp of the current frame given in nanoseconds. This + * value will be the same for all {@code AnimationTimers} called + * during one frame. + */ + @Override + public void handle(long now) { + long timeChange = now - prevTime; + + // 5e9 is 5 seconds + if (timeChange > 4e9 & textController.changeText()) { + prevTime = now; + tutorialDisplay.getController().nextPhase(); + String tutorialText = tutorialDisplay.getController().bottomText(); + bottomText.setText(tutorialDisplay.showBottomText(tutorialText)); + + } + + } + } + +} + + diff --git a/src/test/java/com/mg105/entities/ChestTest.java b/src/test/java/com/mg105/entities/ChestTest.java index 46bd17d6..4d258645 100644 --- a/src/test/java/com/mg105/entities/ChestTest.java +++ b/src/test/java/com/mg105/entities/ChestTest.java @@ -1,11 +1,10 @@ package com.mg105.entities; -import com.mg105.entities.*; import com.mg105.entities.items.HealthPotion; import com.mg105.outputds.ItemDetails; import com.mg105.presenter_interfaces.InventoryPresenterInterface; import com.mg105.use_cases.Inventory.InventoryInteractor; -import com.mg105.utils.PartyConstants; +import com.mg105.entities.items.utils.PartyConstants; import org.junit.jupiter.api.Test; import java.awt.*; import java.util.ArrayList; diff --git a/src/test/java/com/mg105/entities/InventoryTest.java b/src/test/java/com/mg105/entities/InventoryTest.java index aaf911d6..299fb2ee 100644 --- a/src/test/java/com/mg105/entities/InventoryTest.java +++ b/src/test/java/com/mg105/entities/InventoryTest.java @@ -1,15 +1,10 @@ package com.mg105.entities; -import com.mg105.entities.BattleCharacter; -import com.mg105.entities.Inventory; -import com.mg105.entities.Move; import com.mg105.entities.items.HealthPotion; import com.mg105.entities.items.UpgradeToken; -import com.mg105.utils.ItemConstants; +import com.mg105.entities.items.utils.ItemConstants; import org.junit.jupiter.api.Test; -import java.util.NoSuchElementException; - import static org.junit.jupiter.api.Assertions.*; class InventoryTest { diff --git a/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java b/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java index 169f3c7a..90b08f10 100644 --- a/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java +++ b/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java @@ -4,8 +4,7 @@ import com.mg105.entities.items.UpgradeToken; import com.mg105.outputds.ItemDetails; import com.mg105.presenter_interfaces.InventoryPresenterInterface; -import com.mg105.use_cases.Inventory.InventoryInteractor; -import com.mg105.utils.ItemConstants; +import com.mg105.entities.items.utils.ItemConstants; import org.junit.jupiter.api.Test; import java.awt.*; diff --git a/src/test/java/TutorialTest.java b/src/test/java/com/mg105/use_cases/Tutorial/TutorialTest.java similarity index 96% rename from src/test/java/TutorialTest.java rename to src/test/java/com/mg105/use_cases/Tutorial/TutorialTest.java index 8e585659..d7729ca6 100644 --- a/src/test/java/TutorialTest.java +++ b/src/test/java/com/mg105/use_cases/Tutorial/TutorialTest.java @@ -1,7 +1,9 @@ +package com.mg105.use_cases.Tutorial; + import com.mg105.entities.GiveTutorial; import com.mg105.use_cases.PlayerGetsTutorial; import com.mg105.user_interface.TutorialTextDisplay; -import com.mg105.utils.TutorialTexts; +import com.mg105.entities.items.utils.TutorialTexts; import org.junit.jupiter.api.Test; import java.util.Arrays; From 5150ed109adcfc4b07d83773bf569afa57885a23 Mon Sep 17 00:00:00 2001 From: zhaoan12 Date: Sat, 26 Nov 2022 18:52:22 -0500 Subject: [PATCH 02/22] New class for a window for the tutorial. The story text only starts changing after the map is generated and the user clicks any button. Pressing "K" at any time displays a tutorial for the controls of the game for a few seconds. Changed layout of first room. --- src/main/java/com/mg105/Main.java | 16 +++--- .../controllers/TutorialTextController.java | 15 +++++- .../java/com/mg105/entities/GiveTutorial.java | 2 +- .../mg105/entities/items/HealthPotion.java | 2 +- .../com/mg105/entities/items/MegaPotion.java | 2 +- .../mg105/entities/items/UpgradeToken.java | 2 +- .../entities/items/utils/TutorialTexts.java | 37 ------------- .../interface_adapters/InputInterpreter.java | 4 +- .../interface_adapters/RoomInterpreter.java | 2 +- .../com/mg105/use_cases/CharacterMover.java | 2 +- .../Inventory/InventoryInteractor.java | 4 +- .../use_cases/Inventory/ItemFactory.java | 2 +- .../com/mg105/use_cases/MapGenerator.java | 2 +- .../mg105/use_cases/PlayerGetsTutorial.java | 2 +- .../com/mg105/user_interface/MapDrawer.java | 2 +- .../user_interface/TutorialTextDisplay.java | 12 ++++- .../user_interface/TutorialTextWindow.java | 53 +++++++++++++------ .../items => }/utils/ItemConstants.java | 2 +- .../items => }/utils/MapConstants.java | 2 +- .../items => }/utils/PartyConstants.java | 2 +- .../java/com/mg105/utils/TutorialTexts.java | 49 +++++++++++++++++ .../java/com/mg105/entities/ChestTest.java | 2 +- .../com/mg105/entities/InventoryTest.java | 2 +- .../Inventory/InventoryInteractorTest.java | 2 +- .../use_cases/Tutorial/TutorialTest.java | 8 ++- 25 files changed, 142 insertions(+), 88 deletions(-) delete mode 100644 src/main/java/com/mg105/entities/items/utils/TutorialTexts.java rename src/main/java/com/mg105/{entities/items => }/utils/ItemConstants.java (96%) rename src/main/java/com/mg105/{entities/items => }/utils/MapConstants.java (86%) rename src/main/java/com/mg105/{entities/items => }/utils/PartyConstants.java (82%) create mode 100644 src/main/java/com/mg105/utils/TutorialTexts.java diff --git a/src/main/java/com/mg105/Main.java b/src/main/java/com/mg105/Main.java index cf73c2dc..977a9f83 100644 --- a/src/main/java/com/mg105/Main.java +++ b/src/main/java/com/mg105/Main.java @@ -10,9 +10,8 @@ import com.mg105.use_cases.MapGenerator; import com.mg105.use_cases.RoomGetter; import com.mg105.user_interface.*; -import javafx.animation.AnimationTimer; +import com.mg105.utils.TutorialTexts; import javafx.application.Application; -import javafx.scene.control.Label; import javafx.scene.input.KeyEvent; import javafx.stage.Stage; @@ -95,15 +94,12 @@ public void start(Stage primaryStage) { primaryStage.setResizable(false); primaryStage.show(); - // make new window for tutorial - if (state.isCurrentRoomFirstRoom()) { - TutorialTextWindow tutorialWindow = new TutorialTextWindow(textChanger); - Stage tutorialStage = new Stage(); - tutorialStage.setX(660); - tutorialStage.setY(780); - tutorialWindow.start(tutorialStage); + TutorialTextWindow tutorialWindow = new TutorialTextWindow(textChanger); + Stage tutorialStage = new Stage(); + tutorialStage.setX(TutorialTexts.tutorialTextX); + tutorialStage.setY(TutorialTexts.tutorialTextY); + tutorialWindow.start(tutorialStage); } } -} diff --git a/src/main/java/com/mg105/controllers/TutorialTextController.java b/src/main/java/com/mg105/controllers/TutorialTextController.java index 7fabdc9f..e8cf334b 100644 --- a/src/main/java/com/mg105/controllers/TutorialTextController.java +++ b/src/main/java/com/mg105/controllers/TutorialTextController.java @@ -2,12 +2,13 @@ import com.mg105.entities.GiveTutorial; import com.mg105.use_cases.PlayerGetsTutorial; -import com.mg105.entities.items.utils.TutorialTexts; +import com.mg105.utils.TutorialTexts; public class TutorialTextController { private final PlayerGetsTutorial tutorial = new PlayerGetsTutorial(TutorialTexts.PHASES, 0, new GiveTutorial(false, false, false)); private boolean changeText; + private boolean showControls = false; public TutorialTextController(boolean changeText) { this.changeText = changeText; @@ -37,6 +38,18 @@ public String bottomText() { */ public boolean changeText() { return this.changeText; } + /** + * Tell player the controls again if they forgot + */ + public void setShowControls(boolean show) { + this.showControls = show; + } + + /** + * Check if player should be shown controls again + */ + public boolean getShowControls() { return this.showControls; } + /** * Get an instance of the PlayerGetsTutorial use case * diff --git a/src/main/java/com/mg105/entities/GiveTutorial.java b/src/main/java/com/mg105/entities/GiveTutorial.java index d4aa8b0c..2d4fea22 100644 --- a/src/main/java/com/mg105/entities/GiveTutorial.java +++ b/src/main/java/com/mg105/entities/GiveTutorial.java @@ -1,7 +1,7 @@ package com.mg105.entities; -import com.mg105.entities.items.utils.TutorialTexts; +import com.mg105.utils.TutorialTexts; public class GiveTutorial { diff --git a/src/main/java/com/mg105/entities/items/HealthPotion.java b/src/main/java/com/mg105/entities/items/HealthPotion.java index e49afa51..bc6d5bf8 100644 --- a/src/main/java/com/mg105/entities/items/HealthPotion.java +++ b/src/main/java/com/mg105/entities/items/HealthPotion.java @@ -3,7 +3,7 @@ import com.mg105.entities.BattleCharacter; import com.mg105.entities.Consumable; import com.mg105.entities.Item; -import com.mg105.entities.items.utils.ItemConstants; +import com.mg105.utils.ItemConstants; /** * A health potion is an item that can be used to heal a character by a certain amount of points. diff --git a/src/main/java/com/mg105/entities/items/MegaPotion.java b/src/main/java/com/mg105/entities/items/MegaPotion.java index f1083ba4..1ceb7cf0 100644 --- a/src/main/java/com/mg105/entities/items/MegaPotion.java +++ b/src/main/java/com/mg105/entities/items/MegaPotion.java @@ -3,7 +3,7 @@ import com.mg105.entities.BattleCharacter; import com.mg105.entities.Consumable; import com.mg105.entities.Item; -import com.mg105.entities.items.utils.ItemConstants; +import com.mg105.utils.ItemConstants; /** * A mega health potion is larger health potion that can be used to heal a character by a greater number of points. diff --git a/src/main/java/com/mg105/entities/items/UpgradeToken.java b/src/main/java/com/mg105/entities/items/UpgradeToken.java index 7e586f9c..260f9e7d 100644 --- a/src/main/java/com/mg105/entities/items/UpgradeToken.java +++ b/src/main/java/com/mg105/entities/items/UpgradeToken.java @@ -3,7 +3,7 @@ import com.mg105.entities.BattleCharacter; import com.mg105.entities.Consumable; import com.mg105.entities.Item; -import com.mg105.entities.items.utils.ItemConstants; +import com.mg105.utils.ItemConstants; /** * An item that is used upgrade a characters stat diff --git a/src/main/java/com/mg105/entities/items/utils/TutorialTexts.java b/src/main/java/com/mg105/entities/items/utils/TutorialTexts.java deleted file mode 100644 index 296e5ff1..00000000 --- a/src/main/java/com/mg105/entities/items/utils/TutorialTexts.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.mg105.entities.items.utils; - -import java.util.Arrays; -import java.util.List; - -public class TutorialTexts { - public static final String moved = "moved"; - public static final String attacked = "attacked"; - public static final String usedItem = "usedItem"; - - public static final int tutorialTextX = 150; - public static final int tutorialTextY = 550; - - public static final int TEXT_DURATION1 = 5; - public static final int TEXT_DURATION2 = 10; - - public static final String textFont = "Verdana"; - public static final int textSize = 18; - - public static final List PHASES - = Arrays.asList("", "story", "tell move", "tell attack", "tell use item", "exit room"); - - public static final List PHASES_TEXT = Arrays.asList("", - TutorialTexts.STORY, TutorialTexts.TELL_MOVE, TutorialTexts.TELL_ATTACK, TutorialTexts.TELL_USE_ITEM, TutorialTexts.EXIT_ROOM); - - public static final String STORY = "Battle your way to the top of the mountain!\n" + - "Inside various rooms, you will encounter enemies and find treasures."; - - public static final String TELL_MOVE = "Move your character with the arrow keys."; - - public static final String TELL_ATTACK = "Use the attack button to attack the enemy."; - - public static final String TELL_USE_ITEM = "Pick up health potions and use them to restore hp."; - - public static final String EXIT_ROOM = "Good luck on your journey!"; - -} diff --git a/src/main/java/com/mg105/interface_adapters/InputInterpreter.java b/src/main/java/com/mg105/interface_adapters/InputInterpreter.java index c7ae7b45..3e8f87da 100644 --- a/src/main/java/com/mg105/interface_adapters/InputInterpreter.java +++ b/src/main/java/com/mg105/interface_adapters/InputInterpreter.java @@ -34,13 +34,15 @@ public InputInterpreter(@NotNull CharacterMover mover, @NotNull Toggler toggler, public void interpret(String key) { switch (toggler.getCurrentComponent()) { case MAP -> { - textChanger.setChangeText(); // start displaying tutorial if they click any button + textChanger.setChangeText(); switch (key) { case "w" -> mover.generateMapMoveBy(new Point(0, -1)); case "a" -> mover.generateMapMoveBy(new Point(-1, 0)); case "s" -> mover.generateMapMoveBy(new Point(0, 1)); case "d" -> mover.generateMapMoveBy(new Point(1, 0)); + + case "k" -> textChanger.setShowControls(true); } } } diff --git a/src/main/java/com/mg105/interface_adapters/RoomInterpreter.java b/src/main/java/com/mg105/interface_adapters/RoomInterpreter.java index fe4f0cad..b36f9b47 100644 --- a/src/main/java/com/mg105/interface_adapters/RoomInterpreter.java +++ b/src/main/java/com/mg105/interface_adapters/RoomInterpreter.java @@ -5,7 +5,7 @@ import com.mg105.entities.Room; import com.mg105.entities.TreasureChest; import com.mg105.use_cases.RoomGetter; -import com.mg105.entities.items.utils.MapConstants; +import com.mg105.utils.MapConstants; import org.jetbrains.annotations.NotNull; import java.awt.*; diff --git a/src/main/java/com/mg105/use_cases/CharacterMover.java b/src/main/java/com/mg105/use_cases/CharacterMover.java index 4b89271b..95612c71 100644 --- a/src/main/java/com/mg105/use_cases/CharacterMover.java +++ b/src/main/java/com/mg105/use_cases/CharacterMover.java @@ -1,7 +1,7 @@ package com.mg105.use_cases; import com.mg105.entities.*; -import com.mg105.entities.items.utils.MapConstants; +import com.mg105.utils.MapConstants; import org.jetbrains.annotations.NotNull; import java.awt.*; diff --git a/src/main/java/com/mg105/use_cases/Inventory/InventoryInteractor.java b/src/main/java/com/mg105/use_cases/Inventory/InventoryInteractor.java index 0615b63e..7e799c79 100644 --- a/src/main/java/com/mg105/use_cases/Inventory/InventoryInteractor.java +++ b/src/main/java/com/mg105/use_cases/Inventory/InventoryInteractor.java @@ -4,8 +4,8 @@ import com.mg105.entities.GameState; import com.mg105.outputds.ItemDetails; import com.mg105.presenter_interfaces.InventoryPresenterInterface; -import com.mg105.entities.items.utils.ItemConstants; -import com.mg105.entities.items.utils.PartyConstants; +import com.mg105.utils.ItemConstants; +import com.mg105.utils.PartyConstants; /** * This class is the only class that should directly interact with the inventory diff --git a/src/main/java/com/mg105/use_cases/Inventory/ItemFactory.java b/src/main/java/com/mg105/use_cases/Inventory/ItemFactory.java index 57fce75c..629cdc02 100644 --- a/src/main/java/com/mg105/use_cases/Inventory/ItemFactory.java +++ b/src/main/java/com/mg105/use_cases/Inventory/ItemFactory.java @@ -1,7 +1,7 @@ package com.mg105.use_cases.Inventory; import com.mg105.entities.items.*; import com.mg105.entities.Item; -import com.mg105.entities.items.utils.ItemConstants; +import com.mg105.utils.ItemConstants; import java.util.NoSuchElementException; diff --git a/src/main/java/com/mg105/use_cases/MapGenerator.java b/src/main/java/com/mg105/use_cases/MapGenerator.java index 8bde2efe..aae59613 100644 --- a/src/main/java/com/mg105/use_cases/MapGenerator.java +++ b/src/main/java/com/mg105/use_cases/MapGenerator.java @@ -48,7 +48,7 @@ public void generateMap() { new Move(-10, -10, "Move1", false), new Move(1, 1, "Move2", false)) ); - firstRoom.getOpponents().add(new OpponentSet(new Point(6, 2), firstRoomBattle)); + firstRoom.getOpponents().add(new OpponentSet(new Point(4, 6), firstRoomBattle)); // Add chests firstRoom.getChests().add(new TreasureChest(new HealthPotion(), new Point(2, 2))); diff --git a/src/main/java/com/mg105/use_cases/PlayerGetsTutorial.java b/src/main/java/com/mg105/use_cases/PlayerGetsTutorial.java index bc86669f..137e9475 100644 --- a/src/main/java/com/mg105/use_cases/PlayerGetsTutorial.java +++ b/src/main/java/com/mg105/use_cases/PlayerGetsTutorial.java @@ -1,7 +1,7 @@ package com.mg105.use_cases; import com.mg105.entities.GiveTutorial; -import com.mg105.entities.items.utils.TutorialTexts; +import com.mg105.utils.TutorialTexts; import java.util.List; diff --git a/src/main/java/com/mg105/user_interface/MapDrawer.java b/src/main/java/com/mg105/user_interface/MapDrawer.java index c57658f0..2bb30599 100644 --- a/src/main/java/com/mg105/user_interface/MapDrawer.java +++ b/src/main/java/com/mg105/user_interface/MapDrawer.java @@ -3,7 +3,7 @@ import com.mg105.interface_adapters.RoomInterpreter; import com.mg105.interface_adapters.TileType; import com.mg105.use_cases.RoomUpdater; -import com.mg105.entities.items.utils.MapConstants; +import com.mg105.utils.MapConstants; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.image.Image; diff --git a/src/main/java/com/mg105/user_interface/TutorialTextDisplay.java b/src/main/java/com/mg105/user_interface/TutorialTextDisplay.java index b2084f0b..752f43ba 100644 --- a/src/main/java/com/mg105/user_interface/TutorialTextDisplay.java +++ b/src/main/java/com/mg105/user_interface/TutorialTextDisplay.java @@ -1,7 +1,7 @@ package com.mg105.user_interface; import com.mg105.controllers.TutorialTextController; -import com.mg105.entities.items.utils.TutorialTexts; +import com.mg105.utils.TutorialTexts; import javafx.scene.control.Label; import javafx.scene.text.Font; @@ -27,6 +27,16 @@ public String showBottomText(String displayedText) { } + /** + * String for reminding user of controls + * + * @return the actual text displayed to the user + */ + public String showControlsText() { + return TutorialTexts.CONTROLS; + + } + /** * Return a label that will show at the bottom of the screen. * diff --git a/src/main/java/com/mg105/user_interface/TutorialTextWindow.java b/src/main/java/com/mg105/user_interface/TutorialTextWindow.java index 768a1753..986f46e6 100644 --- a/src/main/java/com/mg105/user_interface/TutorialTextWindow.java +++ b/src/main/java/com/mg105/user_interface/TutorialTextWindow.java @@ -1,26 +1,29 @@ package com.mg105.user_interface; import com.mg105.controllers.TutorialTextController; -import com.mg105.interface_adapters.InputInterpreter; +import com.mg105.utils.TutorialTexts; import javafx.animation.AnimationTimer; import javafx.application.Application; -import javafx.scene.Group; +import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.Label; +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; +import javafx.scene.layout.CornerRadii; import javafx.scene.layout.Pane; +import javafx.scene.paint.Color; import javafx.scene.text.Font; import javafx.stage.Stage; -import javax.swing.plaf.ColorUIResource; -import java.awt.*; -import java.text.BreakIterator; - public class TutorialTextWindow extends Application { TutorialTextDisplay tutorialDisplay = new TutorialTextDisplay(); Label bottomText = new Label(); + Label helpText = new Label(); TutorialTextController textController; - public TutorialTextWindow(TutorialTextController textController){ + Pane tutorialPane = new Pane(); + + public TutorialTextWindow(TutorialTextController textController) { this.textController = textController; } @@ -31,14 +34,18 @@ public static void main(String[] args) { @Override public void start(Stage tutorialStage) { - Group tutorialWindow = new Group(); - Pane tutorialPane = new Pane(); - bottomText = tutorialDisplay.tutorialLabel(); - bottomText.setFont(Font.font("Courier", 16)); + bottomText.setFont(Font.font(TutorialTexts.textFont1, TutorialTexts.textSize)); + + helpText = tutorialDisplay.tutorialLabel(); + helpText.setFont(Font.font(TutorialTexts.textFont2, TutorialTexts.textSize)); + helpText.setBackground(new Background(new BackgroundFill(Color.rgb(255, 215, 0, 1), + new CornerRadii(30.0), new Insets(-40.0)))); + tutorialPane.getChildren().add(bottomText); + tutorialPane.getChildren().add(helpText); - Scene tutorialScene = new Scene(tutorialPane,550, 70); + Scene tutorialScene = new Scene(tutorialPane, TutorialTexts.helperPaneX, TutorialTexts.helperPaneY); AnimationTimer timer = new TutorialTimer(); timer.start(); @@ -46,8 +53,10 @@ public void start(Stage tutorialStage) { tutorialStage.setScene(tutorialScene); tutorialStage.show(); } + private class TutorialTimer extends AnimationTimer { private long prevTime = 0; + private double helpTimer = TutorialTexts.helpTime; /** * This method needs to be overridden by extending classes. It is going to @@ -61,8 +70,8 @@ private class TutorialTimer extends AnimationTimer { public void handle(long now) { long timeChange = now - prevTime; - // 5e9 is 5 seconds - if (timeChange > 4e9 & textController.changeText()) { + // 4e9 is 4 seconds + if (timeChange > TutorialTexts.TEXT_DURATION1 * 1e9 & textController.changeText()) { prevTime = now; tutorialDisplay.getController().nextPhase(); String tutorialText = tutorialDisplay.getController().bottomText(); @@ -70,9 +79,23 @@ public void handle(long now) { } + if (textController.getShowControls()){ + helpText.setText(TutorialTexts.CONTROLS); + helpTimer --; + if (helpTimer < 1){ + textController.setShowControls(false); + helpTimer = TutorialTexts.helpTime; + } + } + else { + helpText.setText(""); + } + } } - } + + + diff --git a/src/main/java/com/mg105/entities/items/utils/ItemConstants.java b/src/main/java/com/mg105/utils/ItemConstants.java similarity index 96% rename from src/main/java/com/mg105/entities/items/utils/ItemConstants.java rename to src/main/java/com/mg105/utils/ItemConstants.java index b47ac445..69c43290 100644 --- a/src/main/java/com/mg105/entities/items/utils/ItemConstants.java +++ b/src/main/java/com/mg105/utils/ItemConstants.java @@ -1,4 +1,4 @@ -package com.mg105.entities.items.utils; +package com.mg105.utils; import com.mg105.entities.items.HealthPotion; diff --git a/src/main/java/com/mg105/entities/items/utils/MapConstants.java b/src/main/java/com/mg105/utils/MapConstants.java similarity index 86% rename from src/main/java/com/mg105/entities/items/utils/MapConstants.java rename to src/main/java/com/mg105/utils/MapConstants.java index 40314e6f..77672fb0 100644 --- a/src/main/java/com/mg105/entities/items/utils/MapConstants.java +++ b/src/main/java/com/mg105/utils/MapConstants.java @@ -1,4 +1,4 @@ -package com.mg105.entities.items.utils; +package com.mg105.utils; /** * Constants used in the map. diff --git a/src/main/java/com/mg105/entities/items/utils/PartyConstants.java b/src/main/java/com/mg105/utils/PartyConstants.java similarity index 82% rename from src/main/java/com/mg105/entities/items/utils/PartyConstants.java rename to src/main/java/com/mg105/utils/PartyConstants.java index 46c26979..9dbfb3cb 100644 --- a/src/main/java/com/mg105/entities/items/utils/PartyConstants.java +++ b/src/main/java/com/mg105/utils/PartyConstants.java @@ -1,4 +1,4 @@ -package com.mg105.entities.items.utils; +package com.mg105.utils; public class PartyConstants { diff --git a/src/main/java/com/mg105/utils/TutorialTexts.java b/src/main/java/com/mg105/utils/TutorialTexts.java new file mode 100644 index 00000000..02377d62 --- /dev/null +++ b/src/main/java/com/mg105/utils/TutorialTexts.java @@ -0,0 +1,49 @@ +package com.mg105.utils; + +import java.util.Arrays; +import java.util.List; + +public class TutorialTexts { + public static final String moved = "moved"; + public static final String attacked = "attacked"; + public static final String usedItem = "usedItem"; + + public static final int tutorialTextX = 660; + public static final int tutorialTextY = 780; + + public static final int helperPaneX = 500; + public static final int helperPaneY = 100; + + + public static final int TEXT_DURATION1 = 4; + + public static final String textFont1 = "Verdana"; + public static final String textFont2 = "Courier"; + public static final int textSize = 16; + public static final int helpTime = 200; + + public static final List PHASES + = Arrays.asList("", "story", "tell move", "tell attack", "tell use item", "exit room", ""); + + public static final List PHASES_TEXT = Arrays.asList("", + TutorialTexts.STORY, TutorialTexts.TELL_MOVE, TutorialTexts.TELL_ATTACK, TutorialTexts.TELL_USE_ITEM, TutorialTexts.EXIT_ROOM, ""); + + public static final String STORY = """ + Welcome to mountain climber. You must battle your way + to the top of the mountain. Inside various rooms + you will encounter enemies and find treasures."""; + + public static final String TELL_MOVE = "Move your character with the arrow keys."; + + public static final String TELL_ATTACK = "Use the attack button to attack the enemy."; + + public static final String TELL_USE_ITEM = "Pick up health potions and use them to restore hp."; + + public static final String EXIT_ROOM = "Good luck on your journey!"; + + public static final String CONTROLS = """ + Hotkeys: Press K for help. Press esc to open menu.\s + Game Controls: Use WASD to move. Use attack key [..] to attack. \s + Pickup items using [..]. Use item key [..] to use potions."""; + +} diff --git a/src/test/java/com/mg105/entities/ChestTest.java b/src/test/java/com/mg105/entities/ChestTest.java index 4d258645..9f93f2b7 100644 --- a/src/test/java/com/mg105/entities/ChestTest.java +++ b/src/test/java/com/mg105/entities/ChestTest.java @@ -4,7 +4,7 @@ import com.mg105.outputds.ItemDetails; import com.mg105.presenter_interfaces.InventoryPresenterInterface; import com.mg105.use_cases.Inventory.InventoryInteractor; -import com.mg105.entities.items.utils.PartyConstants; +import com.mg105.utils.PartyConstants; import org.junit.jupiter.api.Test; import java.awt.*; import java.util.ArrayList; diff --git a/src/test/java/com/mg105/entities/InventoryTest.java b/src/test/java/com/mg105/entities/InventoryTest.java index 299fb2ee..d73ee815 100644 --- a/src/test/java/com/mg105/entities/InventoryTest.java +++ b/src/test/java/com/mg105/entities/InventoryTest.java @@ -2,7 +2,7 @@ import com.mg105.entities.items.HealthPotion; import com.mg105.entities.items.UpgradeToken; -import com.mg105.entities.items.utils.ItemConstants; +import com.mg105.utils.ItemConstants; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; diff --git a/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java b/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java index 90b08f10..b3d70b58 100644 --- a/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java +++ b/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java @@ -4,7 +4,7 @@ import com.mg105.entities.items.UpgradeToken; import com.mg105.outputds.ItemDetails; import com.mg105.presenter_interfaces.InventoryPresenterInterface; -import com.mg105.entities.items.utils.ItemConstants; +import com.mg105.utils.ItemConstants; import org.junit.jupiter.api.Test; import java.awt.*; diff --git a/src/test/java/com/mg105/use_cases/Tutorial/TutorialTest.java b/src/test/java/com/mg105/use_cases/Tutorial/TutorialTest.java index d7729ca6..23bb516a 100644 --- a/src/test/java/com/mg105/use_cases/Tutorial/TutorialTest.java +++ b/src/test/java/com/mg105/use_cases/Tutorial/TutorialTest.java @@ -3,12 +3,9 @@ import com.mg105.entities.GiveTutorial; import com.mg105.use_cases.PlayerGetsTutorial; import com.mg105.user_interface.TutorialTextDisplay; -import com.mg105.entities.items.utils.TutorialTexts; +import com.mg105.utils.TutorialTexts; import org.junit.jupiter.api.Test; -import java.util.Arrays; -import java.util.List; - import static org.junit.jupiter.api.Assertions.*; public class TutorialTest { @@ -16,6 +13,7 @@ public class TutorialTest { void testActionGetterSetter() { GiveTutorial newTutorial = new GiveTutorial(false, false, false); newTutorial.ActionPerformedSetter(TutorialTexts.attacked); + assertFalse(newTutorial.ActionPerformedGetter(TutorialTexts.moved)); assertTrue(newTutorial.ActionPerformedGetter(TutorialTexts.attacked)); assertFalse(newTutorial.ActionPerformedGetter(TutorialTexts.usedItem)); @@ -26,7 +24,6 @@ void testAdvancePhase() { PlayerGetsTutorial tutorialPlayer = new PlayerGetsTutorial(TutorialTexts.PHASES, 0, new GiveTutorial(false, false, false)); - List expectedPhases = Arrays.asList("", "story", "tell move", "tell attack", "tell use item", "exit room"); assertEquals(tutorialPlayer.currentPhase(), 0); tutorialPlayer.nextPhase(); @@ -58,6 +55,7 @@ void testTutorialBottomText(){ String phase = tutorialDisplay.getController().getTutorial().allPhases().get(phase_num); String tutorialText = tutorialDisplay.showBottomText(phase); String expected = "Move your character with the arrow keys."; + assertEquals(tutorialText, expected); } } From d31994f3453c58f828fb97264da1d5e9ef23bc59 Mon Sep 17 00:00:00 2001 From: m-grigoriu Date: Sat, 26 Nov 2022 21:38:12 -0500 Subject: [PATCH 03/22] - Finished implementation of BattleMenu. - BattleMenu is designed to be launched using Application.launch(). One BattlePresenter instance should exist before BattleMenu is ever launched. - Modified BattlePresenter to work with BattleMenu better, and to allow unit testing. - Modified BattlePresenter and Battle related entities to remove yellow warnings. --- src/main/java/com/mg105/entities/Battle.java | 4 +- .../com/mg105/entities/BattleCharacter.java | 12 +- .../BattlePresenter.java | 94 ++-- .../com/mg105/user_interface/BattleMenu.java | 417 +++++++++++++++++- .../java/com/mg105/entities/BattleTest.java | 41 +- 5 files changed, 501 insertions(+), 67 deletions(-) rename src/main/java/com/mg105/{interfaceadapter => interface_adapters}/BattlePresenter.java (79%) diff --git a/src/main/java/com/mg105/entities/Battle.java b/src/main/java/com/mg105/entities/Battle.java index d74a7d24..8ac37c81 100644 --- a/src/main/java/com/mg105/entities/Battle.java +++ b/src/main/java/com/mg105/entities/Battle.java @@ -13,7 +13,7 @@ public class Battle { private int battleStatus; private final ArrayList opponents; private final ArrayList playerCharacters; - private final ArrayList moveQueue = new ArrayList(); + private final ArrayList moveQueue = new ArrayList<>(); //not sure if numTokens should be randomly generated on creation, or after battleStatus has changed (this // implementation will assume the latter). @@ -110,7 +110,7 @@ public void removeChar(BattleCharacter fainted) { /** * Returns the character in the encounter based on the given name * - * @param name + * @param name the name String of the BattleCharacter to be returned * @return the BattleCharacter in the encounter with the given name * @throws NoSuchElementException if no character in the party has the given name */ diff --git a/src/main/java/com/mg105/entities/BattleCharacter.java b/src/main/java/com/mg105/entities/BattleCharacter.java index 46e473a9..10fe08d8 100644 --- a/src/main/java/com/mg105/entities/BattleCharacter.java +++ b/src/main/java/com/mg105/entities/BattleCharacter.java @@ -11,9 +11,9 @@ public class BattleCharacter implements Comparable { private int dmg; private int speed; - private boolean isOpponent; + private final boolean isOpponent; - private Move[] moves = new Move[2]; + private final Move[] moves = new Move[2]; //Don't know how to handle the sprite instance @@ -154,12 +154,6 @@ public void modifySpeed(int speedChange) { */ @Override public int compareTo(BattleCharacter other) { - if (this.speed < other.speed) { - return -1; - } else if (this.speed > other.speed) { - return 1; - } else { - return 0; - } + return Integer.compare(this.speed, other.speed); } } diff --git a/src/main/java/com/mg105/interfaceadapter/BattlePresenter.java b/src/main/java/com/mg105/interface_adapters/BattlePresenter.java similarity index 79% rename from src/main/java/com/mg105/interfaceadapter/BattlePresenter.java rename to src/main/java/com/mg105/interface_adapters/BattlePresenter.java index b9939680..360ca301 100644 --- a/src/main/java/com/mg105/interfaceadapter/BattlePresenter.java +++ b/src/main/java/com/mg105/interface_adapters/BattlePresenter.java @@ -1,4 +1,4 @@ -package com.mg105.interfaceadapter; +package com.mg105.interface_adapters; import com.mg105.entities.Battle; import com.mg105.entities.BattleCharacter; @@ -11,29 +11,36 @@ /** * Class communicating between BattleMenu view and game entities. - * * Follows MVP pattern; contains a reference to the view and interacts with Battle and related classes. */ public class BattlePresenter { - private GameState state; + private final GameState state; private Battle encounter; private BattleMenu view; - public BattlePresenter(GameState state, BattleMenu view) { + public BattlePresenter(GameState state) { this.state = state; this.encounter = state.getCurrEncounter(); - this.view = view; + BattleMenu.setPresenter(this); } + /** + * Sets the view attribute. + * + * @param view the BattleMenu instance to set the view attribute to. + */ + public void setView(BattleMenu view) { + this.view = view; + } /** * Creates a new encounter with random opponents and sets it as the current encounter in GameState */ public void createEncounter() { Random rand = new Random(); - ArrayList opponents = new ArrayList(); + ArrayList opponents = new ArrayList<>(); for (int i = 0; i < 4; ++i){ int charHealth = rand.nextInt(5, 41); @@ -41,31 +48,57 @@ public void createEncounter() { int charSpeed = rand.nextInt(3, 16); Move m1 = new Move(-rand.nextInt(1, 8), 0, "first", false); Move m2 = new Move(rand.nextInt(1, 4), 0, "second", true); - BattleCharacter character = new BattleCharacter(charHealth, "Opponent " + Integer.toString(i), + BattleCharacter character = new BattleCharacter(charHealth, "Opponent " + i, charDmg, charSpeed, true, m1, m2); opponents.add(character); } - Battle b = new Battle(opponents, this.state.getParty()); + ArrayList party = this.state.getParty(); + Battle b = new Battle(opponents, party); this.state.setCurrEncounter(b); this.encounter = b; + + String[] partyNames = new String[party.size()]; + String[] opponentNames = new String[opponents.size()]; + + for (int i = 0; i < party.size(); ++i) { + partyNames[i] = party.get(i).getName(); + opponentNames[i] = opponents.get(i).getName(); + } + if (view != null) { + this.view.setNames(partyNames, opponentNames); + } } /** - * Returns the current health of the BattleCharacter with the given name. + * Returns whether the given name is associated with a fainted character. + * Assumes that the inputted name corresponds to a character who was in the encounter at some point. * - * @return the desired BattleCharacter's current health. + * @param name the name of the character being checked. + * @return whether the given name corresponds to a fainted character. */ - public int givenCharacterHealth(String name) { - return this.encounter.getCharacter(name).getHp(); + public boolean givenCharacterFainted(String name) { + for (BattleCharacter c : encounter.getPlayerCharacters()) { + if (c.getName().equals(name)) { + return false; + } + } + + for (BattleCharacter c : encounter.getOpponents()) { + if (c.getName().equals(name)) { + return false; + } + } + + return true; } /** - * Returns the maximum health of the BattleCharacter with the given name. + * Returns the current health of the BattleCharacter with the given name. * - * @return the desired BattleCharacter's max health. + * @return the desired BattleCharacter's current health. */ - public int givenCharacterMaxHealth(String name) { - return this.encounter.getCharacter(name).getMaxHp(); + public int givenCharacterHealth(String name) { + return this.encounter.getCharacter(name).getHp(); } /** @@ -77,15 +110,6 @@ public int givenCharacterDamage(String name) { return this.encounter.getCharacter(name).getDmg(); } - /** - * Returns the speed of the BattleCharacter with the given name. - * - * @return the desired BattleCharacter's speed. - */ - public int givenCharacterSpeed(String name) { - return this.encounter.getCharacter(name).getSpeed(); - } - /** * Returns the stats of the BattleCharacter with the given name's moves. * Stats order: Move1 health change, Move1 damage change, Move2 health change, Move2 damage change. @@ -94,10 +118,8 @@ public int givenCharacterSpeed(String name) { */ public int[] givenCharacterMoveStats(String name) { BattleCharacter caster = this.encounter.getCharacter(name); - int[] moveStats = {caster.getMoveOne().getHealthChange(), caster.getMoveOne().getDamageChange(), - caster.getMoveTwo().getHealthChange(), caster.getMoveTwo().getDamageChange()}; - - return moveStats; + return new int[] {caster.getMoveOne().getHealthChange(), caster.getMoveOne().getDamageChange(), + caster.getMoveTwo().getHealthChange(), caster.getMoveTwo().getDamageChange()}; } /** @@ -108,9 +130,7 @@ public int[] givenCharacterMoveStats(String name) { */ public String[] givenCharacterMoveNames(String name) { BattleCharacter caster = this.encounter.getCharacter(name); - String[] moveNames = {caster.getMoveOne().getName(), caster.getMoveTwo().getName()}; - - return moveNames; + return new String[] {caster.getMoveOne().getName(), caster.getMoveTwo().getName()}; } /** @@ -131,9 +151,8 @@ public String roundStart() { return null; } else { //Battle is ongoing BattleCharacter moving = this.encounter.getMovingCharacter(); - boolean isOpponentMoving = moving.isOpponent(); - if (isOpponentMoving) { //Opponent character is moving + if (moving.isOpponent()) { //Opponent character is moving Random rand = new Random(); int moveNumber = rand.nextInt(2); @@ -187,7 +206,7 @@ public ArrayList retrieveTargets(int moveNum, String casterName) { m = caster.getMoveTwo(); } - ArrayList targets = new ArrayList(); + ArrayList targets = new ArrayList<>(); ArrayList targetCharacters; @@ -251,8 +270,9 @@ private void _useMove(Move m, BattleCharacter caster, BattleCharacter target) { target.modifyDamage(m.getDamageChange()); - //Currently unimplemented, will notify the view to update the impacted character - //this.view.updateCharacter(target.getName()); + if (view != null) { + this.view.updateCharacter(target.getName()); + } } private void _addReward() { diff --git a/src/main/java/com/mg105/user_interface/BattleMenu.java b/src/main/java/com/mg105/user_interface/BattleMenu.java index 196da908..4b9b7c11 100644 --- a/src/main/java/com/mg105/user_interface/BattleMenu.java +++ b/src/main/java/com/mg105/user_interface/BattleMenu.java @@ -1,31 +1,430 @@ package com.mg105.user_interface; -import com.mg105.interfaceadapter.BattlePresenter; +import com.mg105.interface_adapters.BattlePresenter; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.control.Button; -import javafx.scene.layout.StackPane; +import javafx.scene.control.Label; +import javafx.scene.layout.GridPane; import javafx.stage.Stage; -public class BattleMenu extends Application { +import java.util.ArrayList; - private BattlePresenter presenter; - public BattleMenu(){ +public class BattleMenu extends Application implements EventHandler { + private static BattlePresenter presenter; + private String[] playerNames = new String[4]; + private final int[] playerHealth = new int[4]; + private final int[] playerDmg = new int[4]; + private String[] opponentNames = new String[4]; + private final int[] opponentHealth = new int[4]; + private final int[] opponentDmg = new int[4]; + + private final Label p0 = new Label(); + private final Label p1 = new Label(); + private final Label p2 = new Label(); + private final Label p3 = new Label(); + + private final Label o0 = new Label(); + private final Label o1 = new Label(); + private final Label o2 = new Label(); + private final Label o3 = new Label(); + + private Button nextRound; + private Button moveOne; + private Button moveTwo; + + private Button targetP0; + private Button targetP1; + private Button targetP2; + private Button targetP3; + private Button targetO0; + private Button targetO1; + private Button targetO2; + private Button targetO3; + private GridPane grid; + + //Used in Button handle event + private String moving; + private int moveNum; + + + public BattleMenu() { + presenter.setView(this); + presenter.createEncounter(); + } + + /** + * Sets the BattlePresenter attribute for every BattleMenu. + * + * @param pres the BattlePresenter instance to set the attribute to. + */ + public static void setPresenter(BattlePresenter pres) { + presenter = pres; + } + + /** + * Sets the names of the player and opponent characters participating in the active battle. + * + * @param playerNames array of name Strings representing player characters. + * @param opponentNames array of name Strings representing opponents. + */ + public void setNames(String[] playerNames, String[] opponentNames) { + this.playerNames = playerNames; + this.opponentNames = opponentNames; + + for (int i = 0; i < playerNames.length; ++i) { + this.playerHealth[i] = presenter.givenCharacterHealth(this.playerNames[i]); + this.playerDmg[i] = presenter.givenCharacterDamage(this.playerNames[i]); + + this.opponentHealth[i] = presenter.givenCharacterHealth(this.opponentNames[i]); + this.opponentDmg[i] = presenter.givenCharacterDamage(this.opponentNames[i]); + } + } + + /** + * Updates the display corresponding to the given affected character. + * + * @param character the character who needs to be updated on the screen. + */ + public void updateCharacter(String character){ + if (playerNames[0].equals(character)) { + updateCharacterData(character, 0, p0, false); + } else if (playerNames[1].equals(character)) { + updateCharacterData(character, 1, p1, false); + } else if (playerNames[2].equals(character)) { + updateCharacterData(character, 2, p2, false); + } else if (playerNames[3].equals(character)) { + updateCharacterData(character, 3, p3, false); + } else if (opponentNames[0].equals(character)) { + updateCharacterData(character, 0, o0, true); + } else if (opponentNames[1].equals(character)) { + updateCharacterData(character, 1, o1, true); + } else if (opponentNames[2].equals(character)) { + updateCharacterData(character, 2, o2, true); + } else if (opponentNames[3].equals(character)) { + updateCharacterData(character, 3, o3, true); + } } @Override - public void start(Stage primaryStage) throws Exception { + public void start(Stage primaryStage) { primaryStage.setTitle("Battle"); - Button nextRound = new Button("Next Round"); + grid = new GridPane(); + grid.setVgap(10); + grid.setHgap(10); + + nextRound = new Button("Next Round"); + nextRound.setId("Next Round"); + nextRound.setOnAction(this); + grid.add(nextRound, 10, 30); + + setupCharacterLabel(p0, 0, false); + setupCharacterLabel(p1, 1, false); + setupCharacterLabel(p2, 2, false); + setupCharacterLabel(p3, 3, false); - StackPane layout = new StackPane(); + setupCharacterLabel(o0, 0, true); + setupCharacterLabel(o1, 1, true); + setupCharacterLabel(o2, 2, true); + setupCharacterLabel(o3, 3, true); + + grid.add(p0, 1, 4); + grid.add(p1, 1, 8); + grid.add(p2, 1, 12); + grid.add(p3, 1, 16); + + grid.add(o0, 18, 4); + grid.add(o1, 18, 8); + grid.add(o2, 18, 12); + grid.add(o3, 18, 16); + + targetP0 = new Button("TARGET"); + targetP0.setOnAction(this); + targetP0.setVisible(false); + grid.add(targetP0, 0, 4); + + targetP1 = new Button("TARGET"); + targetP1.setOnAction(this); + targetP1.setVisible(false); + grid.add(targetP1, 0, 8); + + targetP2 = new Button("TARGET"); + targetP2.setOnAction(this); + targetP2.setVisible(false); + grid.add(targetP2, 0, 12); + + targetP3 = new Button("TARGET"); + targetP3.setOnAction(this); + targetP3.setVisible(false); + grid.add(targetP3, 0, 16); + + targetO0 = new Button("TARGET"); + targetO0.setOnAction(this); + grid.add(targetO0, 19, 4); + targetO0.setVisible(false); + + targetO1 = new Button("TARGET"); + targetO1.setOnAction(this); + targetO1.setVisible(false); + grid.add(targetO1, 19, 8); + + targetO2 = new Button("TARGET"); + targetO2.setOnAction(this); + targetO2.setVisible(false); + grid.add(targetO2, 19, 12); + + targetO3 = new Button("TARGET"); + targetO3.setOnAction(this); + targetO3.setVisible(false); + grid.add(targetO3, 19, 16); + + moveOne = new Button(""); + moveOne.setOnAction(this); + moveOne.setVisible(false); + + moveTwo = new Button(""); + moveTwo.setOnAction(this); + moveTwo.setVisible(false); + + Scene scene = new Scene(grid, 800, 800); + primaryStage.setScene(scene); + primaryStage.show(); } - public void updateCharacter(String character){ + @Override + public void handle(ActionEvent event) { + Object source = event.getSource(); + if (source.equals(nextRound)) { + nextRound.setDisable(true); + + moving = presenter.roundStart(); + + if (moving == null) { //Battle ended + ((Stage) ((Button) source).getScene().getWindow()).close(); + return; + } + + //moving != null + if (playerNames[0].equals(moving)) { + int[] moveStats = presenter.givenCharacterMoveStats(moving); + String[] moveNames = presenter.givenCharacterMoveNames(moving); + + grid.add(moveOne, 2, 4); + moveOne.setVisible(true); + grid.add(moveTwo, 3, 4); + moveTwo.setVisible(true); + + moveOne.setText(moveNames[0] + "\n Hp: " + moveStats[0] + ", Dmg: " + moveStats[1]); + moveTwo.setText(moveNames[1] + "\n Hp: " + moveStats[2] + ", Dmg: " + moveStats[3]); + } else if (playerNames[1].equals(moving)) { + int[] moveStats = presenter.givenCharacterMoveStats(moving); + String[] moveNames = presenter.givenCharacterMoveNames(moving); + + grid.add(moveOne, 2, 8); + moveOne.setVisible(true); + grid.add(moveTwo, 3, 8); + moveTwo.setVisible(true); + + moveOne.setText(moveNames[0] + "\n Hp: " + moveStats[0] + ", Dmg: " + moveStats[1]); + moveTwo.setText(moveNames[1] + "\n Hp: " + moveStats[2] + ", Dmg: " + moveStats[3]); + } else if (playerNames[2].equals(moving)) { + int[] moveStats = presenter.givenCharacterMoveStats(moving); + String[] moveNames = presenter.givenCharacterMoveNames(moving); + + grid.add(moveOne, 2, 12); + moveOne.setVisible(true); + grid.add(moveTwo, 3, 12); + moveTwo.setVisible(true); + + moveOne.setText(moveNames[0] + "\n Hp: " + moveStats[0] + ", Dmg: " + moveStats[1]); + moveTwo.setText(moveNames[1] + "\n Hp: " + moveStats[2] + ", Dmg: " + moveStats[3]); + } else if (playerNames[3].equals(moving)) { + int[] moveStats = presenter.givenCharacterMoveStats(moving); + String[] moveNames = presenter.givenCharacterMoveNames(moving); + + grid.add(moveOne, 2, 16); + moveOne.setVisible(true); + grid.add(moveTwo, 3, 16); + moveTwo.setVisible(true); + + moveOne.setText(moveNames[0] + "\n Hp: " + moveStats[0] + ", Dmg: " + moveStats[1]); + moveTwo.setText(moveNames[1] + "\n Hp: " + moveStats[2] + ", Dmg: " + moveStats[3]); + } else if(opponentNames[0].equals(moving) || opponentNames[1].equals(moving) || + opponentNames[2].equals(moving) || opponentNames[3].equals(moving)) { + //If opponent moved, re-enable nextRound button + nextRound.setDisable(false); + } + + } else if(source.equals(moveOne)) { + moveNum = 1; + displayTargets(); + } else if(source.equals(moveTwo)) { + moveNum = 2; + displayTargets(); + } else if(source.equals(targetP0)) { + targetP0.setVisible(false); + targetP1.setVisible(false); + targetP2.setVisible(false); + targetP3.setVisible(false); + + presenter.executeTurn(moveNum, moving, playerNames[0]); + + //Re-enable nextRound button after a move has been made. + nextRound.setDisable(false); + } else if(source.equals(targetP1)) { + targetP0.setVisible(false); + targetP1.setVisible(false); + targetP2.setVisible(false); + targetP3.setVisible(false); + + presenter.executeTurn(moveNum, moving, playerNames[1]); + + //Re-enable nextRound button after a move has been made. + nextRound.setDisable(false); + } else if(source.equals(targetP2)) { + targetP0.setVisible(false); + targetP1.setVisible(false); + targetP2.setVisible(false); + targetP3.setVisible(false); + + presenter.executeTurn(moveNum, moving, playerNames[2]); + + //Re-enable nextRound button after a move has been made. + nextRound.setDisable(false); + } else if(source.equals(targetP3)) { + targetP0.setVisible(false); + targetP1.setVisible(false); + targetP2.setVisible(false); + targetP3.setVisible(false); + + presenter.executeTurn(moveNum, moving, playerNames[3]); + + //Re-enable nextRound button after a move has been made. + nextRound.setDisable(false); + } else if(source.equals(targetO0)) { + targetO0.setVisible(false); + targetO1.setVisible(false); + targetO2.setVisible(false); + targetO3.setVisible(false); + + presenter.executeTurn(moveNum, moving, opponentNames[0]); + + //Re-enable nextRound button after a move has been made. + nextRound.setDisable(false); + } else if(source.equals(targetO1)) { + targetO0.setVisible(false); + targetO1.setVisible(false); + targetO2.setVisible(false); + targetO3.setVisible(false); + + presenter.executeTurn(moveNum, moving, opponentNames[1]); + + //Re-enable nextRound button after a move has been made. + nextRound.setDisable(false); + } else if(source.equals(targetO2)) { + targetO0.setVisible(false); + targetO1.setVisible(false); + targetO2.setVisible(false); + targetO3.setVisible(false); + + presenter.executeTurn(moveNum, moving, opponentNames[2]); + + //Re-enable nextRound button after a move has been made. + nextRound.setDisable(false); + } else if(source.equals(targetO3)) { + targetO0.setVisible(false); + targetO1.setVisible(false); + targetO2.setVisible(false); + targetO3.setVisible(false); + + presenter.executeTurn(moveNum, moving, opponentNames[3]); + + //Re-enable nextRound button after a move has been made. + nextRound.setDisable(false); + } + } + + /** + * Helper function for updateCharacter. + * @param character name String of the character to be updated. + * @param position index of the character's data in the data arrays. + * @param lbl Label object to be updated. + * @param isOpponent boolean for whether the character is an opponent or not. + */ + private void updateCharacterData(String character, int position, Label lbl, boolean isOpponent) { + if (presenter.givenCharacterFainted(character)) { + lbl.setText("FAINTED"); + return; + } + int[] hpData; + int[] dmgData; + String[] nameData; + + if (isOpponent) { + hpData = opponentHealth; + dmgData = opponentDmg; + nameData = opponentNames; + } else { + hpData = playerHealth; + dmgData = playerDmg; + nameData = playerNames; + } + hpData[position] = presenter.givenCharacterHealth(character); + dmgData[position] = presenter.givenCharacterDamage(character); + lbl.setText(nameData[position] + "\n Hp: " + hpData[position] + ", Dmg: " + dmgData[position]); + } + + /** + * Helper function for moveOne/moveTwo button click events. + * Removes the two buttons, retrieves targets based on the chosen move, displays respective target buttons. + */ + private void displayTargets() { + moveOne.setVisible(false); + moveTwo.setVisible(false); + + grid.getChildren().remove(moveOne); + grid.getChildren().remove(moveTwo); + + ArrayList targets = presenter.retrieveTargets(moveNum, moving); + + for (String s : targets) { + if (playerNames[0].equals(s)) { + targetP0.setVisible(true); + } else if (playerNames[1].equals(s)) { + targetP1.setVisible(true); + } else if (playerNames[2].equals(s)) { + targetP2.setVisible(true); + } else if (playerNames[3].equals(s)) { + targetP3.setVisible(true); + } else if (opponentNames[0].equals(s)) { + targetO0.setVisible(true); + } else if (opponentNames[1].equals(s)) { + targetO1.setVisible(true); + } else if (opponentNames[2].equals(s)) { + targetO2.setVisible(true); + } else if (opponentNames[3].equals(s)) { + targetO3.setVisible(true); + } + } + } + /** + * Helper function to initialize the character labels in + * @param lbl Label object corresponding to the character. + * @param position Integer representing index of character's data in data arrays. + * @param isOpponent Boolean of whether the character is an opponent. + */ + private void setupCharacterLabel(Label lbl, int position, boolean isOpponent) { + if (isOpponent) { + lbl.setText(opponentNames[position] + "\n Hp: " + opponentHealth[position] + ", Dmg: " + + opponentDmg[position]); + } else { + lbl.setText(playerNames[position] + "\n Hp: " + playerHealth[position] + ", Dmg: " + + playerDmg[position]); + } } } diff --git a/src/test/java/com/mg105/entities/BattleTest.java b/src/test/java/com/mg105/entities/BattleTest.java index 75713b5b..0e358c0f 100644 --- a/src/test/java/com/mg105/entities/BattleTest.java +++ b/src/test/java/com/mg105/entities/BattleTest.java @@ -1,16 +1,10 @@ package com.mg105.entities; -import com.mg105.entities.Battle; -import com.mg105.entities.BattleCharacter; -import com.mg105.entities.Move; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.util.ArrayDeque; import java.util.ArrayList; -import static org.junit.jupiter.api.Assertions.*; - class BattleTest { @Test @@ -23,11 +17,11 @@ void getMovingCharacter() { BattleCharacter p1 = new BattleCharacter(14, "Mariam", 7, 11,false, m1, m2); BattleCharacter p2 = new BattleCharacter(9, "Leslie", 6, 8, false, m1, m2); - ArrayList opponents = new ArrayList(); + ArrayList opponents = new ArrayList<>(); opponents.add(op1); opponents.add(op2); - ArrayList players = new ArrayList(); + ArrayList players = new ArrayList<>(); players.add(p1); players.add(p2); @@ -55,11 +49,11 @@ void removeChar() { BattleCharacter p1 = new BattleCharacter(14, "Leslie", 7, 8, false, m1, m2); BattleCharacter p2 = new BattleCharacter(9, "Mariam", 6, 11, false, m1, m2); - ArrayList opponents = new ArrayList(); + ArrayList opponents = new ArrayList<>(); opponents.add(op1); opponents.add(op2); - ArrayList players = new ArrayList(); + ArrayList players = new ArrayList<>(); players.add(p1); players.add(p2); @@ -71,4 +65,31 @@ void removeChar() { Assertions.assertEquals(1, encounter.getBattleStatus()); } + + @Test + void getBattleCharacter() { + Move m1 = new Move(5, 0, "first", true); + Move m2 = new Move(0, 1, "second",true); + + BattleCharacter op1 = new BattleCharacter(10, "Michael", 10, 10, true, m1, m2); + BattleCharacter op2 = new BattleCharacter(6, "Alex", 12, 14, true, m1, m2); + BattleCharacter p1 = new BattleCharacter(14, "Leslie", 7, 8, false, m1, m2); + BattleCharacter p2 = new BattleCharacter(9, "Mariam", 6, 11, false, m1, m2); + + ArrayList opponents = new ArrayList<>(); + opponents.add(op1); + opponents.add(op2); + + ArrayList players = new ArrayList<>(); + players.add(p1); + players.add(p2); + + Battle encounter = new Battle(opponents, players); + + BattleCharacter michael = encounter.getCharacter("Michael"); + BattleCharacter mariam = encounter.getCharacter("Mariam"); + + Assertions.assertTrue(michael.getName().equals("Michael") && michael.isOpponent()); + Assertions.assertTrue(mariam.getName().equals("Mariam") && !mariam.isOpponent()); + } } From c0baf9de169f6be1aa25231fd2d03c70a0caa9f2 Mon Sep 17 00:00:00 2001 From: zhaoan12 Date: Sun, 27 Nov 2022 22:03:39 -0500 Subject: [PATCH 04/22] Minor changes to fix warnings. --- src/main/java/com/mg105/entities/GiveTutorial.java | 6 +++--- .../java/com/mg105/user_interface/TutorialTextWindow.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/mg105/entities/GiveTutorial.java b/src/main/java/com/mg105/entities/GiveTutorial.java index 2d4fea22..6393cded 100644 --- a/src/main/java/com/mg105/entities/GiveTutorial.java +++ b/src/main/java/com/mg105/entities/GiveTutorial.java @@ -5,9 +5,9 @@ public class GiveTutorial { - private boolean moved = false; - private boolean attacked = false; - private boolean usedItem = false; + private boolean moved; + private boolean attacked; + private boolean usedItem; public GiveTutorial(boolean moved, boolean attacked, boolean usedItem) { this.moved = moved; diff --git a/src/main/java/com/mg105/user_interface/TutorialTextWindow.java b/src/main/java/com/mg105/user_interface/TutorialTextWindow.java index 986f46e6..6dd7bd27 100644 --- a/src/main/java/com/mg105/user_interface/TutorialTextWindow.java +++ b/src/main/java/com/mg105/user_interface/TutorialTextWindow.java @@ -70,7 +70,7 @@ private class TutorialTimer extends AnimationTimer { public void handle(long now) { long timeChange = now - prevTime; - // 4e9 is 4 seconds + // 1e9 is 1 second if (timeChange > TutorialTexts.TEXT_DURATION1 * 1e9 & textController.changeText()) { prevTime = now; tutorialDisplay.getController().nextPhase(); @@ -80,7 +80,7 @@ public void handle(long now) { } if (textController.getShowControls()){ - helpText.setText(TutorialTexts.CONTROLS); + helpText.setText(tutorialDisplay.showControlsText()); helpTimer --; if (helpTimer < 1){ textController.setShowControls(false); From 30504a2130d4eb0031faa4cdc8144557ea557389 Mon Sep 17 00:00:00 2001 From: m-grigoriu Date: Mon, 28 Nov 2022 16:35:59 -0500 Subject: [PATCH 05/22] Added BattleMenuInterface and in progress BattlePresenterTest. --- .../BattleMenuInterface.java | 19 +++++ .../interface_adapters/BattlePresenter.java | 6 +- .../com/mg105/user_interface/BattleMenu.java | 8 ++- .../BattlePresenterTest.java | 69 +++++++++++++++++++ 4 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/mg105/interface_adapters/BattleMenuInterface.java create mode 100644 src/test/java/com/mg105/interface_adapters/BattlePresenterTest.java diff --git a/src/main/java/com/mg105/interface_adapters/BattleMenuInterface.java b/src/main/java/com/mg105/interface_adapters/BattleMenuInterface.java new file mode 100644 index 00000000..b9dcd2eb --- /dev/null +++ b/src/main/java/com/mg105/interface_adapters/BattleMenuInterface.java @@ -0,0 +1,19 @@ +package com.mg105.interface_adapters; + +public interface BattleMenuInterface { + + /** + * Sets the names of the player and opponent characters participating in the active battle. + * + * @param playerNames array of name Strings representing player characters. + * @param opponentNames array of name Strings representing opponents. + */ + void setNames(String[] playerNames, String[] opponentNames); + + /** + * Updates the display corresponding to the given affected character. + * + * @param character the character who needs to be updated on the screen. + */ + void updateCharacter(String character); +} diff --git a/src/main/java/com/mg105/interface_adapters/BattlePresenter.java b/src/main/java/com/mg105/interface_adapters/BattlePresenter.java index 360ca301..30e14e5c 100644 --- a/src/main/java/com/mg105/interface_adapters/BattlePresenter.java +++ b/src/main/java/com/mg105/interface_adapters/BattlePresenter.java @@ -18,7 +18,7 @@ public class BattlePresenter { private final GameState state; private Battle encounter; - private BattleMenu view; + private BattleMenuInterface view; public BattlePresenter(GameState state) { this.state = state; @@ -29,9 +29,9 @@ public BattlePresenter(GameState state) { /** * Sets the view attribute. * - * @param view the BattleMenu instance to set the view attribute to. + * @param view the BattleMenuInterface instance to set the view attribute to. */ - public void setView(BattleMenu view) { + public void setView(BattleMenuInterface view) { this.view = view; } /** diff --git a/src/main/java/com/mg105/user_interface/BattleMenu.java b/src/main/java/com/mg105/user_interface/BattleMenu.java index 4b9b7c11..a2d80e2d 100644 --- a/src/main/java/com/mg105/user_interface/BattleMenu.java +++ b/src/main/java/com/mg105/user_interface/BattleMenu.java @@ -1,5 +1,6 @@ package com.mg105.user_interface; +import com.mg105.interface_adapters.BattleMenuInterface; import com.mg105.interface_adapters.BattlePresenter; import javafx.application.Application; import javafx.event.ActionEvent; @@ -12,7 +13,7 @@ import java.util.ArrayList; -public class BattleMenu extends Application implements EventHandler { +public class BattleMenu extends Application implements EventHandler, BattleMenuInterface { private static BattlePresenter presenter; private String[] playerNames = new String[4]; @@ -45,6 +46,7 @@ public class BattleMenu extends Application implements EventHandler private Button targetO2; private Button targetO3; private GridPane grid; + private Scene scene; //Used in Button handle event private String moving; @@ -71,6 +73,7 @@ public static void setPresenter(BattlePresenter pres) { * @param playerNames array of name Strings representing player characters. * @param opponentNames array of name Strings representing opponents. */ + @Override public void setNames(String[] playerNames, String[] opponentNames) { this.playerNames = playerNames; this.opponentNames = opponentNames; @@ -89,6 +92,7 @@ public void setNames(String[] playerNames, String[] opponentNames) { * * @param character the character who needs to be updated on the screen. */ + @Override public void updateCharacter(String character){ if (playerNames[0].equals(character)) { updateCharacterData(character, 0, p0, false); @@ -190,7 +194,7 @@ public void start(Stage primaryStage) { moveTwo.setOnAction(this); moveTwo.setVisible(false); - Scene scene = new Scene(grid, 800, 800); + scene = new Scene(grid, 800, 800); primaryStage.setScene(scene); primaryStage.show(); } diff --git a/src/test/java/com/mg105/interface_adapters/BattlePresenterTest.java b/src/test/java/com/mg105/interface_adapters/BattlePresenterTest.java new file mode 100644 index 00000000..4d3f48ae --- /dev/null +++ b/src/test/java/com/mg105/interface_adapters/BattlePresenterTest.java @@ -0,0 +1,69 @@ +package com.mg105.interface_adapters; + +import com.mg105.entities.BattleCharacter; +import com.mg105.entities.GameState; +import com.mg105.entities.Inventory; +import com.mg105.entities.Move; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; + +class BattlePresenterTest { + + @Test + void createValidEncounter() { + Inventory inventory = new Inventory(); + BattleCharacter p1 = new BattleCharacter(14, "Leslie", 7, 8, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p2 = new BattleCharacter(9, "Mariam", 6, 11, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p3 = new BattleCharacter(10, "Michael", 10, 10, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p4 = new BattleCharacter(6, "Alex", 12, 14, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + + BattleCharacter[] party = {p1, p2, p3, p4}; + + GameState state = new GameState(inventory, party); + BattlePresenter presenter = new BattlePresenter(state); + presenter.createEncounter(); + + Assertions.assertEquals(4, presenter.retrieveTargets(1, "Leslie").size()); + } + + @Test + void executeMoveSuccess() { + Inventory inventory = new Inventory(); + BattleCharacter p1 = new BattleCharacter(14, "Leslie", 7, 8, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p2 = new BattleCharacter(9, "Mariam", 6, 11, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p3 = new BattleCharacter(10, "Michael", 10, 10, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p4 = new BattleCharacter(6, "Alex", 12, 14, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + + BattleCharacter[] party = {p1, p2, p3, p4}; + + GameState state = new GameState(inventory, party); + BattlePresenter presenter = new BattlePresenter(state); + presenter.createEncounter(); + + ArrayList targets = presenter.retrieveTargets(1, "Leslie"); + String target = targets.get(0); + int originalHealth = presenter.givenCharacterHealth(target); + presenter.executeTurn(1, "Leslie", target); + + Assertions.assertTrue(presenter.givenCharacterFainted(target) || + presenter.givenCharacterHealth(target) != originalHealth); + } +} From 02abe43a656009e2315cf62a075ed3e16881ee2e Mon Sep 17 00:00:00 2001 From: m-grigoriu Date: Mon, 28 Nov 2022 16:43:38 -0500 Subject: [PATCH 06/22] Added BattleMenuInterface and in progress BattlePresenterTest. --- .../BattlePresenterTest.java | 69 ------------------- 1 file changed, 69 deletions(-) delete mode 100644 src/test/java/com/mg105/interface_adapters/BattlePresenterTest.java diff --git a/src/test/java/com/mg105/interface_adapters/BattlePresenterTest.java b/src/test/java/com/mg105/interface_adapters/BattlePresenterTest.java deleted file mode 100644 index 4d3f48ae..00000000 --- a/src/test/java/com/mg105/interface_adapters/BattlePresenterTest.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.mg105.interface_adapters; - -import com.mg105.entities.BattleCharacter; -import com.mg105.entities.GameState; -import com.mg105.entities.Inventory; -import com.mg105.entities.Move; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; - -class BattlePresenterTest { - - @Test - void createValidEncounter() { - Inventory inventory = new Inventory(); - BattleCharacter p1 = new BattleCharacter(14, "Leslie", 7, 8, false, - new Move(-5, 0, "first", false), - new Move(0, 1, "second",true)); - BattleCharacter p2 = new BattleCharacter(9, "Mariam", 6, 11, false, - new Move(-5, 0, "first", false), - new Move(0, 1, "second",true)); - BattleCharacter p3 = new BattleCharacter(10, "Michael", 10, 10, false, - new Move(-5, 0, "first", false), - new Move(0, 1, "second",true)); - BattleCharacter p4 = new BattleCharacter(6, "Alex", 12, 14, false, - new Move(-5, 0, "first", false), - new Move(0, 1, "second",true)); - - BattleCharacter[] party = {p1, p2, p3, p4}; - - GameState state = new GameState(inventory, party); - BattlePresenter presenter = new BattlePresenter(state); - presenter.createEncounter(); - - Assertions.assertEquals(4, presenter.retrieveTargets(1, "Leslie").size()); - } - - @Test - void executeMoveSuccess() { - Inventory inventory = new Inventory(); - BattleCharacter p1 = new BattleCharacter(14, "Leslie", 7, 8, false, - new Move(-5, 0, "first", false), - new Move(0, 1, "second",true)); - BattleCharacter p2 = new BattleCharacter(9, "Mariam", 6, 11, false, - new Move(-5, 0, "first", false), - new Move(0, 1, "second",true)); - BattleCharacter p3 = new BattleCharacter(10, "Michael", 10, 10, false, - new Move(-5, 0, "first", false), - new Move(0, 1, "second",true)); - BattleCharacter p4 = new BattleCharacter(6, "Alex", 12, 14, false, - new Move(-5, 0, "first", false), - new Move(0, 1, "second",true)); - - BattleCharacter[] party = {p1, p2, p3, p4}; - - GameState state = new GameState(inventory, party); - BattlePresenter presenter = new BattlePresenter(state); - presenter.createEncounter(); - - ArrayList targets = presenter.retrieveTargets(1, "Leslie"); - String target = targets.get(0); - int originalHealth = presenter.givenCharacterHealth(target); - presenter.executeTurn(1, "Leslie", target); - - Assertions.assertTrue(presenter.givenCharacterFainted(target) || - presenter.givenCharacterHealth(target) != originalHealth); - } -} From 5cb31a145970a33c6273666358efa5d47a391cce Mon Sep 17 00:00:00 2001 From: Theodore Date: Tue, 29 Nov 2022 10:23:03 -0500 Subject: [PATCH 07/22] Tutorial patch fix --- src/main/java/com/mg105/Application.java | 8 +------- .../mg105/interface_adapters/InputInterpreter.java | 12 +++++++----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/mg105/Application.java b/src/main/java/com/mg105/Application.java index 3c1be9f7..ad03cca3 100644 --- a/src/main/java/com/mg105/Application.java +++ b/src/main/java/com/mg105/Application.java @@ -78,16 +78,10 @@ public void start(Stage primaryStage) { TutorialTextDisplay textDisplay = new TutorialTextDisplay(); TutorialTextWindow tutorialDisplay = new TutorialTextWindow(textChanger, textDisplay); drawableComponents.put(Toggler.ToggleableComponent.TUTORIAL, tutorialDisplay); -// sceneController.toggle((Toggler.ToggleableComponent.TUTORIAL)); - SceneController sceneControllerTutorial = new SceneController( - primaryStage, - drawableComponents, - Toggler.ToggleableComponent.TUTORIAL - ); ////////////////////// CharacterMover characterMover = new CharacterMover(state, mapDrawer); - InputInterpreter inputInterpreter = new InputInterpreter(characterMover, sceneController, textChanger, sceneControllerTutorial); + InputInterpreter inputInterpreter = new InputInterpreter(characterMover, sceneController, textChanger); InputListener inputListener = new InputListener(inputInterpreter); primaryStage.addEventFilter(KeyEvent.KEY_TYPED, inputListener); diff --git a/src/main/java/com/mg105/interface_adapters/InputInterpreter.java b/src/main/java/com/mg105/interface_adapters/InputInterpreter.java index c9487b5f..1c367d42 100644 --- a/src/main/java/com/mg105/interface_adapters/InputInterpreter.java +++ b/src/main/java/com/mg105/interface_adapters/InputInterpreter.java @@ -15,7 +15,6 @@ public class InputInterpreter { private final @NotNull Toggler toggler; private final @NotNull TutorialTextController textChanger; - private final @NotNull SceneController tutorialScene; /** * Create a new InputInterpreter that translates keyboard inputs to appropriate function invocations. @@ -23,11 +22,10 @@ public class InputInterpreter { * @param mover the character mover. */ public InputInterpreter(@NotNull CharacterMover mover, @NotNull Toggler toggler, - @NotNull TutorialTextController textChanger, SceneController tutorialScene) { + @NotNull TutorialTextController textChanger) { this.mover = mover; this.toggler = toggler; this.textChanger = textChanger; - this.tutorialScene = tutorialScene; } /** @@ -52,10 +50,14 @@ public void interpret(String key) { } case TUTORIAL -> { switch (key) { - case "t" -> tutorialScene.toggle(Toggler.ToggleableComponent.MAP); - + case "w", "a", "s", "d" -> { + toggler.toggle(Toggler.ToggleableComponent.TUTORIAL); + textChanger.setChangeText(); + } + case "k" -> textChanger.setShowControls(true); } } } + } } From 11a9b972ac113adfc6e53c2cd17b92343433eb89 Mon Sep 17 00:00:00 2001 From: zhaoan12 Date: Tue, 29 Nov 2022 10:23:27 -0500 Subject: [PATCH 08/22] Fixed testing issues for tutorial and fixed bug that did not correctly do the scenes. --- .../mg105/controllers/TutorialTextController.java | 4 +++- .../interface_adapters/InputInterpreter.java | 11 ++++++++--- .../mg105/user_interface/TutorialTextWindow.java | 3 +-- src/main/java/com/mg105/utils/TutorialTexts.java | 15 +++++++-------- .../mg105/use_cases/Tutorial/TutorialTest.java | 2 +- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/mg105/controllers/TutorialTextController.java b/src/main/java/com/mg105/controllers/TutorialTextController.java index 52c7adeb..09528585 100644 --- a/src/main/java/com/mg105/controllers/TutorialTextController.java +++ b/src/main/java/com/mg105/controllers/TutorialTextController.java @@ -31,7 +31,9 @@ public String bottomText() { /** * Return if text should start changing */ - public void setChangeText() { this.changeText = true; } + public void setChangeText() { + this.changeText = !this.changeText; + } /** * Return if text should start changing diff --git a/src/main/java/com/mg105/interface_adapters/InputInterpreter.java b/src/main/java/com/mg105/interface_adapters/InputInterpreter.java index 1c367d42..7f401028 100644 --- a/src/main/java/com/mg105/interface_adapters/InputInterpreter.java +++ b/src/main/java/com/mg105/interface_adapters/InputInterpreter.java @@ -42,10 +42,15 @@ public void interpret(String key) { case "s" -> mover.generateMapMoveBy(new Point(0, 1)); case "d" -> mover.generateMapMoveBy(new Point(1, 0)); - case "t" ->{tutorialScene.toggle(Toggler.ToggleableComponent.TUTORIAL);} - + case "k" -> { + toggler.toggle(Toggler.ToggleableComponent.TUTORIAL); + textChanger.setShowControls(true); - case "k" -> textChanger.setShowControls(true); + } + case "t" -> { + toggler.toggle(Toggler.ToggleableComponent.TUTORIAL); + textChanger.setChangeText(); + } } } case TUTORIAL -> { diff --git a/src/main/java/com/mg105/user_interface/TutorialTextWindow.java b/src/main/java/com/mg105/user_interface/TutorialTextWindow.java index 9b38881f..7b58b098 100644 --- a/src/main/java/com/mg105/user_interface/TutorialTextWindow.java +++ b/src/main/java/com/mg105/user_interface/TutorialTextWindow.java @@ -79,8 +79,7 @@ public void handle(long now) { long timeChange = now - prevTime; // 1e9 is 1 second -// if (timeChange > TutorialTexts.TEXT_DURATION1 * 1e9 & textController.changeText()) { - if (timeChange > TutorialTexts.TEXT_DURATION1 * 1e9) { + if (timeChange > TutorialTexts.TEXT_DURATION1 * 1e9 & textController.changeText()) { prevTime = now; tutorialDisplay.getController().nextPhase(); String tutorialText = tutorialDisplay.getController().bottomText(); diff --git a/src/main/java/com/mg105/utils/TutorialTexts.java b/src/main/java/com/mg105/utils/TutorialTexts.java index 17a22eee..32dc9e9b 100644 --- a/src/main/java/com/mg105/utils/TutorialTexts.java +++ b/src/main/java/com/mg105/utils/TutorialTexts.java @@ -8,22 +8,19 @@ public class TutorialTexts { public static final String ATTACKED = "attacked"; public static final String USED_ITEM = "usedItem"; - public static final int TUTORIAL_TEXT_X = 660; - public static final int TUTORIAL_TEXT_Y = 780; - public static final int HELPER_PANE_X = 420; public static final int HELPER_PANE_Y = 100; - public static final int TEXT_DURATION1 = 4; + public static final int TEXT_DURATION1 = 3; public static final int TEXT_SIZE = 14; - public static final int HELP_TIME = 200; + public static final int HELP_TIME = 250; public static final List PHASES - = Arrays.asList("...", "story", "tell move", "tell attack", "tell use item", "exit room", "..."); + = Arrays.asList("...", "story", "tell move", "tell attack", "tell use item", "exit room", "hotkeys"); public static final List PHASES_TEXT = Arrays.asList("", - TutorialTexts.STORY, TutorialTexts.TELL_MOVE, TutorialTexts.TELL_ATTACK, TutorialTexts.TELL_USE_ITEM, TutorialTexts.EXIT_ROOM, ""); + TutorialTexts.STORY, TutorialTexts.TELL_MOVE, TutorialTexts.TELL_ATTACK, TutorialTexts.TELL_USE_ITEM, TutorialTexts.EXIT_ROOM, TutorialTexts.HOTKEYS); public static final String STORY = """ Welcome to mountain climber. You must battle your way @@ -39,8 +36,10 @@ public class TutorialTexts { public static final String EXIT_ROOM = "Good luck on your journey!"; public static final String CONTROLS = """ - Hotkeys: Press K for help. Press esc to open menu.\s + Hotkeys: Press K for help. Press WASD to return to game.\s Game Controls: Use WASD to move. Use attack key [..] to attack. \s Pickup items using [..]. Use item key [..] to use potions."""; + public static final String HOTKEYS = "Hint: Press WASD to return to the game. Press K for help"; + } diff --git a/src/test/java/com/mg105/use_cases/Tutorial/TutorialTest.java b/src/test/java/com/mg105/use_cases/Tutorial/TutorialTest.java index 4deabb2f..0d313bf3 100644 --- a/src/test/java/com/mg105/use_cases/Tutorial/TutorialTest.java +++ b/src/test/java/com/mg105/use_cases/Tutorial/TutorialTest.java @@ -54,7 +54,7 @@ void testTutorialBottomText(){ int phase_num = tutorialDisplay.getController().getTutorial().currentPhase(); String phase = tutorialDisplay.getController().getTutorial().allPhases().get(phase_num); String tutorialText = tutorialDisplay.showBottomText(phase); - String expected = "Move your character with the arrow keys."; + String expected = "Move your character with the WASD keys."; assertEquals(tutorialText, expected); } From afe376c37ce1487a867004a8b386bf6954143e48 Mon Sep 17 00:00:00 2001 From: m-grigoriu Date: Tue, 29 Nov 2022 11:25:18 -0500 Subject: [PATCH 09/22] - Added BattlePresenterInterface, implemented by BattlePresenter, and BattleInteractor use case class in order for Battle code structure to follow clean architecture. - Added code to handle the case where player enters combat with one or more of their characters fainted. - endBattle() has a partial implementation in BattlePresenter, unfinished. - endBattle(), _addReward(), and _removeActiveBattle() are unimplemented in BattleInteractor --- .../java/com/mg105/entities/GameState.java | 2 +- .../interface_adapters/BattlePresenter.java | 203 ++---------- .../BattlePresenterInterface.java | 17 + .../com/mg105/use_cases/BattleInteractor.java | 290 ++++++++++++++++++ .../com/mg105/user_interface/BattleMenu.java | 208 +++++++------ 5 files changed, 455 insertions(+), 265 deletions(-) create mode 100644 src/main/java/com/mg105/presenter_interfaces/BattlePresenterInterface.java create mode 100644 src/main/java/com/mg105/use_cases/BattleInteractor.java diff --git a/src/main/java/com/mg105/entities/GameState.java b/src/main/java/com/mg105/entities/GameState.java index febc90ea..670218c4 100644 --- a/src/main/java/com/mg105/entities/GameState.java +++ b/src/main/java/com/mg105/entities/GameState.java @@ -21,7 +21,7 @@ public class GameState { private Battle currEncounter = null; //Potentially useless. Keeps track of party characters who faint in battle. - private final ArrayList fainted = new ArrayList(); + private final ArrayList fainted = new ArrayList<>(); public GameState(Inventory inventory, BattleCharacter[] party, WalkingCharacter walkingCharacter) { this.inventory = inventory; diff --git a/src/main/java/com/mg105/interface_adapters/BattlePresenter.java b/src/main/java/com/mg105/interface_adapters/BattlePresenter.java index 30e14e5c..53bef1cd 100644 --- a/src/main/java/com/mg105/interface_adapters/BattlePresenter.java +++ b/src/main/java/com/mg105/interface_adapters/BattlePresenter.java @@ -1,29 +1,23 @@ package com.mg105.interface_adapters; -import com.mg105.entities.Battle; -import com.mg105.entities.BattleCharacter; -import com.mg105.entities.GameState; -import com.mg105.entities.Move; -import com.mg105.user_interface.BattleMenu; +import com.mg105.presenter_interfaces.BattlePresenterInterface; +import com.mg105.use_cases.BattleInteractor; import java.util.ArrayList; -import java.util.Random; /** * Class communicating between BattleMenu view and game entities. * Follows MVP pattern; contains a reference to the view and interacts with Battle and related classes. */ -public class BattlePresenter { +public class BattlePresenter implements BattlePresenterInterface { - private final GameState state; - private Battle encounter; + private final BattleInteractor interactor; private BattleMenuInterface view; - public BattlePresenter(GameState state) { - this.state = state; - this.encounter = state.getCurrEncounter(); - BattleMenu.setPresenter(this); + public BattlePresenter(BattleInteractor interactor) { + this.interactor = interactor; + this.interactor.setPresenter(this); } /** @@ -34,36 +28,21 @@ public BattlePresenter(GameState state) { public void setView(BattleMenuInterface view) { this.view = view; } + /** * Creates a new encounter with random opponents and sets it as the current encounter in GameState */ public void createEncounter() { - Random rand = new Random(); - - ArrayList opponents = new ArrayList<>(); - - for (int i = 0; i < 4; ++i){ - int charHealth = rand.nextInt(5, 41); - int charDmg = rand.nextInt(1, 11); - int charSpeed = rand.nextInt(3, 16); - Move m1 = new Move(-rand.nextInt(1, 8), 0, "first", false); - Move m2 = new Move(rand.nextInt(1, 4), 0, "second", true); - BattleCharacter character = new BattleCharacter(charHealth, "Opponent " + i, - charDmg, charSpeed, true, m1, m2); - opponents.add(character); - } - ArrayList party = this.state.getParty(); - Battle b = new Battle(opponents, party); - this.state.setCurrEncounter(b); - this.encounter = b; - - String[] partyNames = new String[party.size()]; - String[] opponentNames = new String[opponents.size()]; + interactor.createEncounter(); + } - for (int i = 0; i < party.size(); ++i) { - partyNames[i] = party.get(i).getName(); - opponentNames[i] = opponents.get(i).getName(); - } + /** + * Set the characters in the view. + * @param partyNames the name strings of the party characters. + * @param opponentNames the name strings of the opponent characters. + */ + @Override + public void setViewNames(String[] partyNames, String[] opponentNames) { if (view != null) { this.view.setNames(partyNames, opponentNames); } @@ -77,19 +56,7 @@ public void createEncounter() { * @return whether the given name corresponds to a fainted character. */ public boolean givenCharacterFainted(String name) { - for (BattleCharacter c : encounter.getPlayerCharacters()) { - if (c.getName().equals(name)) { - return false; - } - } - - for (BattleCharacter c : encounter.getOpponents()) { - if (c.getName().equals(name)) { - return false; - } - } - - return true; + return interactor.isCharacterFainted(name); } /** @@ -98,7 +65,7 @@ public boolean givenCharacterFainted(String name) { * @return the desired BattleCharacter's current health. */ public int givenCharacterHealth(String name) { - return this.encounter.getCharacter(name).getHp(); + return interactor.getCharacterHealth(name); } /** @@ -107,7 +74,7 @@ public int givenCharacterHealth(String name) { * @return the desired BattleCharacter's current damage. */ public int givenCharacterDamage(String name) { - return this.encounter.getCharacter(name).getDmg(); + return interactor.getCharacterDamage(name); } /** @@ -117,9 +84,7 @@ public int givenCharacterDamage(String name) { * @return the desired BattleCharacter's move stats. */ public int[] givenCharacterMoveStats(String name) { - BattleCharacter caster = this.encounter.getCharacter(name); - return new int[] {caster.getMoveOne().getHealthChange(), caster.getMoveOne().getDamageChange(), - caster.getMoveTwo().getHealthChange(), caster.getMoveTwo().getDamageChange()}; + return interactor.getCharacterMoveStats(name); } /** @@ -129,8 +94,7 @@ public int[] givenCharacterMoveStats(String name) { * @return the desired BattleCharacter's move names. */ public String[] givenCharacterMoveNames(String name) { - BattleCharacter caster = this.encounter.getCharacter(name); - return new String[] {caster.getMoveOne().getName(), caster.getMoveTwo().getName()}; + return interactor.getCharacterMoveNames(name); } /** @@ -141,48 +105,7 @@ public String[] givenCharacterMoveNames(String name) { * @return a String of the name of the moving character */ public String roundStart() { - - int status = this.encounter.getBattleStatus(); - if (status == -1) { //Player lost last round - //Something with ReplayGenerator - return null; - } else if (status == 1) { //Player won last round - this.endBattle(); - return null; - } else { //Battle is ongoing - BattleCharacter moving = this.encounter.getMovingCharacter(); - - if (moving.isOpponent()) { //Opponent character is moving - Random rand = new Random(); - int moveNumber = rand.nextInt(2); - - Move chosenMove; - if (moveNumber == 0) { - chosenMove = moving.getMoveOne(); - } else { - chosenMove = moving.getMoveTwo(); - } - - if (!chosenMove.isFriendly()) { - ArrayList players = this.encounter.getPlayerCharacters(); - - //Choose a random player character to attack - int target = rand.nextInt(players.size()); - - this._useMove(chosenMove, moving, players.get(target)); - } else { - ArrayList opponents = this.encounter.getOpponents(); - - //Choose a random opponent to use the friendly move on - int target = rand.nextInt(opponents.size()); - - this._useMove(chosenMove, moving, opponents.get(target)); - } - } - - //No matter what, the moving BattleCharacter's name is returned - return moving.getName(); - } + return interactor.roundStart(); } /** @@ -195,34 +118,7 @@ public String roundStart() { * @return ArrayList of Strings representing the names of every possible target BattleCharacter. */ public ArrayList retrieveTargets(int moveNum, String casterName) { - //Retrieve the moving BattleCharacter - BattleCharacter caster = this.encounter.getCharacter(casterName); - - //Retrieve the Move being used - Move m; - if (moveNum == 1) { - m = caster.getMoveOne(); - } else { //moveNum == 2 - m = caster.getMoveTwo(); - } - - ArrayList targets = new ArrayList<>(); - - ArrayList targetCharacters; - - //Retrieve possible target BattleCharacters - if (m.isFriendly()) { //caster is a player character, so targets are player characters - targetCharacters = this.encounter.getPlayerCharacters(); - } else { //caster is a player character, so targets are opponent characters - targetCharacters = this.encounter.getOpponents(); - } - - //Add character names to ArrayList - for (BattleCharacter c : targetCharacters) { - targets.add(c.getName()); - } - - return targets; + return interactor.retrieveTargets(moveNum, casterName); } /** @@ -232,55 +128,24 @@ public ArrayList retrieveTargets(int moveNum, String casterName) { * @param targetName String representing the name of the target BattleCharacter. */ public void executeTurn(int moveNum, String casterName, String targetName) { - BattleCharacter caster = this.encounter.getCharacter(casterName); - BattleCharacter target = this.encounter.getCharacter(targetName); - if (moveNum == 1) { - this._useMove(caster.getMoveOne(), caster, target); - } else { //moveNum == 2 - this._useMove(caster.getMoveTwo(), caster, target); - } + interactor.executeTurn(moveNum, casterName, targetName); } + /** + * UNIMPLEMENTED + */ public void endBattle() { - //unimplemented, includes _removeActiveBattle and _addReward() + interactor.endBattle(); } /** - * Applies the given move used by given caster onto the given target. - * If the target faints and is a player character, remove it from the list of active players in state, - * and add it to the list of fainted characters. - * Calls on the view to update the impacted character. + * Call on the BattleMenuInterface to update the displayed information for the given character. + * @param targetName the name String of the character whose information displayed on the view needs to be updated. */ - private void _useMove(Move m, BattleCharacter caster, BattleCharacter target) { - target.modifyHealth(m.getHealthChange()); - - //If the move is to be used on a character on the other team, and the move is meant to deal health damage, - // then increase the health damage applied by the move based on the character's damage stat. - if (!m.isFriendly() && m.getHealthChange() < 0) { - target.modifyHealth(-caster.getDmg()); - } - - if (target.getHp() == 0) { - this.encounter.removeChar(target); - if (!target.isOpponent()) { - this.state.getParty().remove(target); - this.state.getFainted().add(target); - } - } - - target.modifyDamage(m.getDamageChange()); - + @Override + public void updateViewCharacter(String targetName) { if (view != null) { - this.view.updateCharacter(target.getName()); + this.view.updateCharacter(targetName); } } - - private void _addReward() { - //unimplemented - } - - private void _removeActiveBattle() { - //unimplemented - } - } diff --git a/src/main/java/com/mg105/presenter_interfaces/BattlePresenterInterface.java b/src/main/java/com/mg105/presenter_interfaces/BattlePresenterInterface.java new file mode 100644 index 00000000..d6a8f6fb --- /dev/null +++ b/src/main/java/com/mg105/presenter_interfaces/BattlePresenterInterface.java @@ -0,0 +1,17 @@ +package com.mg105.presenter_interfaces; + +public interface BattlePresenterInterface { + + /** + * Set the characters in the view. + * @param partyNames the name strings of the party characters. + * @param opponentNames the name strings of the opponent characters. + */ + void setViewNames(String[] partyNames, String[] opponentNames); + + /** + * Call on the BattleMenuInterface to update the displayed information for the given character. + * @param targetName the name String of the character whose information displayed on the view needs to be updated. + */ + void updateViewCharacter(String targetName); +} diff --git a/src/main/java/com/mg105/use_cases/BattleInteractor.java b/src/main/java/com/mg105/use_cases/BattleInteractor.java new file mode 100644 index 00000000..af778e3c --- /dev/null +++ b/src/main/java/com/mg105/use_cases/BattleInteractor.java @@ -0,0 +1,290 @@ +package com.mg105.use_cases; + +import com.mg105.entities.Battle; +import com.mg105.entities.BattleCharacter; +import com.mg105.entities.GameState; +import com.mg105.entities.Move; +import com.mg105.interface_adapters.BattlePresenter; +import com.mg105.presenter_interfaces.BattlePresenterInterface; + +import java.util.ArrayList; +import java.util.Random; + +public class BattleInteractor { + + private final GameState state; + private Battle encounter; + + private BattlePresenterInterface presenter; + + public BattleInteractor(GameState state) { + this.state = state; + this.encounter = state.getCurrEncounter(); + } + + /** + * Sets the presenter attribute. + * + * @param presenter the BattlePresenterInterface instance to set the presenter attribute to. + */ + public void setPresenter(BattlePresenterInterface presenter) { + this.presenter = presenter; + } + + /** + * Creates a new encounter with random opponents and sets it as the current encounter in GameState + */ + public void createEncounter() { + Random rand = new Random(); + + ArrayList opponents = new ArrayList<>(); + + for (int i = 0; i < 4; ++i){ + int charHealth = rand.nextInt(5, 41); + int charDmg = rand.nextInt(1, 11); + int charSpeed = rand.nextInt(3, 16); + Move m1 = new Move(-rand.nextInt(1, 8), 0, "first", false); + Move m2 = new Move(rand.nextInt(1, 4), 0, "second", true); + BattleCharacter character = new BattleCharacter(charHealth, "Opponent " + i, + charDmg, charSpeed, true, m1, m2); + opponents.add(character); + } + ArrayList party = this.state.getParty(); + Battle b = new Battle(opponents, party); + this.state.setCurrEncounter(b); + this.encounter = b; + + String[] partyNames = new String[party.size()]; + String[] opponentNames = new String[opponents.size()]; + + for (int i = 0; i < party.size(); ++i) { + partyNames[i] = party.get(i).getName(); + } + + for (int i = 0; i < opponents.size(); ++i) { + opponentNames[i] = opponents.get(i).getName(); + } + + presenter.setViewNames(partyNames, opponentNames); + } + + /** + * Returns whether the given name is associated with a fainted character. + * Assumes that the inputted name corresponds to a character who was in the encounter at some point. + * + * @param name the name of the character being checked. + * @return whether the given name corresponds to a fainted character. + */ + public boolean isCharacterFainted(String name) { + for (BattleCharacter c : encounter.getPlayerCharacters()) { + if (c.getName().equals(name)) { + return false; + } + } + + for (BattleCharacter c : encounter.getOpponents()) { + if (c.getName().equals(name)) { + return false; + } + } + + return true; + } + + /** + * Returns the current health of the BattleCharacter with the given name. + * + * @return the desired BattleCharacter's current health. + */ + public int getCharacterHealth(String name) { + return this.encounter.getCharacter(name).getHp(); + } + + /** + * Returns the current damage stat of the BattleCharacter with the given name. + * + * @return the desired BattleCharacter's current damage. + */ + public int getCharacterDamage(String name) { + return this.encounter.getCharacter(name).getDmg(); + } + + /** + * Returns the stats of the BattleCharacter with the given name's moves. + * Stats order: Move1 health change, Move1 damage change, Move2 health change, Move2 damage change. + * + * @return the desired BattleCharacter's move stats. + */ + public int[] getCharacterMoveStats(String name) { + BattleCharacter caster = this.encounter.getCharacter(name); + return new int[] {caster.getMoveOne().getHealthChange(), caster.getMoveOne().getDamageChange(), + caster.getMoveTwo().getHealthChange(), caster.getMoveTwo().getDamageChange()}; + } + + /** + * Returns the names of the BattleCharacter with the given name's moves. + * Stats order: Move1 name, Move2 name. + * + * @return the desired BattleCharacter's move names. + */ + public String[] getCharacterMoveNames(String name) { + BattleCharacter caster = this.encounter.getCharacter(name); + return new String[] {caster.getMoveOne().getName(), caster.getMoveTwo().getName()}; + } + + /** + * Starts a round of the encounter. If battle ended last round, end the encounter/the run depending on the result. + * If encounter is still in progress, get the next moving character. + * If opponent is moving, choose a random move and random target and use it. + * + * @return a String of the name of the moving character + */ + public String roundStart() { + int status = this.encounter.getBattleStatus(); + if (status == -1) { //Player lost last round + //Something with ReplayGenerator + return null; + } else if (status == 1) { //Player won last round + this.endBattle(); + return null; + } else { //Battle is ongoing + BattleCharacter moving = this.encounter.getMovingCharacter(); + + if (moving.isOpponent()) { //Opponent character is moving + Random rand = new Random(); + int moveNumber = rand.nextInt(2); + + Move chosenMove; + if (moveNumber == 0) { + chosenMove = moving.getMoveOne(); + } else { + chosenMove = moving.getMoveTwo(); + } + + if (!chosenMove.isFriendly()) { + ArrayList players = this.encounter.getPlayerCharacters(); + + //Choose a random player character to attack + int target = rand.nextInt(players.size()); + + this._useMove(chosenMove, moving, players.get(target)); + } else { + ArrayList opponents = this.encounter.getOpponents(); + + //Choose a random opponent to use the friendly move on + int target = rand.nextInt(opponents.size()); + + this._useMove(chosenMove, moving, opponents.get(target)); + } + } + + //No matter what, the moving BattleCharacter's name is returned + return moving.getName(); + } + } + + /** + * Returns the name of every BattleCharacter which can be targeted by the given move. + * Note: Function should only be called from view when caster is friendly, so method does not accommodate for case + * where caster is an opponent. + * + * @param moveNum integer representing which of the two Moves is being used. + * @param casterName String representing the name of the given moving BattleCharacter. + * @return ArrayList of Strings representing the names of every possible target BattleCharacter. + */ + public ArrayList retrieveTargets(int moveNum, String casterName) { + //Retrieve the moving BattleCharacter + BattleCharacter caster = this.encounter.getCharacter(casterName); + + //Retrieve the Move being used + Move m; + if (moveNum == 1) { + m = caster.getMoveOne(); + } else { //moveNum == 2 + m = caster.getMoveTwo(); + } + + ArrayList targets = new ArrayList<>(); + + ArrayList targetCharacters; + + //Retrieve possible target BattleCharacters + if (m.isFriendly()) { //caster is a player character, so targets are player characters + targetCharacters = this.encounter.getPlayerCharacters(); + } else { //caster is a player character, so targets are opponent characters + targetCharacters = this.encounter.getOpponents(); + } + + //Add character names to ArrayList + for (BattleCharacter c : targetCharacters) { + targets.add(c.getName()); + } + + return targets; + } + + /** + * Use one of (given) the given caster's moves on the given target. + * @param moveNum integer representing which of the two moves is being used. + * @param casterName String representing the name of the caster BattleCharacter. + * @param targetName String representing the name of the target BattleCharacter. + */ + public void executeTurn(int moveNum, String casterName, String targetName) { + BattleCharacter caster = this.encounter.getCharacter(casterName); + BattleCharacter target = this.encounter.getCharacter(targetName); + if (moveNum == 1) { + this._useMove(caster.getMoveOne(), caster, target); + } else { //moveNum == 2 + this._useMove(caster.getMoveTwo(), caster, target); + } + } + + /** + * Applies the given move used by given caster onto the given target. + * If the target faints and is a player character, remove it from the list of active players in state, + * and add it to the list of fainted characters. + * Calls on the view to update the impacted character. + */ + private void _useMove(Move m, BattleCharacter caster, BattleCharacter target) { + target.modifyHealth(m.getHealthChange()); + + //If the move is to be used on a character on the other team, and the move is meant to deal health damage, + // then increase the health damage applied by the move based on the character's damage stat. + if (!m.isFriendly() && m.getHealthChange() < 0) { + target.modifyHealth(-caster.getDmg()); + } + + if (target.getHp() == 0) { + this.encounter.removeChar(target); + if (!target.isOpponent()) { + this.state.getParty().remove(target); + this.state.getFainted().add(target); + } + } + + target.modifyDamage(m.getDamageChange()); + + presenter.updateViewCharacter(target.getName()); + } + + /** + * UNIMPLEMENTED + */ + public void endBattle() { + //unimplemented, includes _removeActiveBattle and _addReward() + } + + /** + * UNIMPLEMENTED + */ + private void _addReward() { + //unimplemented + } + + /** + * UNIMPLEMENTED + */ + private void _removeActiveBattle() { + //unimplemented + } +} diff --git a/src/main/java/com/mg105/user_interface/BattleMenu.java b/src/main/java/com/mg105/user_interface/BattleMenu.java index 95e180c7..f1dffec8 100644 --- a/src/main/java/com/mg105/user_interface/BattleMenu.java +++ b/src/main/java/com/mg105/user_interface/BattleMenu.java @@ -2,7 +2,6 @@ import com.mg105.interface_adapters.BattleMenuInterface; import com.mg105.interface_adapters.BattlePresenter; -import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Scene; @@ -10,12 +9,13 @@ import javafx.scene.control.Label; import javafx.scene.layout.GridPane; import javafx.stage.Stage; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; -public class BattleMenu extends Application implements EventHandler, BattleMenuInterface { +public class BattleMenu implements EventHandler, BattleMenuInterface, Toggleable{ - private static BattlePresenter presenter; + private final BattlePresenter presenter; private String[] playerNames = new String[4]; private final int[] playerHealth = new int[4]; private final int[] playerDmg = new int[4]; @@ -33,89 +33,29 @@ public class BattleMenu extends Application implements EventHandler private final Label o2 = new Label(); private final Label o3 = new Label(); - private Button nextRound; - private Button moveOne; - private Button moveTwo; - - private Button targetP0; - private Button targetP1; - private Button targetP2; - private Button targetP3; - private Button targetO0; - private Button targetO1; - private Button targetO2; - private Button targetO3; - private GridPane grid; - private Scene scene; + private final Button nextRound; + private final Button moveOne; + private final Button moveTwo; + + private final Button targetP0; + private final Button targetP1; + private final Button targetP2; + private final Button targetP3; + private final Button targetO0; + private final Button targetO1; + private final Button targetO2; + private final Button targetO3; + private final GridPane grid; + private final Scene scene; //Used in Button handle event private String moving; private int moveNum; - - public BattleMenu() { - presenter.setView(this); - presenter.createEncounter(); - } - - /** - * Sets the BattlePresenter attribute for every BattleMenu. - * - * @param pres the BattlePresenter instance to set the attribute to. - */ - public static void setPresenter(BattlePresenter pres) { - presenter = pres; - } - - /** - * Sets the names of the player and opponent characters participating in the active battle. - * - * @param playerNames array of name Strings representing player characters. - * @param opponentNames array of name Strings representing opponents. - */ - @Override - public void setNames(String[] playerNames, String[] opponentNames) { - this.playerNames = playerNames; - this.opponentNames = opponentNames; - - for (int i = 0; i < playerNames.length; ++i) { - this.playerHealth[i] = presenter.givenCharacterHealth(this.playerNames[i]); - this.playerDmg[i] = presenter.givenCharacterDamage(this.playerNames[i]); - - this.opponentHealth[i] = presenter.givenCharacterHealth(this.opponentNames[i]); - this.opponentDmg[i] = presenter.givenCharacterDamage(this.opponentNames[i]); - } - } - - /** - * Updates the display corresponding to the given affected character. - * - * @param character the character who needs to be updated on the screen. - */ - @Override - public void updateCharacter(String character){ - if (playerNames[0].equals(character)) { - updateCharacterData(character, 0, p0, false); - } else if (playerNames[1].equals(character)) { - updateCharacterData(character, 1, p1, false); - } else if (playerNames[2].equals(character)) { - updateCharacterData(character, 2, p2, false); - } else if (playerNames[3].equals(character)) { - updateCharacterData(character, 3, p3, false); - } else if (opponentNames[0].equals(character)) { - updateCharacterData(character, 0, o0, true); - } else if (opponentNames[1].equals(character)) { - updateCharacterData(character, 1, o1, true); - } else if (opponentNames[2].equals(character)) { - updateCharacterData(character, 2, o2, true); - } else if (opponentNames[3].equals(character)) { - updateCharacterData(character, 3, o3, true); - } - } - @Override - public void start(Stage primaryStage) { - primaryStage.setTitle("Battle"); + public BattleMenu(BattlePresenter battlePres) { + this.presenter = battlePres; + presenter.setView(this); grid = new GridPane(); grid.setVgap(10); @@ -126,16 +66,6 @@ public void start(Stage primaryStage) { nextRound.setOnAction(this); grid.add(nextRound, 10, 30); - setupCharacterLabel(p0, 0, false); - setupCharacterLabel(p1, 1, false); - setupCharacterLabel(p2, 2, false); - setupCharacterLabel(p3, 3, false); - - setupCharacterLabel(o0, 0, true); - setupCharacterLabel(o1, 1, true); - setupCharacterLabel(o2, 2, true); - setupCharacterLabel(o3, 3, true); - grid.add(p0, 1, 4); grid.add(p1, 1, 8); grid.add(p2, 1, 12); @@ -195,8 +125,92 @@ public void start(Stage primaryStage) { moveTwo.setVisible(false); scene = new Scene(grid, 800, 800); - primaryStage.setScene(scene); - primaryStage.show(); + } + + /** + * Sets the names of the player and opponent characters participating in the active battle. + * + * @param playerNames array of name Strings representing player characters. + * @param opponentNames array of name Strings representing opponents. + */ + @Override + public void setNames(String[] playerNames, String[] opponentNames) { + for (int i = 0; i < 4; ++i) { + //Check if any player characters have fainted. Opponent set will always contain four characters initially. + if (playerNames.length <= i) { + this.playerNames[i] = "FAINTED"; + this.playerHealth[i] = 0; + this.playerDmg[i] = 0; + } else { + this.playerNames[i] = playerNames[i]; + this.playerHealth[i] = presenter.givenCharacterHealth(this.playerNames[i]); + this.playerDmg[i] = presenter.givenCharacterDamage(this.playerNames[i]); + } + + this.opponentNames[i] = opponentNames[i]; + this.opponentHealth[i] = presenter.givenCharacterHealth(this.opponentNames[i]); + this.opponentDmg[i] = presenter.givenCharacterDamage(this.opponentNames[i]); + } + } + + /** + * Updates the display corresponding to the given affected character. + * + * @param character the character who needs to be updated on the screen. + */ + @Override + public void updateCharacter(String character){ + if (playerNames[0].equals(character)) { + updateCharacterData(character, 0, p0, false); + } else if (playerNames[1].equals(character)) { + updateCharacterData(character, 1, p1, false); + } else if (playerNames[2].equals(character)) { + updateCharacterData(character, 2, p2, false); + } else if (playerNames[3].equals(character)) { + updateCharacterData(character, 3, p3, false); + } else if (opponentNames[0].equals(character)) { + updateCharacterData(character, 0, o0, true); + } else if (opponentNames[1].equals(character)) { + updateCharacterData(character, 1, o1, true); + } else if (opponentNames[2].equals(character)) { + updateCharacterData(character, 2, o2, true); + } else if (opponentNames[3].equals(character)) { + updateCharacterData(character, 3, o3, true); + } + } + + /** + * Get the scene of this toggleable object. It is this scene that will be displayed. + * + * @return the scene to be displayed. + */ + @Override + @NotNull + public Scene getScene() { + return this.scene; + } + + /** + * Set the visibility of this component. + * + * @param isVisible true if the Toggleable is now visible, false otherwise. If false the Toggleable is expected + * to do nothing on ANY user inputs. + */ + @Override + public void toggle(boolean isVisible) { + if (isVisible) { + presenter.createEncounter(); //Will call setNames and update character data. + + setupCharacterLabel(p0, 0, false); + setupCharacterLabel(p1, 1, false); + setupCharacterLabel(p2, 2, false); + setupCharacterLabel(p3, 3, false); + + setupCharacterLabel(o0, 0, true); + setupCharacterLabel(o1, 1, true); + setupCharacterLabel(o2, 2, true); + setupCharacterLabel(o3, 3, true); + } } @Override @@ -417,7 +431,7 @@ private void displayTargets() { } /** - * Helper function to initialize the character labels in + * Helper function to initialize the character labels. * @param lbl Label object corresponding to the character. * @param position Integer representing index of character's data in data arrays. * @param isOpponent Boolean of whether the character is an opponent. @@ -427,8 +441,12 @@ private void setupCharacterLabel(Label lbl, int position, boolean isOpponent) { lbl.setText(opponentNames[position] + "\n Hp: " + opponentHealth[position] + ", Dmg: " + opponentDmg[position]); } else { - lbl.setText(playerNames[position] + "\n Hp: " + playerHealth[position] + ", Dmg: " + - playerDmg[position]); + if (playerNames[position].equals("FAINTED")) { + lbl.setText("FAINTED"); + } else { + lbl.setText(playerNames[position] + "\n Hp: " + playerHealth[position] + ", Dmg: " + + playerDmg[position]); + } } } } From 484a84f1812ea1f33c029d93027fb18e33f7d819 Mon Sep 17 00:00:00 2001 From: m-grigoriu Date: Tue, 29 Nov 2022 11:29:11 -0500 Subject: [PATCH 10/22] Removed condition checking if view attribute of BattlePresenter is null, since the methods containing the statements are never called when the view attribute is null. --- .../com/mg105/interface_adapters/BattlePresenter.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/mg105/interface_adapters/BattlePresenter.java b/src/main/java/com/mg105/interface_adapters/BattlePresenter.java index 53bef1cd..ee29fb5d 100644 --- a/src/main/java/com/mg105/interface_adapters/BattlePresenter.java +++ b/src/main/java/com/mg105/interface_adapters/BattlePresenter.java @@ -43,9 +43,7 @@ public void createEncounter() { */ @Override public void setViewNames(String[] partyNames, String[] opponentNames) { - if (view != null) { - this.view.setNames(partyNames, opponentNames); - } + this.view.setNames(partyNames, opponentNames); } /** @@ -144,8 +142,6 @@ public void endBattle() { */ @Override public void updateViewCharacter(String targetName) { - if (view != null) { - this.view.updateCharacter(targetName); - } + this.view.updateCharacter(targetName); } } From 601a5606410ba7c46345cd4d72edbdd751ccb038 Mon Sep 17 00:00:00 2001 From: m-grigoriu Date: Tue, 29 Nov 2022 12:42:36 -0500 Subject: [PATCH 11/22] - Removed generic references in ArrayList declarations and changed modification of party attribute in constructor for GameState to remove some warnings. - Added BattleInteractorTest. - Re-added condition statements in BattleMenu and BattlePresenter to allow unit tests for BattleInteractor to pass. --- .../java/com/mg105/entities/GameState.java | 7 +- .../interface_adapters/BattlePresenter.java | 37 +++-- .../com/mg105/use_cases/BattleInteractor.java | 7 +- .../com/mg105/user_interface/BattleMenu.java | 9 +- .../Battle/BattleInteractorTest.java | 126 ++++++++++++++++++ 5 files changed, 162 insertions(+), 24 deletions(-) create mode 100644 src/test/java/com/mg105/use_cases/Battle/BattleInteractorTest.java diff --git a/src/main/java/com/mg105/entities/GameState.java b/src/main/java/com/mg105/entities/GameState.java index 670218c4..5f3b715e 100644 --- a/src/main/java/com/mg105/entities/GameState.java +++ b/src/main/java/com/mg105/entities/GameState.java @@ -1,6 +1,7 @@ package com.mg105.entities; import java.util.ArrayList; +import java.util.Arrays; import java.util.NoSuchElementException; import org.jetbrains.annotations.NotNull; @@ -25,11 +26,9 @@ public class GameState { public GameState(Inventory inventory, BattleCharacter[] party, WalkingCharacter walkingCharacter) { this.inventory = inventory; - this.party = new ArrayList(); + this.party = new ArrayList<>(); - for (BattleCharacter c : party) { - this.party.add(c); - } + this.party.addAll(Arrays.asList(party)); this.walkingCharacter = walkingCharacter; } diff --git a/src/main/java/com/mg105/interface_adapters/BattlePresenter.java b/src/main/java/com/mg105/interface_adapters/BattlePresenter.java index ee29fb5d..e20ad009 100644 --- a/src/main/java/com/mg105/interface_adapters/BattlePresenter.java +++ b/src/main/java/com/mg105/interface_adapters/BattlePresenter.java @@ -32,20 +32,10 @@ public void setView(BattleMenuInterface view) { /** * Creates a new encounter with random opponents and sets it as the current encounter in GameState */ - public void createEncounter() { + public void startBattle() { interactor.createEncounter(); } - /** - * Set the characters in the view. - * @param partyNames the name strings of the party characters. - * @param opponentNames the name strings of the opponent characters. - */ - @Override - public void setViewNames(String[] partyNames, String[] opponentNames) { - this.view.setNames(partyNames, opponentNames); - } - /** * Returns whether the given name is associated with a fainted character. * Assumes that the inputted name corresponds to a character who was in the encounter at some point. @@ -130,10 +120,17 @@ public void executeTurn(int moveNum, String casterName, String targetName) { } /** - * UNIMPLEMENTED + * Set the characters in the view. + * @param partyNames the name strings of the party characters. + * @param opponentNames the name strings of the opponent characters. */ - public void endBattle() { - interactor.endBattle(); + @Override + public void setViewNames(String[] partyNames, String[] opponentNames) { + if (this.view == null) { //Used for unit tests. Never executed during regular running of the application. + return; + } + + this.view.setNames(partyNames, opponentNames); } /** @@ -142,6 +139,18 @@ public void endBattle() { */ @Override public void updateViewCharacter(String targetName) { + if (this.view == null) { //Used for unit tests. Never executed during regular running of the application. + return; + } + this.view.updateCharacter(targetName); } + + /** + * UNIMPLEMENTED + */ + public void endBattle() { + interactor.endBattle(); + } + } diff --git a/src/main/java/com/mg105/use_cases/BattleInteractor.java b/src/main/java/com/mg105/use_cases/BattleInteractor.java index af778e3c..4c7f701c 100644 --- a/src/main/java/com/mg105/use_cases/BattleInteractor.java +++ b/src/main/java/com/mg105/use_cases/BattleInteractor.java @@ -4,7 +4,6 @@ import com.mg105.entities.BattleCharacter; import com.mg105.entities.GameState; import com.mg105.entities.Move; -import com.mg105.interface_adapters.BattlePresenter; import com.mg105.presenter_interfaces.BattlePresenterInterface; import java.util.ArrayList; @@ -65,6 +64,9 @@ public void createEncounter() { opponentNames[i] = opponents.get(i).getName(); } + if (this.presenter == null) { //Used for unit tests. Never executed during regular running of the application. + return; + } presenter.setViewNames(partyNames, opponentNames); } @@ -264,6 +266,9 @@ private void _useMove(Move m, BattleCharacter caster, BattleCharacter target) { target.modifyDamage(m.getDamageChange()); + if (this.presenter == null) { //Used for unit tests. Never executed during regular running of the application. + return; + } presenter.updateViewCharacter(target.getName()); } diff --git a/src/main/java/com/mg105/user_interface/BattleMenu.java b/src/main/java/com/mg105/user_interface/BattleMenu.java index f1dffec8..73a9e226 100644 --- a/src/main/java/com/mg105/user_interface/BattleMenu.java +++ b/src/main/java/com/mg105/user_interface/BattleMenu.java @@ -16,10 +16,10 @@ public class BattleMenu implements EventHandler, BattleMenuInterface, Toggleable{ private final BattlePresenter presenter; - private String[] playerNames = new String[4]; + private final String[] playerNames = new String[4]; private final int[] playerHealth = new int[4]; private final int[] playerDmg = new int[4]; - private String[] opponentNames = new String[4]; + private final String[] opponentNames = new String[4]; private final int[] opponentHealth = new int[4]; private final int[] opponentDmg = new int[4]; @@ -185,8 +185,7 @@ public void updateCharacter(String character){ * @return the scene to be displayed. */ @Override - @NotNull - public Scene getScene() { + public @NotNull Scene getScene() { return this.scene; } @@ -199,7 +198,7 @@ public Scene getScene() { @Override public void toggle(boolean isVisible) { if (isVisible) { - presenter.createEncounter(); //Will call setNames and update character data. + presenter.startBattle(); //Will call setNames and update character data. setupCharacterLabel(p0, 0, false); setupCharacterLabel(p1, 1, false); diff --git a/src/test/java/com/mg105/use_cases/Battle/BattleInteractorTest.java b/src/test/java/com/mg105/use_cases/Battle/BattleInteractorTest.java new file mode 100644 index 00000000..2e4d3872 --- /dev/null +++ b/src/test/java/com/mg105/use_cases/Battle/BattleInteractorTest.java @@ -0,0 +1,126 @@ +package com.mg105.use_cases.Battle; + +import com.mg105.entities.*; +import com.mg105.use_cases.BattleInteractor; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.awt.*; +import java.util.ArrayList; + +class BattleInteractorTest { + + @Test + void createValidEncounter() { + Inventory inventory = new Inventory(); + WalkingCharacter character = new WalkingCharacter(new Point(0, 0)); + BattleCharacter p1 = new BattleCharacter(14, "Leslie", 7, 8, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p2 = new BattleCharacter(9, "Mariam", 6, 11, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p3 = new BattleCharacter(10, "Michael", 10, 10, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p4 = new BattleCharacter(6, "Alex", 12, 14, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + + BattleCharacter[] party = {p1, p2, p3, p4}; + + GameState state = new GameState(inventory, party, character); + BattleInteractor interactor = new BattleInteractor(state); + interactor.createEncounter(); + + Assertions.assertEquals(4, interactor.retrieveTargets(1, "Leslie").size()); + Assertions.assertEquals(4, interactor.retrieveTargets(2, "Leslie").size()); + Assertions.assertNotNull(interactor.roundStart()); + } + + @Test + void executeMoveSuccess() { + Inventory inventory = new Inventory(); + WalkingCharacter character = new WalkingCharacter(new Point(0, 0)); + BattleCharacter p1 = new BattleCharacter(14, "Leslie", 7, 8, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p2 = new BattleCharacter(9, "Mariam", 6, 11, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p3 = new BattleCharacter(10, "Michael", 10, 10, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p4 = new BattleCharacter(6, "Alex", 12, 14, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + + BattleCharacter[] party = {p1, p2, p3, p4}; + + GameState state = new GameState(inventory, party, character); + BattleInteractor interactor = new BattleInteractor(state); + interactor.createEncounter(); + + ArrayList targets = interactor.retrieveTargets(1, "Leslie"); + String target = targets.get(0); + int originalHealth = interactor.getCharacterHealth(target); + interactor.executeTurn(1, "Leslie", target); + + Assertions.assertTrue(interactor.isCharacterFainted(target) || + interactor.getCharacterHealth(target) != originalHealth); + } + + @Test + void findFaintedCharacter() { + Inventory inventory = new Inventory(); + WalkingCharacter character = new WalkingCharacter(new Point(0, 0)); + BattleCharacter p1 = new BattleCharacter(14, "Leslie", 7, 8, false, + new Move(-2000, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p2 = new BattleCharacter(9, "Mariam", 6, 11, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p3 = new BattleCharacter(10, "Michael", 10, 10, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p4 = new BattleCharacter(6, "Alex", 12, 14, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + + BattleCharacter[] party = {p1, p2, p3, p4}; + + GameState state = new GameState(inventory, party, character); + BattleInteractor interactor = new BattleInteractor(state); + interactor.createEncounter(); + + interactor.executeTurn(1, "Leslie", "Opponent 0"); + Assertions.assertTrue(interactor.isCharacterFainted("Opponent 0")); + } + + @Test + void startRoundProperly() { + Inventory inventory = new Inventory(); + WalkingCharacter character = new WalkingCharacter(new Point(0, 0)); + BattleCharacter p1 = new BattleCharacter(14, "Leslie", 7, 2000, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p2 = new BattleCharacter(9, "Mariam", 6, 11, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p3 = new BattleCharacter(10, "Michael", 10, 10, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p4 = new BattleCharacter(6, "Alex", 12, 14, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + + BattleCharacter[] party = {p1, p2, p3, p4}; + + GameState state = new GameState(inventory, party, character); + BattleInteractor interactor = new BattleInteractor(state); + interactor.createEncounter(); + + Assertions.assertEquals("Leslie", interactor.roundStart()); + } +} + From 99dc41c97349c90c16fb33ae47c53b047e65368c Mon Sep 17 00:00:00 2001 From: Theodore Date: Tue, 29 Nov 2022 13:08:11 -0500 Subject: [PATCH 12/22] Remove direct RoomInterpreter dependencies on entities. --- .../interface_adapters/RoomInterpreter.java | 20 +++--- .../java/com/mg105/use_cases/RoomGetter.java | 35 +++++---- .../java/com/mg105/use_cases/RoomLayout.java | 71 +++++++++++++++++++ 3 files changed, 103 insertions(+), 23 deletions(-) create mode 100644 src/main/java/com/mg105/use_cases/RoomLayout.java diff --git a/src/main/java/com/mg105/interface_adapters/RoomInterpreter.java b/src/main/java/com/mg105/interface_adapters/RoomInterpreter.java index 6b6f1ac0..2679ab8d 100644 --- a/src/main/java/com/mg105/interface_adapters/RoomInterpreter.java +++ b/src/main/java/com/mg105/interface_adapters/RoomInterpreter.java @@ -1,7 +1,7 @@ package com.mg105.interface_adapters; -import com.mg105.entities.*; import com.mg105.use_cases.RoomGetter; +import com.mg105.use_cases.RoomLayout; import com.mg105.utils.MapConstants; import org.jetbrains.annotations.NotNull; @@ -45,23 +45,21 @@ public TileType[][] getCurrentRoom() { canvas[i][MapConstants.ROOM_SIZE-1] = TileType.WALL; } - Room room = getter.getCurrentRoom(); + RoomLayout room = getter.getCurrentRoomLayout(); - for (Doorway doorway : room.getDoorways()) { - canvas[doorway.getPosition().y][doorway.getPosition().x] = TileType.EXIT; + for (Point doorway : room.getDoorways()) { + canvas[doorway.y][doorway.x] = TileType.EXIT; } - for (TreasureChest chest : room.getChests()) { - canvas[chest.getPosition().y][chest.getPosition().x] = TileType.CHEST; + for (Point chest : room.getChests()) { + canvas[chest.y][chest.x] = TileType.CHEST; } - for (OpponentSet opponents : room.getOpponents()) { - canvas[opponents.getPosition().y][opponents.getPosition().x] = TileType.OPPONENT_SET; + for (Point opponents : room.getOpponents()) { + canvas[opponents.y][opponents.x] = TileType.OPPONENT_SET; } - WalkingCharacter player = getter.getWalkingCharacter(); - Point playerPosition = player.getCharPosition(); - canvas[playerPosition.y][playerPosition.x] = TileType.PLAYER; + canvas[room.getPlayer().y][room.getPlayer().x] = TileType.PLAYER; return canvas; } diff --git a/src/main/java/com/mg105/use_cases/RoomGetter.java b/src/main/java/com/mg105/use_cases/RoomGetter.java index 391c0930..6def1e7e 100644 --- a/src/main/java/com/mg105/use_cases/RoomGetter.java +++ b/src/main/java/com/mg105/use_cases/RoomGetter.java @@ -1,10 +1,15 @@ package com.mg105.use_cases; +import com.mg105.entities.Doorway; import com.mg105.entities.GameState; -import com.mg105.entities.Room; -import com.mg105.entities.WalkingCharacter; +import com.mg105.entities.OpponentSet; +import com.mg105.entities.TreasureChest; import org.jetbrains.annotations.NotNull; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + /** * RoomGetter is responsible for getting the state current room. */ @@ -27,16 +32,22 @@ public RoomGetter(@NotNull GameState state) { * * @return the current room. */ - public Room getCurrentRoom() { - return state.getCurrentRoom(); - } + public @NotNull RoomLayout getCurrentRoomLayout() { + List chests = new ArrayList<>(state.getCurrentRoom().getChests().size()); + for (TreasureChest chest : state.getCurrentRoom().getChests()) { + chests.add(chest.getPosition()); + } - /** - * Get the position current walking character. - * - * @return the current walking character. - */ - public @NotNull WalkingCharacter getWalkingCharacter() { - return state.getWalkingCharacter(); + List opponents = new ArrayList<>(state.getCurrentRoom().getOpponents().size()); + for (OpponentSet opponent : state.getCurrentRoom().getOpponents()) { + opponents.add(opponent.getPosition()); + } + + List doorways = new ArrayList<>(state.getCurrentRoom().getDoorways().size()); + for (Doorway doorway : state.getCurrentRoom().getDoorways()) { + doorways.add(doorway.getPosition()); + } + + return new RoomLayout(chests, opponents, doorways, state.getWalkingCharacter().getCharPosition()); } } diff --git a/src/main/java/com/mg105/use_cases/RoomLayout.java b/src/main/java/com/mg105/use_cases/RoomLayout.java new file mode 100644 index 00000000..c808476e --- /dev/null +++ b/src/main/java/com/mg105/use_cases/RoomLayout.java @@ -0,0 +1,71 @@ +package com.mg105.use_cases; + +import org.jetbrains.annotations.NotNull; +import java.util.List; + +import java.awt.*; + +/** + * The layout of a room. + *

+ * Note: There is an implicit, assumed, border around the edge. + */ +public class RoomLayout { + private final @NotNull List chests; + private final @NotNull List opponents; + private final @NotNull List doorways; + private final @NotNull Point player; + + /** + * Create a room given some number of chests, opponents, and doorways. + * + * @param chests the chests in this room. + * @param opponents the opponents in this room. + * @param doorways the doorways in this room leading to other rooms. + */ + public RoomLayout(@NotNull List chests, + @NotNull List opponents, + @NotNull List doorways, + @NotNull Point player) { + this.chests = chests; + this.opponents = opponents; + this.doorways = doorways; + this.player = player; + } + + /** + * Get the treasure chests in this room. + * + * @return the treasure chest positions in this room. + */ + public @NotNull List getChests() { + return chests; + } + + /** + * Get the opponents in this room. + * + * @return the opponent positions in this room. + */ + public @NotNull List getOpponents() { + return opponents; + } + + /** + * Get the doorways in this room. + * + * @return the doorway positions in this room. + */ + public @NotNull List getDoorways() { + return doorways; + } + + /** + * Get the player position in this room. + * + * @return the player position in the room. + */ + public @NotNull Point getPlayer() { + return player; + } +} From b7e81107f98206adbe9ec17e0cc8dd498b1d95b8 Mon Sep 17 00:00:00 2001 From: m-grigoriu Date: Tue, 29 Nov 2022 13:12:54 -0500 Subject: [PATCH 13/22] - Updated/added documentation to BattleMenuInterface, BattleMenu, BattlePresenterInterface, BattlePresenter, and BattleInteractor. - Added BattlePresenterTest class. --- .../BattleMenuInterface.java | 5 + .../interface_adapters/BattlePresenter.java | 6 +- .../com/mg105/use_cases/BattleInteractor.java | 6 +- .../BattlePresenterInterface.java | 7 +- .../com/mg105/user_interface/BattleMenu.java | 3 + .../BattlePresenterTest.java | 128 ++++++++++++++++++ 6 files changed, 150 insertions(+), 5 deletions(-) rename src/main/java/com/mg105/{presenter_interfaces => use_cases}/BattlePresenterInterface.java (79%) create mode 100644 src/test/java/com/mg105/interface_adapters/BattlePresenterTest.java diff --git a/src/main/java/com/mg105/interface_adapters/BattleMenuInterface.java b/src/main/java/com/mg105/interface_adapters/BattleMenuInterface.java index b9dcd2eb..6a79ef3b 100644 --- a/src/main/java/com/mg105/interface_adapters/BattleMenuInterface.java +++ b/src/main/java/com/mg105/interface_adapters/BattleMenuInterface.java @@ -1,5 +1,10 @@ package com.mg105.interface_adapters; +/** + * This interface should be implemented by BattleMenu. + *

+ * The methods represent calls to update data attributes and the display. + */ public interface BattleMenuInterface { /** diff --git a/src/main/java/com/mg105/interface_adapters/BattlePresenter.java b/src/main/java/com/mg105/interface_adapters/BattlePresenter.java index e20ad009..66704e73 100644 --- a/src/main/java/com/mg105/interface_adapters/BattlePresenter.java +++ b/src/main/java/com/mg105/interface_adapters/BattlePresenter.java @@ -1,13 +1,13 @@ package com.mg105.interface_adapters; -import com.mg105.presenter_interfaces.BattlePresenterInterface; +import com.mg105.use_cases.BattlePresenterInterface; import com.mg105.use_cases.BattleInteractor; import java.util.ArrayList; /** - * Class communicating between BattleMenu view and game entities. - * Follows MVP pattern; contains a reference to the view and interacts with Battle and related classes. + * Class communicating between BattleMenuInterface view and BattleInteractor. + * Follows MVP pattern; contains a reference to the view and interacts with BattleInteractor. */ public class BattlePresenter implements BattlePresenterInterface { diff --git a/src/main/java/com/mg105/use_cases/BattleInteractor.java b/src/main/java/com/mg105/use_cases/BattleInteractor.java index 4c7f701c..37eae3ae 100644 --- a/src/main/java/com/mg105/use_cases/BattleInteractor.java +++ b/src/main/java/com/mg105/use_cases/BattleInteractor.java @@ -4,11 +4,15 @@ import com.mg105.entities.BattleCharacter; import com.mg105.entities.GameState; import com.mg105.entities.Move; -import com.mg105.presenter_interfaces.BattlePresenterInterface; import java.util.ArrayList; import java.util.Random; +/** + * This class interacts with the Battle entity. + *

+ * It is responsible for modifying Battle related entities and for the processing needed during combat encounters. + */ public class BattleInteractor { private final GameState state; diff --git a/src/main/java/com/mg105/presenter_interfaces/BattlePresenterInterface.java b/src/main/java/com/mg105/use_cases/BattlePresenterInterface.java similarity index 79% rename from src/main/java/com/mg105/presenter_interfaces/BattlePresenterInterface.java rename to src/main/java/com/mg105/use_cases/BattlePresenterInterface.java index d6a8f6fb..581d2f37 100644 --- a/src/main/java/com/mg105/presenter_interfaces/BattlePresenterInterface.java +++ b/src/main/java/com/mg105/use_cases/BattlePresenterInterface.java @@ -1,5 +1,10 @@ -package com.mg105.presenter_interfaces; +package com.mg105.use_cases; +/** + * This interface should be implemented by BattlePresenter. + *

+ * The methods represent calls to update the view. + */ public interface BattlePresenterInterface { /** diff --git a/src/main/java/com/mg105/user_interface/BattleMenu.java b/src/main/java/com/mg105/user_interface/BattleMenu.java index 73a9e226..9e15d50e 100644 --- a/src/main/java/com/mg105/user_interface/BattleMenu.java +++ b/src/main/java/com/mg105/user_interface/BattleMenu.java @@ -13,6 +13,9 @@ import java.util.ArrayList; +/** + * This class uses JavaFX and is displayed during an active battle. + */ public class BattleMenu implements EventHandler, BattleMenuInterface, Toggleable{ private final BattlePresenter presenter; diff --git a/src/test/java/com/mg105/interface_adapters/BattlePresenterTest.java b/src/test/java/com/mg105/interface_adapters/BattlePresenterTest.java new file mode 100644 index 00000000..031e4d29 --- /dev/null +++ b/src/test/java/com/mg105/interface_adapters/BattlePresenterTest.java @@ -0,0 +1,128 @@ +package com.mg105.interface_adapters; + +import com.mg105.entities.*; +import com.mg105.use_cases.BattleInteractor; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.awt.*; +import java.util.ArrayList; + +class BattlePresenterTest { + @Test + void startValidBattle() { + Inventory inventory = new Inventory(); + WalkingCharacter character = new WalkingCharacter(new Point(0, 0)); + BattleCharacter p1 = new BattleCharacter(14, "Leslie", 7, 8, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p2 = new BattleCharacter(9, "Mariam", 6, 11, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p3 = new BattleCharacter(10, "Michael", 10, 10, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p4 = new BattleCharacter(6, "Alex", 12, 14, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + + BattleCharacter[] party = {p1, p2, p3, p4}; + + GameState state = new GameState(inventory, party, character); + BattleInteractor interactor = new BattleInteractor(state); + BattlePresenter presenter = new BattlePresenter(interactor); + presenter.startBattle(); + + Assertions.assertEquals(4, presenter.retrieveTargets(1, "Leslie").size()); + Assertions.assertEquals(4, presenter.retrieveTargets(2, "Leslie").size()); + Assertions.assertNotNull(presenter.roundStart()); + } + + @Test + void executeMoveSuccess() { + Inventory inventory = new Inventory(); + WalkingCharacter character = new WalkingCharacter(new Point(0, 0)); + BattleCharacter p1 = new BattleCharacter(14, "Leslie", 7, 8, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p2 = new BattleCharacter(9, "Mariam", 6, 11, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p3 = new BattleCharacter(10, "Michael", 10, 10, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p4 = new BattleCharacter(6, "Alex", 12, 14, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + + BattleCharacter[] party = {p1, p2, p3, p4}; + + GameState state = new GameState(inventory, party, character); + BattleInteractor interactor = new BattleInteractor(state); + BattlePresenter presenter = new BattlePresenter(interactor); + presenter.startBattle(); + + ArrayList targets = presenter.retrieveTargets(1, "Leslie"); + String target = targets.get(0); + int originalHealth = presenter.givenCharacterHealth(target); + presenter.executeTurn(1, "Leslie", target); + + Assertions.assertTrue(presenter.givenCharacterFainted(target) || + presenter.givenCharacterHealth(target) != originalHealth); + } + + @Test + void findFaintedCharacter() { + Inventory inventory = new Inventory(); + WalkingCharacter character = new WalkingCharacter(new Point(0, 0)); + BattleCharacter p1 = new BattleCharacter(14, "Leslie", 7, 8, false, + new Move(-2000, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p2 = new BattleCharacter(9, "Mariam", 6, 11, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p3 = new BattleCharacter(10, "Michael", 10, 10, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p4 = new BattleCharacter(6, "Alex", 12, 14, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + + BattleCharacter[] party = {p1, p2, p3, p4}; + + GameState state = new GameState(inventory, party, character); + BattleInteractor interactor = new BattleInteractor(state); + BattlePresenter presenter = new BattlePresenter(interactor); + presenter.startBattle(); + + presenter.executeTurn(1, "Leslie", "Opponent 0"); + Assertions.assertTrue(presenter.givenCharacterFainted("Opponent 0")); + } + + @Test + void startRoundProperly() { + Inventory inventory = new Inventory(); + WalkingCharacter character = new WalkingCharacter(new Point(0, 0)); + BattleCharacter p1 = new BattleCharacter(14, "Leslie", 7, 2000, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p2 = new BattleCharacter(9, "Mariam", 6, 11, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p3 = new BattleCharacter(10, "Michael", 10, 10, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + BattleCharacter p4 = new BattleCharacter(6, "Alex", 12, 14, false, + new Move(-5, 0, "first", false), + new Move(0, 1, "second",true)); + + BattleCharacter[] party = {p1, p2, p3, p4}; + + GameState state = new GameState(inventory, party, character); + BattleInteractor interactor = new BattleInteractor(state); + BattlePresenter presenter = new BattlePresenter(interactor); + presenter.startBattle(); + + Assertions.assertEquals("Leslie", presenter.roundStart()); + } +} From f9d865c387b69852baf5338a4d52b790d40d56c7 Mon Sep 17 00:00:00 2001 From: Theodore Date: Tue, 29 Nov 2022 14:01:30 -0500 Subject: [PATCH 14/22] Fix IDEA warning in MapDrawer --- .../java/com/mg105/user_interface/MapDrawer.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/mg105/user_interface/MapDrawer.java b/src/main/java/com/mg105/user_interface/MapDrawer.java index 2bb30599..61d7592e 100644 --- a/src/main/java/com/mg105/user_interface/MapDrawer.java +++ b/src/main/java/com/mg105/user_interface/MapDrawer.java @@ -12,6 +12,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Objects; /** * MapDrawer draws the map as a grid of tiles. @@ -42,12 +43,12 @@ public MapDrawer(@NotNull RoomInterpreter interpreter) { isVisible = false; tiles = new HashMap<>(6); - tiles.put(TileType.FLOOR, new Image(RoomUpdater.class.getResourceAsStream("/tiles/floor.png"))); - tiles.put(TileType.WALL, new Image(RoomUpdater.class.getResourceAsStream("/tiles/wall.png"))); - tiles.put(TileType.EXIT, new Image(RoomUpdater.class.getResourceAsStream("/tiles/exit.png"))); - tiles.put(TileType.CHEST, new Image(RoomUpdater.class.getResourceAsStream("/tiles/chest.png"))); - tiles.put(TileType.PLAYER, new Image(RoomUpdater.class.getResourceAsStream("/tiles/player.png"))); - tiles.put(TileType.OPPONENT_SET, new Image(RoomUpdater.class.getResourceAsStream("/tiles/battle.png"))); + tiles.put(TileType.FLOOR, new Image(Objects.requireNonNull(RoomUpdater.class.getResourceAsStream("/tiles/floor.png")))); + tiles.put(TileType.WALL, new Image(Objects.requireNonNull(RoomUpdater.class.getResourceAsStream("/tiles/wall.png")))); + tiles.put(TileType.EXIT, new Image(Objects.requireNonNull(RoomUpdater.class.getResourceAsStream("/tiles/exit.png")))); + tiles.put(TileType.CHEST, new Image(Objects.requireNonNull(RoomUpdater.class.getResourceAsStream("/tiles/chest.png")))); + tiles.put(TileType.PLAYER, new Image(Objects.requireNonNull(RoomUpdater.class.getResourceAsStream("/tiles/player.png")))); + tiles.put(TileType.OPPONENT_SET, new Image(Objects.requireNonNull(RoomUpdater.class.getResourceAsStream("/tiles/battle.png")))); // While in theory getResourceAsStream can fail, in practice this will never happen because the images are // bundled in the Jar. If this isn't the case then the nullpointerexception is the least of your worries. } From 62b47352bac8aed0db7077e376eb818591d21fda Mon Sep 17 00:00:00 2001 From: Theodore Date: Tue, 29 Nov 2022 14:20:02 -0500 Subject: [PATCH 15/22] Add missing Javadoc in map-related classes --- src/main/java/com/mg105/entities/Doorway.java | 3 +++ src/main/java/com/mg105/entities/GameState.java | 7 +++++++ src/main/java/com/mg105/entities/OpponentSet.java | 3 +++ src/main/java/com/mg105/entities/Room.java | 9 ++++++--- .../com/mg105/interface_adapters/InputInterpreter.java | 3 ++- src/main/java/com/mg105/use_cases/RoomLayout.java | 1 + 6 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/mg105/entities/Doorway.java b/src/main/java/com/mg105/entities/Doorway.java index ce34ca1d..52b88e47 100644 --- a/src/main/java/com/mg105/entities/Doorway.java +++ b/src/main/java/com/mg105/entities/Doorway.java @@ -2,6 +2,9 @@ import java.awt.*; +/** + * A Doorway represents a single-direction connection from one room to another. + */ public class Doorway { private final Point position; private final Room nextRoom; diff --git a/src/main/java/com/mg105/entities/GameState.java b/src/main/java/com/mg105/entities/GameState.java index febc90ea..57963a96 100644 --- a/src/main/java/com/mg105/entities/GameState.java +++ b/src/main/java/com/mg105/entities/GameState.java @@ -23,6 +23,13 @@ public class GameState { //Potentially useless. Keeps track of party characters who faint in battle. private final ArrayList fainted = new ArrayList(); + /** + * Create a new game state. + * + * @param inventory the player's inventory. + * @param party the player's party. + * @param walkingCharacter the player's character data. + */ public GameState(Inventory inventory, BattleCharacter[] party, WalkingCharacter walkingCharacter) { this.inventory = inventory; this.party = new ArrayList(); diff --git a/src/main/java/com/mg105/entities/OpponentSet.java b/src/main/java/com/mg105/entities/OpponentSet.java index a069f6ae..c7527ca5 100644 --- a/src/main/java/com/mg105/entities/OpponentSet.java +++ b/src/main/java/com/mg105/entities/OpponentSet.java @@ -3,6 +3,9 @@ import java.awt.*; import java.util.List; +/** + * OpponentSet stores a potential battle on a map. + */ public class OpponentSet { private final Point position; private final List opponents; diff --git a/src/main/java/com/mg105/entities/Room.java b/src/main/java/com/mg105/entities/Room.java index 2b73e2c2..bea59672 100644 --- a/src/main/java/com/mg105/entities/Room.java +++ b/src/main/java/com/mg105/entities/Room.java @@ -5,6 +5,9 @@ import java.util.List; +/** + * Room represents a single room in the map. + */ public class Room { private final @NotNull List chests; private final @NotNull List opponents; @@ -28,7 +31,7 @@ public Room(@NotNull List chests, @NotNull List oppo * * @return the treasure chests in this room. */ - public List getChests() { + public @NotNull List getChests() { return chests; } @@ -37,7 +40,7 @@ public List getChests() { * * @return the opponents in this room. */ - public List getOpponents() { + public @NotNull List getOpponents() { return opponents; } @@ -46,7 +49,7 @@ public List getOpponents() { * * @return the doorways in this room. */ - public List getDoorways() { + public @NotNull List getDoorways() { return doorways; } diff --git a/src/main/java/com/mg105/interface_adapters/InputInterpreter.java b/src/main/java/com/mg105/interface_adapters/InputInterpreter.java index d28a79d6..4b8f6e86 100644 --- a/src/main/java/com/mg105/interface_adapters/InputInterpreter.java +++ b/src/main/java/com/mg105/interface_adapters/InputInterpreter.java @@ -15,7 +15,8 @@ public class InputInterpreter { /** * Create a new InputInterpreter that translates keyboard inputs to appropriate function invocations. * - * @param mover the character mover. + * @param mover the character mover. + * @param toggler the toggler used to change the displayed interface. */ public InputInterpreter(@NotNull CharacterMover mover, @NotNull Toggler toggler) { this.mover = mover; diff --git a/src/main/java/com/mg105/use_cases/RoomLayout.java b/src/main/java/com/mg105/use_cases/RoomLayout.java index c808476e..41bda5ed 100644 --- a/src/main/java/com/mg105/use_cases/RoomLayout.java +++ b/src/main/java/com/mg105/use_cases/RoomLayout.java @@ -22,6 +22,7 @@ public class RoomLayout { * @param chests the chests in this room. * @param opponents the opponents in this room. * @param doorways the doorways in this room leading to other rooms. + * @param player the player's position. */ public RoomLayout(@NotNull List chests, @NotNull List opponents, From 6cb8fe44ba6aca9dbde216e5752c3558c2eebe5c Mon Sep 17 00:00:00 2001 From: Theodore Date: Tue, 29 Nov 2022 20:22:43 -0500 Subject: [PATCH 16/22] Remove bad dependency overreach in MapDrawer --- .../java/com/mg105/interface_adapters/MapRoomDrawer.java | 9 +++++++++ src/main/java/com/mg105/user_interface/MapDrawer.java | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/mg105/interface_adapters/MapRoomDrawer.java diff --git a/src/main/java/com/mg105/interface_adapters/MapRoomDrawer.java b/src/main/java/com/mg105/interface_adapters/MapRoomDrawer.java new file mode 100644 index 00000000..fe5202e8 --- /dev/null +++ b/src/main/java/com/mg105/interface_adapters/MapRoomDrawer.java @@ -0,0 +1,9 @@ +package com.mg105.interface_adapters; + +import com.mg105.use_cases.RoomUpdater; + +/** + * Update a room. + */ +public interface MapRoomDrawer extends RoomUpdater { +} diff --git a/src/main/java/com/mg105/user_interface/MapDrawer.java b/src/main/java/com/mg105/user_interface/MapDrawer.java index 61d7592e..92a71033 100644 --- a/src/main/java/com/mg105/user_interface/MapDrawer.java +++ b/src/main/java/com/mg105/user_interface/MapDrawer.java @@ -1,5 +1,6 @@ package com.mg105.user_interface; +import com.mg105.interface_adapters.MapRoomDrawer; import com.mg105.interface_adapters.RoomInterpreter; import com.mg105.interface_adapters.TileType; import com.mg105.use_cases.RoomUpdater; @@ -17,7 +18,7 @@ /** * MapDrawer draws the map as a grid of tiles. */ -public class MapDrawer implements RoomUpdater, Toggleable { +public class MapDrawer implements MapRoomDrawer, Toggleable { private final @NotNull RoomInterpreter interpreter; private final @NotNull Scene scene; From 178cf6829ea8b20c182b6829d6f270158f7310ac Mon Sep 17 00:00:00 2001 From: Theodore Date: Tue, 29 Nov 2022 21:04:13 -0500 Subject: [PATCH 17/22] Switch room updating subsystem to use the new (Java 9+) observer pattern. --- src/main/java/com/mg105/Application.java | 6 ++- .../interface_adapters/MapRoomDrawer.java | 9 ---- .../java/com/mg105/use_cases/RoomUpdater.java | 44 ++++++++++++++++--- .../com/mg105/user_interface/MapDrawer.java | 29 ++++++++---- 4 files changed, 65 insertions(+), 23 deletions(-) delete mode 100644 src/main/java/com/mg105/interface_adapters/MapRoomDrawer.java diff --git a/src/main/java/com/mg105/Application.java b/src/main/java/com/mg105/Application.java index 01adc11e..681d6a6c 100644 --- a/src/main/java/com/mg105/Application.java +++ b/src/main/java/com/mg105/Application.java @@ -11,6 +11,7 @@ import com.mg105.use_cases.Inventory.InventoryInteractor; import com.mg105.use_cases.MapGenerator; import com.mg105.use_cases.RoomGetter; +import com.mg105.use_cases.RoomUpdater; import com.mg105.user_interface.*; import com.mg105.user_interface.inventory.InventoryDisplay; import javafx.animation.AnimationTimer; @@ -85,7 +86,10 @@ public void start(Stage primaryStage) { drawableComponents.put(Toggler.ToggleableComponent.MAIN_MENU, mainMenu); drawableComponents.put(Toggler.ToggleableComponent.MAP, mapDrawer); - CharacterMover characterMover = new CharacterMover(state, mapDrawer); + RoomUpdater roomUpdater = new RoomUpdater(); + roomUpdater.addObserver(mapDrawer); + + CharacterMover characterMover = new CharacterMover(state, roomUpdater); InputInterpreter inputInterpreter = new InputInterpreter(characterMover, sceneController); InputListener inputListener = new InputListener(inputInterpreter); primaryStage.addEventFilter(KeyEvent.KEY_TYPED, inputListener); diff --git a/src/main/java/com/mg105/interface_adapters/MapRoomDrawer.java b/src/main/java/com/mg105/interface_adapters/MapRoomDrawer.java deleted file mode 100644 index fe5202e8..00000000 --- a/src/main/java/com/mg105/interface_adapters/MapRoomDrawer.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.mg105.interface_adapters; - -import com.mg105.use_cases.RoomUpdater; - -/** - * Update a room. - */ -public interface MapRoomDrawer extends RoomUpdater { -} diff --git a/src/main/java/com/mg105/use_cases/RoomUpdater.java b/src/main/java/com/mg105/use_cases/RoomUpdater.java index 3174b4fd..d5a2f5af 100644 --- a/src/main/java/com/mg105/use_cases/RoomUpdater.java +++ b/src/main/java/com/mg105/use_cases/RoomUpdater.java @@ -1,13 +1,47 @@ package com.mg105.use_cases; +import org.jetbrains.annotations.NotNull; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + /** - * RoomUpdater interface defines an object that needs to be told when the room updates. + * RoomUpdater updates any components that need updating when the state of the current room changes. + *

+ * One example of a component that might need updating is the GUI. */ -public interface RoomUpdater { +public class RoomUpdater { + private final @NotNull PropertyChangeSupport observable; + + /** + * Create a new RoomUpdater. + */ + public RoomUpdater() { + observable = new PropertyChangeSupport(this); + } + + /** + * Trigger an update on all the components that need updating on a room state change. + */ + public void updateRoom() { + observable.firePropertyChange("", null, null); + } + + /** + * Add a new observer to the RoomUpdater. + * + * @param observer an observer that requires notification of room changes. + */ + public void addObserver(@NotNull PropertyChangeListener observer) { + observable.addPropertyChangeListener(observer); + } + /** - * Update the current visual representation of the room. + * Remove an observer from the RoomUpdater. * - * It only needs to be called on changes to the underlying room. + * @param observer an observer that no longer requires notification of room changes. */ - void updateRoom(); + public void removeObserver(@NotNull PropertyChangeListener observer) { + observable.removePropertyChangeListener(observer); + } } diff --git a/src/main/java/com/mg105/user_interface/MapDrawer.java b/src/main/java/com/mg105/user_interface/MapDrawer.java index 92a71033..1f6e4fab 100644 --- a/src/main/java/com/mg105/user_interface/MapDrawer.java +++ b/src/main/java/com/mg105/user_interface/MapDrawer.java @@ -1,6 +1,5 @@ package com.mg105.user_interface; -import com.mg105.interface_adapters.MapRoomDrawer; import com.mg105.interface_adapters.RoomInterpreter; import com.mg105.interface_adapters.TileType; import com.mg105.use_cases.RoomUpdater; @@ -11,6 +10,8 @@ import javafx.scene.image.ImageView; import org.jetbrains.annotations.NotNull; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -18,7 +19,7 @@ /** * MapDrawer draws the map as a grid of tiles. */ -public class MapDrawer implements MapRoomDrawer, Toggleable { +public class MapDrawer implements PropertyChangeListener, Toggleable { private final @NotNull RoomInterpreter interpreter; private final @NotNull Scene scene; @@ -82,13 +83,7 @@ public void toggle(boolean isVisible) { * Redraw the current room. This method only needs to be called if something has changed in the underlying * current room. */ - @Override public void updateRoom() { - if (!isVisible) { - // As per the specification of Toggleable, we do nothing if we are not visible. - return; - } - TileType[][] room = interpreter.getCurrentRoom(); group.getChildren().clear(); @@ -107,4 +102,22 @@ public void updateRoom() { } } } + + /** + * Update the current room based on evt. + *

+ * Note that none of the properties of evt are used. + * + * @param evt A PropertyChangeEvent object describing the event source + * and the property that has changed. + */ + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (!isVisible) { + // As per the specification of Toggleable, we do nothing if we are not visible. + return; + } + + updateRoom(); + } } From d342550b2cb135799b9f37f858ee78da83f09c95 Mon Sep 17 00:00:00 2001 From: zhaoan12 Date: Tue, 29 Nov 2022 22:24:48 -0500 Subject: [PATCH 18/22] Fixed testing issues for tutorial and fixed bug that did not correctly do the scenes. Fixed import statement containing class that does not exist yet. --- .../com/mg105/use_cases/Inventory/InventoryInteractorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java b/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java index 0290ab3a..c48cb624 100644 --- a/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java +++ b/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java @@ -4,7 +4,7 @@ import com.mg105.entities.items.HealthPotion; import com.mg105.entities.items.UpgradeToken; import com.mg105.outputds.ItemDetails; -import com.mg105.presenter_interfaces.InventoryPresenterInterface; +//import com.mg105.presenter_interfaces.InventoryPresenterInterface; import com.mg105.utils.ItemConstants; import org.junit.jupiter.api.Test; From f4b33880dd8898145d65df0627db579851d660e4 Mon Sep 17 00:00:00 2001 From: zhaoan12 Date: Tue, 29 Nov 2022 22:59:03 -0500 Subject: [PATCH 19/22] Fixed testing issues for tutorial and fixed bug that did not correctly do the scenes. Fixed import statement containing class that does not exist yet. --- .../mg105/controllers/TutorialTextController.java | 12 +++++++++--- .../mg105/interface_adapters/InputInterpreter.java | 2 ++ .../java/com/mg105/use_cases/PlayerGetsTutorial.java | 7 +++++++ .../use_cases/Inventory/InventoryInteractorTest.java | 1 - 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/mg105/controllers/TutorialTextController.java b/src/main/java/com/mg105/controllers/TutorialTextController.java index 09528585..3d90c2bc 100644 --- a/src/main/java/com/mg105/controllers/TutorialTextController.java +++ b/src/main/java/com/mg105/controllers/TutorialTextController.java @@ -29,19 +29,23 @@ public String bottomText() { public void nextPhase() { this.tutorial.nextPhase(); } /** - * Return if text should start changing + * Make text start changing */ public void setChangeText() { this.changeText = !this.changeText; } /** - * Return if text should start changing + * Check if tutorial phases should advance + * + * @return if text should start changing */ public boolean changeText() { return this.changeText; } /** - * Tell player the controls again if they forgot + * Tell player the controls again + * + * @param show the text on the screen when true */ public void setShowControls(boolean show) { this.showControls = show; @@ -49,6 +53,8 @@ public void setShowControls(boolean show) { /** * Check if player should be shown controls again + * + * @return whether player should be shown the control texts */ public boolean getShowControls() { return this.showControls; } diff --git a/src/main/java/com/mg105/interface_adapters/InputInterpreter.java b/src/main/java/com/mg105/interface_adapters/InputInterpreter.java index 7f401028..7c188d85 100644 --- a/src/main/java/com/mg105/interface_adapters/InputInterpreter.java +++ b/src/main/java/com/mg105/interface_adapters/InputInterpreter.java @@ -20,6 +20,8 @@ public class InputInterpreter { * Create a new InputInterpreter that translates keyboard inputs to appropriate function invocations. * * @param mover the character mover. + * @param toggler the scene toggler + * @param textChanger the text controller for tutorial */ public InputInterpreter(@NotNull CharacterMover mover, @NotNull Toggler toggler, @NotNull TutorialTextController textChanger) { diff --git a/src/main/java/com/mg105/use_cases/PlayerGetsTutorial.java b/src/main/java/com/mg105/use_cases/PlayerGetsTutorial.java index 8af1c2a5..9cd11aff 100644 --- a/src/main/java/com/mg105/use_cases/PlayerGetsTutorial.java +++ b/src/main/java/com/mg105/use_cases/PlayerGetsTutorial.java @@ -53,6 +53,11 @@ public void nextPhase() { } } + /** + * Set the action to true if it has been performed + * + * @param action to set to performed + */ public void setActionPerformed(String action) { this.tutorial.ActionPerformedSetter(action); } @@ -61,6 +66,8 @@ public void setActionPerformed(String action) { * Check if specific action has been performed * * @param action get if it has been performed yet + * + * @return if the action has been performed */ public boolean getActionPerformed(String action) { return this.tutorial.ActionPerformedGetter(action); diff --git a/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java b/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java index c48cb624..83a1a9eb 100644 --- a/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java +++ b/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java @@ -4,7 +4,6 @@ import com.mg105.entities.items.HealthPotion; import com.mg105.entities.items.UpgradeToken; import com.mg105.outputds.ItemDetails; -//import com.mg105.presenter_interfaces.InventoryPresenterInterface; import com.mg105.utils.ItemConstants; import org.junit.jupiter.api.Test; From 5efd30982dc14ac366c3ea09bae45b2ecdb9a260 Mon Sep 17 00:00:00 2001 From: m-grigoriu Date: Wed, 30 Nov 2022 10:40:23 -0500 Subject: [PATCH 20/22] - Added WalkingMenu, WalkVisController. - Updated Unit test classes, updated BattlePresenter and BattleInteractor to reflect updates. --- .../interface_adapters/BattlePresenter.java | 8 -- .../interface_adapters/WalkVisController.java | 13 +++ .../com/mg105/use_cases/BattleInteractor.java | 7 +- .../com/mg105/user_interface/WalkingMenu.java | 103 ++++++++++++++++++ .../BattlePresenterTest.java | 16 +++ .../Battle/BattleInteractorTest.java | 18 +++ 6 files changed, 151 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/mg105/interface_adapters/WalkVisController.java create mode 100644 src/main/java/com/mg105/user_interface/WalkingMenu.java diff --git a/src/main/java/com/mg105/interface_adapters/BattlePresenter.java b/src/main/java/com/mg105/interface_adapters/BattlePresenter.java index 66704e73..fe5dd3c0 100644 --- a/src/main/java/com/mg105/interface_adapters/BattlePresenter.java +++ b/src/main/java/com/mg105/interface_adapters/BattlePresenter.java @@ -126,10 +126,6 @@ public void executeTurn(int moveNum, String casterName, String targetName) { */ @Override public void setViewNames(String[] partyNames, String[] opponentNames) { - if (this.view == null) { //Used for unit tests. Never executed during regular running of the application. - return; - } - this.view.setNames(partyNames, opponentNames); } @@ -139,10 +135,6 @@ public void setViewNames(String[] partyNames, String[] opponentNames) { */ @Override public void updateViewCharacter(String targetName) { - if (this.view == null) { //Used for unit tests. Never executed during regular running of the application. - return; - } - this.view.updateCharacter(targetName); } diff --git a/src/main/java/com/mg105/interface_adapters/WalkVisController.java b/src/main/java/com/mg105/interface_adapters/WalkVisController.java new file mode 100644 index 00000000..3ba0648b --- /dev/null +++ b/src/main/java/com/mg105/interface_adapters/WalkVisController.java @@ -0,0 +1,13 @@ +package com.mg105.interface_adapters; + +import com.mg105.use_cases.RoomUpdater; + +public class WalkVisController { + + + public WalkVisController() { + } + + public void changePlayerSprite(String spriteName) { + } +} diff --git a/src/main/java/com/mg105/use_cases/BattleInteractor.java b/src/main/java/com/mg105/use_cases/BattleInteractor.java index 37eae3ae..24e1d7a7 100644 --- a/src/main/java/com/mg105/use_cases/BattleInteractor.java +++ b/src/main/java/com/mg105/use_cases/BattleInteractor.java @@ -36,6 +36,7 @@ public void setPresenter(BattlePresenterInterface presenter) { /** * Creates a new encounter with random opponents and sets it as the current encounter in GameState + * Could use the Builder design pattern here. */ public void createEncounter() { Random rand = new Random(); @@ -68,9 +69,6 @@ public void createEncounter() { opponentNames[i] = opponents.get(i).getName(); } - if (this.presenter == null) { //Used for unit tests. Never executed during regular running of the application. - return; - } presenter.setViewNames(partyNames, opponentNames); } @@ -270,9 +268,6 @@ private void _useMove(Move m, BattleCharacter caster, BattleCharacter target) { target.modifyDamage(m.getDamageChange()); - if (this.presenter == null) { //Used for unit tests. Never executed during regular running of the application. - return; - } presenter.updateViewCharacter(target.getName()); } diff --git a/src/main/java/com/mg105/user_interface/WalkingMenu.java b/src/main/java/com/mg105/user_interface/WalkingMenu.java new file mode 100644 index 00000000..ea4f67b6 --- /dev/null +++ b/src/main/java/com/mg105/user_interface/WalkingMenu.java @@ -0,0 +1,103 @@ +package com.mg105.user_interface; + +import com.mg105.interface_adapters.WalkVisController; +import com.mg105.utils.PartyConstants; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.geometry.Pos; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.RadioButton; +import javafx.scene.control.ToggleGroup; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; +import org.jetbrains.annotations.NotNull; + +public class WalkingMenu implements EventHandler, Toggleable { + private final WalkVisController controller; + private final RadioButton radA; + private final RadioButton radB; + private final RadioButton radC; + private final RadioButton radD; + private final Button select; + private final Scene scene; + + public WalkingMenu(WalkVisController controller) { + this.controller = controller; + + StackPane layout = new StackPane(); + + ToggleGroup group = new ToggleGroup(); + + VBox buttons = new VBox(); + + radA = new RadioButton(PartyConstants.ALL_PARTY_MEMBER_NAMES[0]); + radA.setToggleGroup(group); + radA.setSelected(true); + + radB = new RadioButton(PartyConstants.ALL_PARTY_MEMBER_NAMES[1]); + radB.setToggleGroup(group); + radB.setSelected(false); + + radC = new RadioButton(PartyConstants.ALL_PARTY_MEMBER_NAMES[2]); + radC.setToggleGroup(group); + radC.setSelected(false); + + radD = new RadioButton(PartyConstants.ALL_PARTY_MEMBER_NAMES[3]); + radD.setToggleGroup(group); + radD.setSelected(false); + + select = new Button("Confirm"); + select.setOnAction(this); + buttons.getChildren().addAll(radA, radB, radC, radD, select); + buttons.setAlignment(Pos.CENTER); + layout.getChildren().addAll(buttons); + + scene = new Scene(layout, 300, 300); + } + + @Override + public void handle(ActionEvent event) { + Object source = event.getSource(); + if (source.equals(select)) { + if (radA.isSelected()) { + controller.changePlayerSprite("A"); + } else if (radB.isSelected()) { + controller.changePlayerSprite("B"); + } else if (radC.isSelected()) { + controller.changePlayerSprite("C"); + } else if (radD.isSelected()) { + controller.changePlayerSprite("D"); + } + } + + ((Stage) ((Button) source).getScene().getWindow()).close(); + } + + /** + * Get the scene of this toggleable object. It is this scene that will be displayed. + * + * @return the scene to be displayed. + */ + @Override + public @NotNull Scene getScene() { + return this.scene; + } + + /** + * Set the visibility of this component. + * + * @param isVisible true if the Toggleable is now visible, false otherwise. If false the Toggleable is expected + * to do nothing on ANY user inputs. + */ + @Override + public void toggle(boolean isVisible) { + if (isVisible) { + radA.setSelected(true); + radB.setSelected(false); + radC.setSelected(false); + radD.setSelected(false); + } + } +} diff --git a/src/test/java/com/mg105/interface_adapters/BattlePresenterTest.java b/src/test/java/com/mg105/interface_adapters/BattlePresenterTest.java index 031e4d29..0f3713be 100644 --- a/src/test/java/com/mg105/interface_adapters/BattlePresenterTest.java +++ b/src/test/java/com/mg105/interface_adapters/BattlePresenterTest.java @@ -9,6 +9,18 @@ import java.util.ArrayList; class BattlePresenterTest { + + BattleMenuInterface view = new BattleMenuInterface() { + @Override + public void setNames(String[] playerNames, String[] opponentNames) { + + } + + @Override + public void updateCharacter(String character) { + + } + }; @Test void startValidBattle() { Inventory inventory = new Inventory(); @@ -31,6 +43,7 @@ void startValidBattle() { GameState state = new GameState(inventory, party, character); BattleInteractor interactor = new BattleInteractor(state); BattlePresenter presenter = new BattlePresenter(interactor); + presenter.setView(view); presenter.startBattle(); Assertions.assertEquals(4, presenter.retrieveTargets(1, "Leslie").size()); @@ -60,6 +73,7 @@ void executeMoveSuccess() { GameState state = new GameState(inventory, party, character); BattleInteractor interactor = new BattleInteractor(state); BattlePresenter presenter = new BattlePresenter(interactor); + presenter.setView(view); presenter.startBattle(); ArrayList targets = presenter.retrieveTargets(1, "Leslie"); @@ -93,6 +107,7 @@ void findFaintedCharacter() { GameState state = new GameState(inventory, party, character); BattleInteractor interactor = new BattleInteractor(state); BattlePresenter presenter = new BattlePresenter(interactor); + presenter.setView(view); presenter.startBattle(); presenter.executeTurn(1, "Leslie", "Opponent 0"); @@ -121,6 +136,7 @@ void startRoundProperly() { GameState state = new GameState(inventory, party, character); BattleInteractor interactor = new BattleInteractor(state); BattlePresenter presenter = new BattlePresenter(interactor); + presenter.setView(view); presenter.startBattle(); Assertions.assertEquals("Leslie", presenter.roundStart()); diff --git a/src/test/java/com/mg105/use_cases/Battle/BattleInteractorTest.java b/src/test/java/com/mg105/use_cases/Battle/BattleInteractorTest.java index 2e4d3872..6accc4f8 100644 --- a/src/test/java/com/mg105/use_cases/Battle/BattleInteractorTest.java +++ b/src/test/java/com/mg105/use_cases/Battle/BattleInteractorTest.java @@ -1,7 +1,9 @@ package com.mg105.use_cases.Battle; import com.mg105.entities.*; +import com.mg105.interface_adapters.BattleMenuInterface; import com.mg105.use_cases.BattleInteractor; +import com.mg105.use_cases.BattlePresenterInterface; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -10,6 +12,18 @@ class BattleInteractorTest { + BattlePresenterInterface presenter = new BattlePresenterInterface() { + @Override + public void setViewNames(String[] partyNames, String[] opponentNames) { + + } + + @Override + public void updateViewCharacter(String targetName) { + + } + }; + @Test void createValidEncounter() { Inventory inventory = new Inventory(); @@ -31,6 +45,7 @@ void createValidEncounter() { GameState state = new GameState(inventory, party, character); BattleInteractor interactor = new BattleInteractor(state); + interactor.setPresenter(presenter); interactor.createEncounter(); Assertions.assertEquals(4, interactor.retrieveTargets(1, "Leslie").size()); @@ -59,6 +74,7 @@ void executeMoveSuccess() { GameState state = new GameState(inventory, party, character); BattleInteractor interactor = new BattleInteractor(state); + interactor.setPresenter(presenter); interactor.createEncounter(); ArrayList targets = interactor.retrieveTargets(1, "Leslie"); @@ -91,6 +107,7 @@ void findFaintedCharacter() { GameState state = new GameState(inventory, party, character); BattleInteractor interactor = new BattleInteractor(state); + interactor.setPresenter(presenter); interactor.createEncounter(); interactor.executeTurn(1, "Leslie", "Opponent 0"); @@ -118,6 +135,7 @@ void startRoundProperly() { GameState state = new GameState(inventory, party, character); BattleInteractor interactor = new BattleInteractor(state); + interactor.setPresenter(presenter); interactor.createEncounter(); Assertions.assertEquals("Leslie", interactor.roundStart()); From c24a638ab31e181ed6eab39c1098c3f896095b30 Mon Sep 17 00:00:00 2001 From: m-grigoriu Date: Wed, 30 Nov 2022 17:14:19 -0500 Subject: [PATCH 21/22] Completed an implementation of WalkingMenu and associated classes: - Finished WalkingMenu, WalkVisController, added WalkVisInteractor. - Added a sprite attribute to WalkingCharacter, along with setter and getter methods for the attribute. By default, sprite associated with character "A". - Added four character sprites, filed under /resources/sprites. - Changed Application.java to use the party name constants. - Gave party members names. - Added code to MapDrawer.toggle to display the desired character sprite. - Added sprite retrieval methods to RoomGetter, RoomInterpreter. - Minor changes to BattleMenu. --- src/main/java/com/mg105/Application.java | 17 +++++---- .../com/mg105/entities/WalkingCharacter.java | 20 +++++++++- .../interface_adapters/RoomInterpreter.java | 8 ++++ .../interface_adapters/WalkVisController.java | 15 +++++++- .../com/mg105/use_cases/BattleInteractor.java | 35 ++++++++---------- .../java/com/mg105/use_cases/RoomGetter.java | 8 ++++ .../mg105/use_cases/WalkVisInteractor.java | 25 +++++++++++++ .../com/mg105/user_interface/BattleMenu.java | 4 +- .../com/mg105/user_interface/MapDrawer.java | 7 +++- .../com/mg105/user_interface/WalkingMenu.java | 3 ++ .../java/com/mg105/utils/PartyConstants.java | 2 +- src/main/resources/sprites/A.png | Bin 0 -> 436 bytes src/main/resources/sprites/B.png | Bin 0 -> 551 bytes src/main/resources/sprites/C.png | Bin 0 -> 449 bytes src/main/resources/sprites/D.png | Bin 0 -> 415 bytes 15 files changed, 110 insertions(+), 34 deletions(-) create mode 100644 src/main/java/com/mg105/use_cases/WalkVisInteractor.java create mode 100644 src/main/resources/sprites/A.png create mode 100644 src/main/resources/sprites/B.png create mode 100644 src/main/resources/sprites/C.png create mode 100644 src/main/resources/sprites/D.png diff --git a/src/main/java/com/mg105/Application.java b/src/main/java/com/mg105/Application.java index 681d6a6c..723ff2c7 100644 --- a/src/main/java/com/mg105/Application.java +++ b/src/main/java/com/mg105/Application.java @@ -14,6 +14,7 @@ import com.mg105.use_cases.RoomUpdater; import com.mg105.user_interface.*; import com.mg105.user_interface.inventory.InventoryDisplay; +import com.mg105.utils.PartyConstants; import javafx.animation.AnimationTimer; import javafx.scene.control.Label; import javafx.scene.input.KeyEvent; @@ -41,20 +42,20 @@ public void start(Stage primaryStage) { // Set up the initial use cases - BattleCharacter a = new BattleCharacter(30, "A", 4, 5, false, - new Move(-3, 0, "Slow swing", false), + BattleCharacter a = new BattleCharacter(30, PartyConstants.ALL_PARTY_MEMBER_NAMES[0], 4, 5, + false, new Move(-3, 0, "Slow swing", false), new Move(0, -1, "Nullify", false)); - BattleCharacter b = new BattleCharacter(20, "B", 6, 8, false, - new Move(-4, 0, "Strong swing", false), + BattleCharacter b = new BattleCharacter(20, PartyConstants.ALL_PARTY_MEMBER_NAMES[1], 6, 8, + false, new Move(-4, 0, "Strong swing", false), new Move(3, 0, "Weak heal", true)); - BattleCharacter c = new BattleCharacter(25, "C", 3, 6, false, - new Move(6, 0, "Strong heal", true), + BattleCharacter c = new BattleCharacter(25, PartyConstants.ALL_PARTY_MEMBER_NAMES[2], 3, 6, + false, new Move(6, 0, "Strong heal", true), new Move(2, 2, "Reinforce", true)); - BattleCharacter d = new BattleCharacter(15, "D", 9, 10, false, - new Move(-5, 0, "Surprise attack", false), + BattleCharacter d = new BattleCharacter(15, PartyConstants.ALL_PARTY_MEMBER_NAMES[3], 9, 10, + false, new Move(-5, 0, "Surprise attack", false), new Move(-2, -2, "Sabotage", false)); BattleCharacter[] party = {a, b, c, d}; diff --git a/src/main/java/com/mg105/entities/WalkingCharacter.java b/src/main/java/com/mg105/entities/WalkingCharacter.java index 4926a5af..caa433e3 100644 --- a/src/main/java/com/mg105/entities/WalkingCharacter.java +++ b/src/main/java/com/mg105/entities/WalkingCharacter.java @@ -3,10 +3,12 @@ import java.awt.*; public class WalkingCharacter { - public Point charPosition; + private Point charPosition; + private String spriteName; public WalkingCharacter(Point position) { this.charPosition = position; + this.spriteName = "A"; } /** @@ -22,5 +24,21 @@ public void setCharPosition(Point position) { public Point getCharPosition() { return this.charPosition; } + + /** + * Returns the name of the character whose sprite is currently being used. + * @return a sprite name String. + */ + public String getSpriteName() { + return spriteName; + } + + /** + * Sets the name of the character whose sprite is currently being used. + * @param spriteName name of the character to change the sprite to. + */ + public void setSpriteName(String spriteName) { + this.spriteName = spriteName; + } } diff --git a/src/main/java/com/mg105/interface_adapters/RoomInterpreter.java b/src/main/java/com/mg105/interface_adapters/RoomInterpreter.java index 2679ab8d..81fdd5bf 100644 --- a/src/main/java/com/mg105/interface_adapters/RoomInterpreter.java +++ b/src/main/java/com/mg105/interface_adapters/RoomInterpreter.java @@ -63,4 +63,12 @@ public TileType[][] getCurrentRoom() { return canvas; } + + /** + * Retrieves the sprite String currently associated with the WalkingCharacter. + * @return a file name/location as a String for the desired character sprite. + */ + public String updateCharacterSprite() { + return this.getter.getWalkingSprite(); + } } diff --git a/src/main/java/com/mg105/interface_adapters/WalkVisController.java b/src/main/java/com/mg105/interface_adapters/WalkVisController.java index 3ba0648b..b9c95539 100644 --- a/src/main/java/com/mg105/interface_adapters/WalkVisController.java +++ b/src/main/java/com/mg105/interface_adapters/WalkVisController.java @@ -1,13 +1,24 @@ package com.mg105.interface_adapters; -import com.mg105.use_cases.RoomUpdater; +import com.mg105.use_cases.WalkVisInteractor; +/** + * This class communicates with WalkVisInteractor, called on by WalkingMenu. + * There is no presenter class. When this class is called on, WalkingMenu is closed. + */ public class WalkVisController { + private final WalkVisInteractor interactor; - public WalkVisController() { + public WalkVisController(WalkVisInteractor interactor) { + this.interactor = interactor; } + /** + * Calls on WalkVisInteractor to update the walking character sprite. + * @param spriteName the name of the desired character sprite. + */ public void changePlayerSprite(String spriteName) { + interactor.setWalkingSprite(spriteName); } } diff --git a/src/main/java/com/mg105/use_cases/BattleInteractor.java b/src/main/java/com/mg105/use_cases/BattleInteractor.java index 24e1d7a7..1416020f 100644 --- a/src/main/java/com/mg105/use_cases/BattleInteractor.java +++ b/src/main/java/com/mg105/use_cases/BattleInteractor.java @@ -16,13 +16,11 @@ public class BattleInteractor { private final GameState state; - private Battle encounter; private BattlePresenterInterface presenter; public BattleInteractor(GameState state) { this.state = state; - this.encounter = state.getCurrEncounter(); } /** @@ -56,7 +54,6 @@ public void createEncounter() { ArrayList party = this.state.getParty(); Battle b = new Battle(opponents, party); this.state.setCurrEncounter(b); - this.encounter = b; String[] partyNames = new String[party.size()]; String[] opponentNames = new String[opponents.size()]; @@ -80,13 +77,13 @@ public void createEncounter() { * @return whether the given name corresponds to a fainted character. */ public boolean isCharacterFainted(String name) { - for (BattleCharacter c : encounter.getPlayerCharacters()) { + for (BattleCharacter c : state.getCurrEncounter().getPlayerCharacters()) { if (c.getName().equals(name)) { return false; } } - for (BattleCharacter c : encounter.getOpponents()) { + for (BattleCharacter c : state.getCurrEncounter().getOpponents()) { if (c.getName().equals(name)) { return false; } @@ -101,7 +98,7 @@ public boolean isCharacterFainted(String name) { * @return the desired BattleCharacter's current health. */ public int getCharacterHealth(String name) { - return this.encounter.getCharacter(name).getHp(); + return state.getCurrEncounter().getCharacter(name).getHp(); } /** @@ -110,7 +107,7 @@ public int getCharacterHealth(String name) { * @return the desired BattleCharacter's current damage. */ public int getCharacterDamage(String name) { - return this.encounter.getCharacter(name).getDmg(); + return state.getCurrEncounter().getCharacter(name).getDmg(); } /** @@ -120,7 +117,7 @@ public int getCharacterDamage(String name) { * @return the desired BattleCharacter's move stats. */ public int[] getCharacterMoveStats(String name) { - BattleCharacter caster = this.encounter.getCharacter(name); + BattleCharacter caster = state.getCurrEncounter().getCharacter(name); return new int[] {caster.getMoveOne().getHealthChange(), caster.getMoveOne().getDamageChange(), caster.getMoveTwo().getHealthChange(), caster.getMoveTwo().getDamageChange()}; } @@ -132,7 +129,7 @@ public int[] getCharacterMoveStats(String name) { * @return the desired BattleCharacter's move names. */ public String[] getCharacterMoveNames(String name) { - BattleCharacter caster = this.encounter.getCharacter(name); + BattleCharacter caster = state.getCurrEncounter().getCharacter(name); return new String[] {caster.getMoveOne().getName(), caster.getMoveTwo().getName()}; } @@ -144,7 +141,7 @@ public String[] getCharacterMoveNames(String name) { * @return a String of the name of the moving character */ public String roundStart() { - int status = this.encounter.getBattleStatus(); + int status = state.getCurrEncounter().getBattleStatus(); if (status == -1) { //Player lost last round //Something with ReplayGenerator return null; @@ -152,7 +149,7 @@ public String roundStart() { this.endBattle(); return null; } else { //Battle is ongoing - BattleCharacter moving = this.encounter.getMovingCharacter(); + BattleCharacter moving = state.getCurrEncounter().getMovingCharacter(); if (moving.isOpponent()) { //Opponent character is moving Random rand = new Random(); @@ -166,14 +163,14 @@ public String roundStart() { } if (!chosenMove.isFriendly()) { - ArrayList players = this.encounter.getPlayerCharacters(); + ArrayList players = state.getCurrEncounter().getPlayerCharacters(); //Choose a random player character to attack int target = rand.nextInt(players.size()); this._useMove(chosenMove, moving, players.get(target)); } else { - ArrayList opponents = this.encounter.getOpponents(); + ArrayList opponents = state.getCurrEncounter().getOpponents(); //Choose a random opponent to use the friendly move on int target = rand.nextInt(opponents.size()); @@ -198,7 +195,7 @@ public String roundStart() { */ public ArrayList retrieveTargets(int moveNum, String casterName) { //Retrieve the moving BattleCharacter - BattleCharacter caster = this.encounter.getCharacter(casterName); + BattleCharacter caster = state.getCurrEncounter().getCharacter(casterName); //Retrieve the Move being used Move m; @@ -214,9 +211,9 @@ public ArrayList retrieveTargets(int moveNum, String casterName) { //Retrieve possible target BattleCharacters if (m.isFriendly()) { //caster is a player character, so targets are player characters - targetCharacters = this.encounter.getPlayerCharacters(); + targetCharacters = state.getCurrEncounter().getPlayerCharacters(); } else { //caster is a player character, so targets are opponent characters - targetCharacters = this.encounter.getOpponents(); + targetCharacters = state.getCurrEncounter().getOpponents(); } //Add character names to ArrayList @@ -234,8 +231,8 @@ public ArrayList retrieveTargets(int moveNum, String casterName) { * @param targetName String representing the name of the target BattleCharacter. */ public void executeTurn(int moveNum, String casterName, String targetName) { - BattleCharacter caster = this.encounter.getCharacter(casterName); - BattleCharacter target = this.encounter.getCharacter(targetName); + BattleCharacter caster = state.getCurrEncounter().getCharacter(casterName); + BattleCharacter target = state.getCurrEncounter().getCharacter(targetName); if (moveNum == 1) { this._useMove(caster.getMoveOne(), caster, target); } else { //moveNum == 2 @@ -259,7 +256,7 @@ private void _useMove(Move m, BattleCharacter caster, BattleCharacter target) { } if (target.getHp() == 0) { - this.encounter.removeChar(target); + state.getCurrEncounter().removeChar(target); if (!target.isOpponent()) { this.state.getParty().remove(target); this.state.getFainted().add(target); diff --git a/src/main/java/com/mg105/use_cases/RoomGetter.java b/src/main/java/com/mg105/use_cases/RoomGetter.java index 6def1e7e..71e0478c 100644 --- a/src/main/java/com/mg105/use_cases/RoomGetter.java +++ b/src/main/java/com/mg105/use_cases/RoomGetter.java @@ -50,4 +50,12 @@ public RoomGetter(@NotNull GameState state) { return new RoomLayout(chests, opponents, doorways, state.getWalkingCharacter().getCharPosition()); } + + /** + * Retrieves the WalkingCharacter sprite name String, returns a file name/location corresponding to the name. + * @return a String representing the file name/location for the selected character sprite. + */ + public String getWalkingSprite() { + return "/sprites/" + state.getWalkingCharacter().getSpriteName() + ".png"; + } } diff --git a/src/main/java/com/mg105/use_cases/WalkVisInteractor.java b/src/main/java/com/mg105/use_cases/WalkVisInteractor.java new file mode 100644 index 00000000..04ab2f43 --- /dev/null +++ b/src/main/java/com/mg105/use_cases/WalkVisInteractor.java @@ -0,0 +1,25 @@ +package com.mg105.use_cases; + +import com.mg105.entities.GameState; + +/** + * This class interacts with the WalkingCharacter entity. + *

+ * It is responsible for modifying the sprite attribute of WalkingCharacter. + */ +public class WalkVisInteractor { + + private final GameState state; + + public WalkVisInteractor(GameState state) { + this.state = state; + } + + /** + * Updates the current WalkingCharacter's sprite attribute. + * @param spriteName the name of the desired character sprite to be used. + */ + public void setWalkingSprite(String spriteName) { + state.getWalkingCharacter().setSpriteName(spriteName); + } +} diff --git a/src/main/java/com/mg105/user_interface/BattleMenu.java b/src/main/java/com/mg105/user_interface/BattleMenu.java index 9e15d50e..c1e3608b 100644 --- a/src/main/java/com/mg105/user_interface/BattleMenu.java +++ b/src/main/java/com/mg105/user_interface/BattleMenu.java @@ -4,6 +4,7 @@ import com.mg105.interface_adapters.BattlePresenter; import javafx.event.ActionEvent; import javafx.event.EventHandler; +import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; @@ -63,6 +64,7 @@ public BattleMenu(BattlePresenter battlePres) { grid = new GridPane(); grid.setVgap(10); grid.setHgap(10); + grid.setAlignment(Pos.CENTER); nextRound = new Button("Next Round"); nextRound.setId("Next Round"); @@ -127,7 +129,7 @@ public BattleMenu(BattlePresenter battlePres) { moveTwo.setOnAction(this); moveTwo.setVisible(false); - scene = new Scene(grid, 800, 800); + scene = new Scene(grid, 600, 600); } /** diff --git a/src/main/java/com/mg105/user_interface/MapDrawer.java b/src/main/java/com/mg105/user_interface/MapDrawer.java index 1f6e4fab..4e37b63a 100644 --- a/src/main/java/com/mg105/user_interface/MapDrawer.java +++ b/src/main/java/com/mg105/user_interface/MapDrawer.java @@ -49,7 +49,7 @@ public MapDrawer(@NotNull RoomInterpreter interpreter) { tiles.put(TileType.WALL, new Image(Objects.requireNonNull(RoomUpdater.class.getResourceAsStream("/tiles/wall.png")))); tiles.put(TileType.EXIT, new Image(Objects.requireNonNull(RoomUpdater.class.getResourceAsStream("/tiles/exit.png")))); tiles.put(TileType.CHEST, new Image(Objects.requireNonNull(RoomUpdater.class.getResourceAsStream("/tiles/chest.png")))); - tiles.put(TileType.PLAYER, new Image(Objects.requireNonNull(RoomUpdater.class.getResourceAsStream("/tiles/player.png")))); + tiles.put(TileType.PLAYER, new Image(Objects.requireNonNull(RoomUpdater.class.getResourceAsStream("/sprites/A.png")))); tiles.put(TileType.OPPONENT_SET, new Image(Objects.requireNonNull(RoomUpdater.class.getResourceAsStream("/tiles/battle.png")))); // While in theory getResourceAsStream can fail, in practice this will never happen because the images are // bundled in the Jar. If this isn't the case then the nullpointerexception is the least of your worries. @@ -74,7 +74,10 @@ public MapDrawer(@NotNull RoomInterpreter interpreter) { public void toggle(boolean isVisible) { this.isVisible = isVisible; - if (isVisible) { + if (isVisible) { //Maybe four Image objects should be saved on a file somewhere else instead? + this.tiles.put(TileType.PLAYER, + new Image(Objects.requireNonNull(RoomUpdater.class.getResourceAsStream( + this.interpreter.updateCharacterSprite())))); updateRoom(); } } diff --git a/src/main/java/com/mg105/user_interface/WalkingMenu.java b/src/main/java/com/mg105/user_interface/WalkingMenu.java index ea4f67b6..1d9897a6 100644 --- a/src/main/java/com/mg105/user_interface/WalkingMenu.java +++ b/src/main/java/com/mg105/user_interface/WalkingMenu.java @@ -14,6 +14,9 @@ import javafx.stage.Stage; import org.jetbrains.annotations.NotNull; +/** + * This class uses JavaFX and is displayed when the user wants to change the walking character sprite. + */ public class WalkingMenu implements EventHandler, Toggleable { private final WalkVisController controller; private final RadioButton radA; diff --git a/src/main/java/com/mg105/utils/PartyConstants.java b/src/main/java/com/mg105/utils/PartyConstants.java index 9dbfb3cb..d23c2f03 100644 --- a/src/main/java/com/mg105/utils/PartyConstants.java +++ b/src/main/java/com/mg105/utils/PartyConstants.java @@ -3,5 +3,5 @@ public class PartyConstants { // Can Change Later (probably better to put this information in the csv) - public static String[] ALL_PARTY_MEMBER_NAMES = {"A", "B", "C", "D"}; + public static String[] ALL_PARTY_MEMBER_NAMES = {"Alan", "Beatrice", "Callum", "Diana"}; } diff --git a/src/main/resources/sprites/A.png b/src/main/resources/sprites/A.png new file mode 100644 index 0000000000000000000000000000000000000000..6c3a1ed6914e31f941379d4ccf104c14c74ad947 GIT binary patch literal 436 zcmV;l0ZaagP)Px$Zb?KzR9HvVmcb3eFbqZ8DOd;z3GPhL1-N#AURj_Ma0dyAg_t5JA&y+fN$jSj zf)f&n|Fiw=&^8-?+Ku&_zXUK$)n+H6z39ZRr(IyU+~4qB8_V6(UNTr5ls$wt)}I1o zT7az~u7>1bWIAXA^nV=3Al`MI$`d63lL#IS0&}huTjYTN0GVMSpg>uxvX@RlXaOgV zA&!TA^LW0baYYrdhYSQ(0Ei(9D=4Q03N_+GmqRvGY2rq9tX@# z2Cde)@0;5&xa%HN4nQ)3i@C=r^2;g!0EYSvri&(~3V`%6Q~(2{AfQcE0CwdvFP$qh z{SfDe1y%)sM564ypc_$U^d>8uY)r8Uxk(DyQvd?-GXR?ng$mV@JW!=YM61Awr2yO- zXWBT4xi&y%A%1^a1Ryc4Me*4HU_hTh)!%e=1yajtZWS~DrA&*4<9bp9pt+m$!y-XM eZc7~69N+`K9oHfAQ7V`K0000Px$;Ymb6R9HvFmak3&K@i5b0$+`&Bh7`B5RzhXNGwlKTpb1j0fVWlyRaBox9GS_^W^UQt**^ze)%I@p`^|hav+b!3ubxN0QA+uqb&Bi~0dZP?4&em2 z84T3rY6TFR0T41k_H<%XN)2#pcpVgFDa8Ta54b|gm(|?%Z4 zihyE=4^K@j0L}v|0|ubPif90bI2CJ5K;C-j8X#0xP6+X~(!1>I*xr})A0Rhn5=2zn p*)PRrfc9la>Z3~q$ci$w=?BHm%OUs&pMC%U002ovPDHLkV1lzf?xFwy literal 0 HcmV?d00001 diff --git a/src/main/resources/sprites/C.png b/src/main/resources/sprites/C.png new file mode 100644 index 0000000000000000000000000000000000000000..d506f3d95bdf6e87e03014ac1bbb682b4c9cabe1 GIT binary patch literal 449 zcmV;y0Y3hTP)Px$dr3q=R9Hvtm9bI+F%X7xHg>i)(m0enh1T>A@B-3c2aP>;(%=gKLvLk)PoW({ zgHON%u+AUZH5WK8n}fOLu7Szr{{P!QnS9qtgYM8tb>R& znySg}zBirrg8)pXb8VXPt%lZat=+kw0)Sd9L?}S2dKe-Bm=;YU7ywQ8^z&j~Z~Fco zCx(bgAs7HhD?i>5YXM@+HH~A>051W+7ph(buy>36Z#V9b&@@w0nvb%s-$K{21_0z) r)kdeF1vs!0#fBPx$SxH1eR9HvtmAwwaAQXjZ;yXAxIJ%hd22ET#Iujqxbaw1w(l;P+addF>9ZWEn z0#XXig*J4li~Rx4cMi9gf-L+i7S<;#z?#6+1cX(@NoyrdQlg?POQYYmEnG*h7d^pp zEZqZy63+@?#5GXP1WfdnbIoBVimH#;E$Hq0``PL44&A?#f;b&F{ch~*h)uu?pc8NpHY<_fnTG;kjETCg zT~~wq80WsKB_I?+1pue(`No1F{TyX(FbE*3s_JnxO+x@cS2bfy-cw4=IL`TejmVdT zF990>)Kef(F{v8pH5o0gL`@p85GVjoT?hw2?maxq3gC!k1Ms<*9Wqw}p+g3B__*7d zQUjqrkM93&LkYIYkrx;UlsVL(07z8F3z?Y$kdoYB&I+(5@B<#MkRf>wI+*|f002ov JPDHLkV1oGusviIV literal 0 HcmV?d00001 From 3a4749f881d6d7b157b2186b921acf85140423ee Mon Sep 17 00:00:00 2001 From: m-grigoriu Date: Wed, 30 Nov 2022 17:24:23 -0500 Subject: [PATCH 22/22] Updated InventoryInteractorTest to work with new character names. --- .../Inventory/InventoryInteractorTest.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java b/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java index 83a1a9eb..68823cf4 100644 --- a/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java +++ b/src/test/java/com/mg105/use_cases/Inventory/InventoryInteractorTest.java @@ -5,6 +5,7 @@ import com.mg105.entities.items.UpgradeToken; import com.mg105.outputds.ItemDetails; import com.mg105.utils.ItemConstants; +import com.mg105.utils.PartyConstants; import org.junit.jupiter.api.Test; import java.awt.*; @@ -38,14 +39,14 @@ public void inventoryDetails(ItemDetails[] allItemsDetails) { } }; - BattleCharacter b1 = new BattleCharacter(1, "A", 2, 3, false, - new Move(0, 0, "m1", false), + BattleCharacter b1 = new BattleCharacter(1, PartyConstants.ALL_PARTY_MEMBER_NAMES[0], 2, 3, + false, new Move(0, 0, "m1", false), new Move(0, 0, "m2", false)); - BattleCharacter b2 = new BattleCharacter(1, "B", 2, 3, false, - new Move(0, 0, "m1", false), + BattleCharacter b2 = new BattleCharacter(1, PartyConstants.ALL_PARTY_MEMBER_NAMES[1], 2, 3, + false, new Move(0, 0, "m1", false), new Move(0, 0, "m2", false)); - BattleCharacter b3 = new BattleCharacter(1, "C", 2, 3, false, - new Move(0, 0, "m1", false), + BattleCharacter b3 = new BattleCharacter(1, PartyConstants.ALL_PARTY_MEMBER_NAMES[2], 2, 3, + false, new Move(0, 0, "m1", false), new Move(0, 0, "m2", false)); BattleCharacter[] party = {b1, b2, b3}; @@ -219,7 +220,7 @@ void useItemInventoryExists() { assertEquals(1, inventory.numberOfItems(ItemConstants.UPGRADE_TOKEN_NAME)); - inventoryInteractor.useItem(ItemConstants.UPGRADE_TOKEN_NAME, "A"); + inventoryInteractor.useItem(ItemConstants.UPGRADE_TOKEN_NAME, PartyConstants.ALL_PARTY_MEMBER_NAMES[0]); assertEquals(2, party[0].getMaxHp()); assertEquals(3, party[0].getDmg()); assertEquals(4, party[0].getSpeed()); @@ -257,7 +258,7 @@ void useItemInventoryLimitExists() { InventoryInteractor inventoryInteractor = new InventoryInteractor(state, res); assertEquals(6, inventory.numberOfItems(ItemConstants.HEALTH_POTION_NAME)); - inventoryInteractor.useItem(ItemConstants.HEALTH_POTION_NAME, "B"); + inventoryInteractor.useItem(ItemConstants.HEALTH_POTION_NAME, PartyConstants.ALL_PARTY_MEMBER_NAMES[1]); assertEquals(5, inventory.numberOfItems(ItemConstants.HEALTH_POTION_NAME)); assertEquals(1, party[1].getHp()); }