diff --git a/configurations/demo-config-1/locations/location-1/objects/object-2.json b/configurations/demo-config-1/locations/location-1/objects/object-2.json index d9e6862d..624c983a 100644 --- a/configurations/demo-config-1/locations/location-1/objects/object-2.json +++ b/configurations/demo-config-1/locations/location-1/objects/object-2.json @@ -5,6 +5,7 @@ "onLeftClick": { "tag": "dialogue-action", "type": "collect", - "assetPath": "assets/coin.png" + "assetPath": "assets/key.png", + "description": "A powerful key." } } diff --git a/docs/configuration.md b/docs/configuration.md index abe7b450..0031a1ed 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -172,6 +172,8 @@ As for now we support 5 kinds of actions: * `location-change` * `show-description` * `dialogue` +* `battle` +* `collect` For each kind configuration differs a bit, because different information is required. Let's take a closer look at the common part first. Each action consists of following properties @@ -206,15 +208,19 @@ Let's look at specific action types: Aliases: `targetLocation`, `target` * `show-description`: - * `assetPath` - Path to the image with background for the dialogue window. As any path, it must be eiter absolute or relative to the engine's source root. + * `assetPath` - Path to the image shown in the description popup, presumably depicting the object that the action belongs to. As any path, it must be eiter absolute or relative to the engine's source root. Aliases: `asset-path`, `asset`. * `description` - Additional information about the object. * `dialogue`: * `statements` - **List** of statements to be said. Right now, **only one statement is supported**, however you must provide it as a list. Aliases: `text`, `dialogue-statements`, `dialogueStatements`. \\ - * `assetPath` - Path to the image with background for the dialogue window. As any path, it must be eiter absolute or relative to the engine's source root. + * `assetPath` - Path to the image displayed in the dialogue popup, presumably depicting the NPC that the action is tied to. As any path, it must be eiter absolute or relative to the engine's source root. Aliases: `asset-path`, `asset`. * `battle` -- No props required. +* `collect`: + * `assetPath` - Path to the image that will be shown in a popup after collecting the object, as well as in the Inventory window. As any path, it must be eiter absolute or relative to the engine's source root. + Aliases: `asset-path`, `asset`. + * `description` - Text displayed when the cursor is above the collected item in the Inventory window. ## Condition configuration diff --git a/src/main/java/io/rpg/Initializer.java b/src/main/java/io/rpg/Initializer.java index c93f9b91..c375c97a 100644 --- a/src/main/java/io/rpg/Initializer.java +++ b/src/main/java/io/rpg/Initializer.java @@ -14,10 +14,8 @@ import io.rpg.util.GameObjectViewFactory; import io.rpg.view.GameObjectView; import io.rpg.view.LocationView; -import io.rpg.view.popups.DialoguePopup; -import io.rpg.view.popups.QuestionPopup; -import io.rpg.view.popups.TextImagePopup; -import io.rpg.view.popups.TextPopup; +import io.rpg.view.popups.*; + import java.io.IOException; import java.nio.file.Path; import java.util.Iterator; @@ -63,6 +61,7 @@ public Result initialize() { TextImagePopup.setButtonPath(gameWorldConfig.getTextImagePopupButton()); DialoguePopup.setBackgroundPath(gameWorldConfig.getDialoguePopupBackground()); DialoguePopup.setNpcFramePath(gameWorldConfig.getNpcFrame()); + InventoryPopup.setBackgroundPath(gameWorldConfig.getInventoryPopupBackground()); Controller.Builder controllerBuilder = new Controller.Builder(); diff --git a/src/main/java/io/rpg/config/ConfigLoader.java b/src/main/java/io/rpg/config/ConfigLoader.java index 6e653ac4..f116525e 100644 --- a/src/main/java/io/rpg/config/ConfigLoader.java +++ b/src/main/java/io/rpg/config/ConfigLoader.java @@ -236,7 +236,7 @@ private Result loadGameObjectsForLocation(LocationConfig locati return Result.err(new Exception("Validation for game object config with tag: " + gameObjectConfig.getTag() + " failed.")); } else { - logger.info("Loaded GameObjectConfig for tag: " + gameObjectConfig.getTag() + ":" + gameObjectConfig); + logger.info("Loaded GameObjectConfig for tag: " + gameObjectConfig.getTag()); } } @@ -272,7 +272,7 @@ Result loadRootFile() { return Result.err(exception); } - // after loading a object from JSON we should always call the validate method + // after loading an object from JSON we should always call the validate method // load information from configuration root file GameWorldConfig gameWorldConfigShell = gson.fromJson(reader, GameWorldConfig.class); diff --git a/src/main/java/io/rpg/config/model/ActionConfigBundle.java b/src/main/java/io/rpg/config/model/ActionConfigBundle.java index b9583535..6cbc8db3 100644 --- a/src/main/java/io/rpg/config/model/ActionConfigBundle.java +++ b/src/main/java/io/rpg/config/model/ActionConfigBundle.java @@ -85,6 +85,7 @@ public class ActionConfigBundle implements ConfigWithValidation { /** * {@link io.rpg.model.actions.GameEndAction}
* {@link io.rpg.model.actions.ShowDescriptionAction}
+ * {@link io.rpg.model.actions.CollectAction}
* TODO */ @Nullable @@ -265,7 +266,16 @@ Result validateForBattle() { } Result validateForCollectAction() { - return Result.ok(); + ErrorMessageBuilder builder = new ErrorMessageBuilder(); + if (description == null) { + builder.append("No description provided"); + } + if (assetPath == null) { + builder.append("No asset path provided"); + } else if (!Files.isRegularFile(Path.of(assetPath))) { + builder.append("Provided asset path does not point to a regular file"); + } + return builder.isEmpty() ? Result.ok() : Result.err(new IllegalStateException(builder.toString())); } Result validateBasic() { @@ -324,6 +334,7 @@ public Result validate() { case Quiz -> { return validateForQuizAction(); } case ShowDescription -> { return validateForShowDescriptionAction(); } case Battle -> { return validateForBattle(); } + case Collect -> { return validateForCollectAction(); } default -> { return Result.err(new RuntimeException("Invalid result returned")); } } } diff --git a/src/main/java/io/rpg/controller/Controller.java b/src/main/java/io/rpg/controller/Controller.java index 0594994b..2622ca1f 100644 --- a/src/main/java/io/rpg/controller/Controller.java +++ b/src/main/java/io/rpg/controller/Controller.java @@ -7,29 +7,20 @@ import io.rpg.model.data.MouseClickedEvent; import io.rpg.model.data.Position; import io.rpg.model.location.LocationModel; -import io.rpg.model.object.CollectibleGameObject; import io.rpg.model.object.GameObject; -import io.rpg.model.object.Player; import io.rpg.model.object.Question; -import io.rpg.util.BattleResult; -import io.rpg.view.GameEndView; import io.rpg.view.GameObjectView; -import io.rpg.view.InventoryPopup; import io.rpg.view.LocationView; import javafx.geometry.Point2D; import javafx.scene.Scene; -import javafx.scene.image.Image; import javafx.scene.input.KeyEvent; import javafx.scene.input.MouseButton; import javafx.stage.Stage; -import javafx.stage.StageStyle; -import io.rpg.view.popups.TextPopup; +import javafx.stage.WindowEvent; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.LinkedHashMap; import java.util.List; @@ -84,6 +75,8 @@ public void setMainStage(Stage mainStage) { player.setRightPressed(false); } }); + + mainStage.getScene().getWindow().addEventFilter(WindowEvent.WINDOW_CLOSE_REQUEST, (event) -> popupController.hidePopup()); } public void setCurrentModel(@NotNull LocationModel model) { diff --git a/src/main/java/io/rpg/controller/PopupController.java b/src/main/java/io/rpg/controller/PopupController.java index 40795d3a..9d5fb6d5 100644 --- a/src/main/java/io/rpg/controller/PopupController.java +++ b/src/main/java/io/rpg/controller/PopupController.java @@ -6,10 +6,9 @@ import io.rpg.view.popups.DialoguePopup; import io.rpg.view.popups.QuestionPopup; import io.rpg.model.data.Inventory; -import io.rpg.view.InventoryPopup; +import io.rpg.view.popups.InventoryPopup; import io.rpg.view.popups.TextImagePopup; import io.rpg.view.popups.TextPopup; -import javafx.event.EventHandler; import javafx.scene.image.Image; import javafx.stage.Stage; import javafx.stage.StageStyle; diff --git a/src/main/java/io/rpg/model/actions/ActionEngine.java b/src/main/java/io/rpg/model/actions/ActionEngine.java index 70670945..b4d578c9 100644 --- a/src/main/java/io/rpg/model/actions/ActionEngine.java +++ b/src/main/java/io/rpg/model/actions/ActionEngine.java @@ -5,9 +5,9 @@ import io.rpg.model.object.GameObject; import io.rpg.model.object.Player; import io.rpg.util.BattleResult; +import io.rpg.view.GameObjectView; import io.rpg.view.InventoryGameObjectView; import io.rpg.view.LocationView; -import javafx.application.Platform; import javafx.scene.image.Image; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -124,10 +124,10 @@ public void onAction(BattleAction action) { public void onAction(CollectAction action) { actionGuard(action, () -> { var controller = controller(); - controller.getPopupController().openTextImagePopup("Picked up an item!", new Image("file:" + action.getAssetPath()), + controller.getPopupController().openTextImagePopup("Picked up an item!", new Image(GameObjectView.resolvePathToJFXFormat(action.getAssetPath())), controller.getWindowCenterX(), controller.getWindowCenterY()); controller.getPlayerController().getPlayer().getInventory() - .add(new InventoryGameObjectView(action.getOwner(), action.getAssetPath())); + .add(new InventoryGameObjectView(action.getAssetPath(), action.getDescription())); controller.removeObjectFromModel(action.getOwner()); }); } diff --git a/src/main/java/io/rpg/model/actions/CollectAction.java b/src/main/java/io/rpg/model/actions/CollectAction.java index f6fd399f..8a575e17 100644 --- a/src/main/java/io/rpg/model/actions/CollectAction.java +++ b/src/main/java/io/rpg/model/actions/CollectAction.java @@ -6,10 +6,12 @@ public class CollectAction extends BaseAction { private final String assetPath; + private final String description; - public CollectAction(String assetPath, @Nullable Condition condition) { + public CollectAction(String assetPath, String description, @Nullable Condition condition) { super(condition); this.assetPath = assetPath; + this.description = description; } public GameObject getOwner() { @@ -24,5 +26,9 @@ public void acceptActionEngine(ActionEngine engine) { public String getAssetPath() { return assetPath; } + + public String getDescription() { + return description; + } } diff --git a/src/main/java/io/rpg/util/ActionFactory.java b/src/main/java/io/rpg/util/ActionFactory.java index c982978e..5d45a026 100644 --- a/src/main/java/io/rpg/util/ActionFactory.java +++ b/src/main/java/io/rpg/util/ActionFactory.java @@ -3,7 +3,6 @@ import io.rpg.config.model.ActionConfigBundle; import io.rpg.model.actions.*; import io.rpg.model.actions.condition.ConditionFactory; -import io.rpg.model.object.Question; import javafx.scene.image.Image; public class ActionFactory { @@ -49,11 +48,8 @@ private static Action actionByType(ActionConfigBundle config) { case Collect -> { return collectActionFromConfig(config); } - default -> { - throw new IllegalArgumentException("Unexpected action type!"); - } + default -> throw new IllegalArgumentException("Unexpected action type!"); } - } private static QuizAction quizActionFromConfig(ActionConfigBundle config) { @@ -97,6 +93,6 @@ private static void initBeforeAndAfterActions(Action action, ActionConfigBundle } private static CollectAction collectActionFromConfig(ActionConfigBundle config) { - return new CollectAction(config.getAssetPath(), ConditionFactory.fromConfig(config.getCondition())); + return new CollectAction(config.getAssetPath(), config.getDescription(), ConditionFactory.fromConfig(config.getCondition())); } } diff --git a/src/main/java/io/rpg/view/InventoryGameObjectView.java b/src/main/java/io/rpg/view/InventoryGameObjectView.java index aa803bf7..ffb0cc49 100644 --- a/src/main/java/io/rpg/view/InventoryGameObjectView.java +++ b/src/main/java/io/rpg/view/InventoryGameObjectView.java @@ -1,15 +1,16 @@ package io.rpg.view; -import io.rpg.model.object.GameObject; import javafx.scene.image.Image; import javafx.scene.image.ImageView; public class InventoryGameObjectView extends ImageView { - GameObject collectibleGameObject; - public InventoryGameObjectView(GameObject collectibleGameObject, String assetPath) { - this.collectibleGameObject = collectibleGameObject; + public final String description; + + public InventoryGameObjectView(String assetPath, String description) { Image image = new Image(GameObjectView.resolvePathToJFXFormat(assetPath)); setImage(image); + + this.description = description; } } diff --git a/src/main/java/io/rpg/view/InventoryPopup.java b/src/main/java/io/rpg/view/InventoryPopup.java deleted file mode 100644 index 7465c47c..00000000 --- a/src/main/java/io/rpg/view/InventoryPopup.java +++ /dev/null @@ -1,97 +0,0 @@ -package io.rpg.view; - -import io.rpg.model.data.Inventory; -import io.rpg.model.data.Position; -import io.rpg.model.object.Player; -import io.rpg.viewmodel.InventoryPopupViewModel; -import io.rpg.viewmodel.TextPopupViewModel; -import javafx.event.EventHandler; -import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; -import javafx.scene.Group; -import javafx.scene.Parent; -import javafx.scene.Scene; -import javafx.scene.control.Label; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.input.MouseEvent; -import javafx.scene.paint.Color; -import javafx.scene.shape.Rectangle; - -import java.io.IOException; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -public class InventoryPopup extends Scene { - final int PADDING_LEFT = 25; - final int PADDING_TOP = 20; - @FXML - private Label label; - - @FXML - private Label strengthLabel; - - @FXML - private Label pointsLabel; - - public InventoryPopup(Inventory inventory, Player player) { - - super(new Group(), Color.TRANSPARENT); - Group group = new Group(); - //TODO: load asset path from config - ImageView imageView = new ImageView(GameObjectView.resolvePathToJFXFormat("assets/popup-background.png")); - imageView.setX(0); - imageView.setY(0); - this.pointsLabel = new Label(); - this.pointsLabel.setText("Points :" + String.valueOf(player.getPoints())); - this.pointsLabel.setLayoutX(325); - this.pointsLabel.setLayoutY(150); - this.pointsLabel.setStyle("-fx-font-family: Monospaced; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: " + 18); - this.strengthLabel=new Label(); - this.strengthLabel.setStyle("-fx-font-family: Monospaced; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: " + 18); - this.strengthLabel.setText("Strength :"+String.valueOf(player.getStrength())); - this.strengthLabel.setLayoutX(325); - this.strengthLabel.setLayoutY(200); - label = new Label(); - label.setLayoutX(300); - label.setLayoutY(100); - label.setStyle("-fx-font-family: Monospaced; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: " + 18); - group.getChildren().add(imageView); - group.getChildren().add(label); - group.getChildren().add(pointsLabel); - group.getChildren().add(strengthLabel); - - for (int i = 0; i < inventory.items.size(); i++) { -// String assetPath=inventory.items.get(i).getAssetPath(); -// to display objects in the menu -// wrapperClass to store information about object which we display - InventoryGameObjectView imageGameObjectView = inventory.items.get(i); - - imageGameObjectView.setX(i * 50 + PADDING_LEFT); - imageGameObjectView.setY(0 + PADDING_TOP); - imageGameObjectView.setOnMouseEntered(event -> { - InventoryGameObjectView src = (InventoryGameObjectView) event.getSource(); -// System.out.println("over the item "+src.collectibleGameObject.getAssetPath()); - label.setText("mock description"); - }); - - imageGameObjectView.setOnMouseExited(event -> { - label.setText(""); - }); - - imageGameObjectView.setOnMouseClicked(event -> { - - System.out.println("Object clicked"); - InventoryGameObjectView src = (InventoryGameObjectView) event.getSource(); - System.out.println(); - }); - group.getChildren().add(imageGameObjectView); - - } - this.setRoot(group); - this.setFill(Color.TRANSPARENT); - } - -} diff --git a/src/main/java/io/rpg/view/popups/InventoryPopup.java b/src/main/java/io/rpg/view/popups/InventoryPopup.java new file mode 100644 index 00000000..51d41c5e --- /dev/null +++ b/src/main/java/io/rpg/view/popups/InventoryPopup.java @@ -0,0 +1,77 @@ +package io.rpg.view.popups; + +import io.rpg.model.data.Inventory; +import io.rpg.model.object.Player; +import io.rpg.view.InventoryGameObjectView; +import javafx.fxml.FXML; +import javafx.scene.Group; +import javafx.scene.Scene; +import javafx.scene.control.Label; +import javafx.scene.image.ImageView; +import javafx.scene.paint.Color; + +public class InventoryPopup extends Scene { + final int PADDING_LEFT = 25; + final int PADDING_TOP = 20; + @FXML + private Label label; + + @FXML + private Label strengthLabel; + + @FXML + private Label pointsLabel; + + private static String backgroundPath; + + public InventoryPopup(Inventory inventory, Player player) { + + super(new Group(), Color.TRANSPARENT); + Group group = new Group(); + + ImageView imageView = new ImageView(backgroundPath); + imageView.setX(0); + imageView.setY(0); + + this.pointsLabel = new Label(); + this.pointsLabel.setText("Points :" + player.getPoints()); + this.pointsLabel.setLayoutX(325); + this.pointsLabel.setLayoutY(150); + this.pointsLabel.setStyle("-fx-font-family: Monospaced; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: " + 18); + + this.strengthLabel = new Label(); + this.strengthLabel.setStyle("-fx-font-family: Monospaced; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: " + 18); + this.strengthLabel.setText("Strength :" + player.getStrength()); + this.strengthLabel.setLayoutX(325); + this.strengthLabel.setLayoutY(200); + + label = new Label(); + label.setLayoutX(300); + label.setLayoutY(100); + label.setStyle("-fx-font-family: Monospaced; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: " + 12); + + group.getChildren().add(imageView); + group.getChildren().add(label); + group.getChildren().add(pointsLabel); + group.getChildren().add(strengthLabel); + + for (int i = 0; i < inventory.items.size(); i++) { + InventoryGameObjectView inventoryItem = inventory.items.get(i); + + inventoryItem.setX(i * 50 + PADDING_LEFT); + inventoryItem.setY(PADDING_TOP); + + inventoryItem.setOnMouseEntered(event -> label.setText(inventoryItem.description)); + inventoryItem.setOnMouseExited(event -> label.setText("")); + + group.getChildren().add(inventoryItem); + } + + this.setRoot(group); + this.setFill(Color.TRANSPARENT); + } + + public static void setBackgroundPath(String backgroundPath) { + InventoryPopup.backgroundPath = backgroundPath; + } +} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index c3817e5c..0d4d7f3c 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -25,4 +25,5 @@ opens io.rpg.config.model to com.google.gson; exports io.rpg; + opens io.rpg.view.popups to javafx.fxml; }