diff --git a/configurations/demo-config-1/locations/location-1/location-1.json b/configurations/demo-config-1/locations/location-1/location-1.json index 1d5abd3b..3fcd61de 100644 --- a/configurations/demo-config-1/locations/location-1/location-1.json +++ b/configurations/demo-config-1/locations/location-1/location-1.json @@ -41,9 +41,9 @@ { "tag": "mul-1", "position": { "row": 6, "col": 9 }, "assetPath": "assets/bush.png" }, { "tag": "mul-1", "position": { "row": 7, "col": 9 }, "assetPath": "assets/bush.png" }, { "tag": "mul-1", "position": { "row": 8, "col": 9 }, "assetPath": "assets/bush.png" }, - { "tag": "object-1", "position": { "row": 7, "col": 8 }, "assetPath": "assets/bunny.png" }, - { "tag": "object-2", "position": { "row": 6, "col": 3 }, "assetPath": "assets/key.png" }, - { "tag": "object-3", "position": { "row": 2, "col": 0 }, "assetPath": "assets/zombie.png" }, + { "tag": "tp-bunny", "position": { "row": 7, "col": 8 }, "assetPath": "assets/bunny.png" }, + { "tag": "key", "position": { "row": 6, "col": 3 }, "assetPath": "assets/key.png" }, + { "tag": "bandit", "position": { "row": 2, "col": 0 }, "assetPath": "assets/zombie.png" }, { "tag": "object-4", "position": { "row": 3, "col": 7 }, "assetPath": "assets/zombie.png" }, { "tag": "object-5", "position": { "row": 9, "col": 8 }, "assetPath": "assets/chest.png" }, { "tag": "object-6", "position": { "row": 9, "col": 9 }, "assetPath": "assets/bush.png" } diff --git a/configurations/demo-config-1/locations/location-1/objects/object-3.json b/configurations/demo-config-1/locations/location-1/objects/bandit.json similarity index 87% rename from configurations/demo-config-1/locations/location-1/objects/object-3.json rename to configurations/demo-config-1/locations/location-1/objects/bandit.json index b0719c24..02e18d8b 100644 --- a/configurations/demo-config-1/locations/location-1/objects/object-3.json +++ b/configurations/demo-config-1/locations/location-1/objects/bandit.json @@ -1,5 +1,5 @@ { - "tag": "object-3", + "tag": "bandit", "assetPath": "assets/bandit.png", "type": "dialog", "onLeftClick": { diff --git a/configurations/demo-config-1/locations/location-1/objects/object-2.json b/configurations/demo-config-1/locations/location-1/objects/key.json similarity index 89% rename from configurations/demo-config-1/locations/location-1/objects/object-2.json rename to configurations/demo-config-1/locations/location-1/objects/key.json index 03164a34..895f8289 100644 --- a/configurations/demo-config-1/locations/location-1/objects/object-2.json +++ b/configurations/demo-config-1/locations/location-1/objects/key.json @@ -1,4 +1,4 @@ { - "tag": "object-2", + "tag": "key", "onLeftClick": {"tag": "dialogue-action", "type": "dialogue", "statements": ["A key.,A, keyA, key.A, key.A, key.A, key.A, key.A, key.A key."], "assetPath": "assets/key.png"} } diff --git a/configurations/demo-config-1/locations/location-1/objects/object-1.json b/configurations/demo-config-1/locations/location-1/objects/object-1.json deleted file mode 100644 index 6e24f567..00000000 --- a/configurations/demo-config-1/locations/location-1/objects/object-1.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "tag": "object-1", - "onLeftClick": {"tag": "change-location", "type": "location-change", "target-location": "location-2", "target-position": {"row": 9, "col": 0}} -} \ No newline at end of file diff --git a/configurations/demo-config-1/locations/location-1/objects/tp-bunny.json b/configurations/demo-config-1/locations/location-1/objects/tp-bunny.json new file mode 100644 index 00000000..c31ef1c0 --- /dev/null +++ b/configurations/demo-config-1/locations/location-1/objects/tp-bunny.json @@ -0,0 +1,13 @@ +{ + "tag": "tp-bunny", + "onLeftClick": { + "tag": "change-location", + "type": "location-change", + "target-location": "location-2", + "target-position": {"row": 9, "col": 0}, + "condition": { + "type": "item-required", + "item-tag": "key" + } + } +} \ No newline at end of file diff --git a/src/main/java/io/rpg/Initializer.java b/src/main/java/io/rpg/Initializer.java index 374c7aa3..c93f9b91 100644 --- a/src/main/java/io/rpg/Initializer.java +++ b/src/main/java/io/rpg/Initializer.java @@ -111,7 +111,7 @@ public Result initialize() { Game.Builder gameBuilder = new Game.Builder(); Game game = gameBuilder .setController(controller) - .setOnStartAction(new LocationChangeAction(gameWorldConfig.getRootLocation(), player.getPosition())) + .setOnStartAction(new LocationChangeAction(gameWorldConfig.getRootLocation(), player.getPosition(), null)) .build(); return Result.ok(game); diff --git a/src/main/java/io/rpg/config/model/ActionConfigBundle.java b/src/main/java/io/rpg/config/model/ActionConfigBundle.java index d2c3b134..68f4f41a 100644 --- a/src/main/java/io/rpg/config/model/ActionConfigBundle.java +++ b/src/main/java/io/rpg/config/model/ActionConfigBundle.java @@ -41,9 +41,15 @@ public class ActionConfigBundle implements ConfigWithValidation { */ @Nullable @SerializedName("type") -// private String actionType; private ActionType actionType; + /** + * Condition that needs to be satisfied before the action can be executed. + */ + @Nullable + @SerializedName(value = "condition", alternate = {"requires"}) + private ConditionConfigBundle condition; + /** * Action to be triggered before the proper action is executed. */ @@ -149,6 +155,11 @@ public ActionType getActionType() { return actionType; } + @Nullable + public ConditionConfigBundle getCondition() { + return condition; + } + @Nullable public ActionConfigBundle getBeforeAction() { return beforeAction; @@ -263,6 +274,9 @@ Result validateBasic() { if (actionType == null) { builder.append("No action type or invalid action type provided"); } + if (condition != null) { + condition.validate().ifErr(ex -> builder.append(ex.getMessage())); + } return builder.isEmpty() ? Result.ok() : Result.err(new IllegalStateException(builder.toString())); diff --git a/src/main/java/io/rpg/config/model/ConditionConfigBundle.java b/src/main/java/io/rpg/config/model/ConditionConfigBundle.java new file mode 100644 index 00000000..db5e970a --- /dev/null +++ b/src/main/java/io/rpg/config/model/ConditionConfigBundle.java @@ -0,0 +1,55 @@ +package io.rpg.config.model; + +import com.google.gson.annotations.SerializedName; +import com.kkafara.rt.Result; +import io.rpg.model.actions.ConditionType; +import io.rpg.util.ErrorMessageBuilder; +import org.jetbrains.annotations.Nullable; + +public class ConditionConfigBundle implements ConfigWithValidation { + + @Nullable + private ConditionType type; + + @Nullable + @SerializedName(value = "item-tag", alternate = {"itemTag"}) + private String itemTag; + + @Nullable + public ConditionType getType() { + return type; + } + + @Nullable + public String getItemTag() { + return itemTag; + } + + Result validateItemRequired() { + ErrorMessageBuilder builder = new ErrorMessageBuilder(); + + if (itemTag == null || itemTag.isBlank()) { + builder.append("No or invalid item tag provided"); + } + + return builder.isEmpty() ? Result.ok() : Result.err(new Exception(builder.toString())); + } + + @Override + public Result validate() { + ErrorMessageBuilder builder = new ErrorMessageBuilder(); + + if (type == null) { + builder.append("No or invalid type provided"); + } + + if (!builder.isEmpty()) { + return Result.err(new Exception(builder.toString())); + } + + switch (type) { + case ITEM_REQUIRED -> { return validateItemRequired(); } + default -> throw new IllegalArgumentException("Not implemented condition type!"); + } + } +} diff --git a/src/main/java/io/rpg/controller/Controller.java b/src/main/java/io/rpg/controller/Controller.java index ca9bccef..d73b1e62 100644 --- a/src/main/java/io/rpg/controller/Controller.java +++ b/src/main/java/io/rpg/controller/Controller.java @@ -2,6 +2,7 @@ import com.kkafara.rt.Result; import io.rpg.model.actions.*; +import io.rpg.model.actions.condition.ConditionEngine; import io.rpg.model.data.KeyboardEvent; import io.rpg.model.data.MouseClickedEvent; import io.rpg.model.data.Position; @@ -13,10 +14,6 @@ import io.rpg.view.GameEndView; import io.rpg.view.GameObjectView; import io.rpg.view.LocationView; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.LinkedHashMap; -import java.util.List; import javafx.geometry.Point2D; import javafx.scene.Scene; import javafx.scene.input.KeyEvent; @@ -26,6 +23,11 @@ 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; + public class Controller implements KeyboardEvent.Observer, MouseClickedEvent.Observer, ActionConsumer { private Scene currentView; private LinkedHashMap tagToLocationModelMap; @@ -36,6 +38,7 @@ public class Controller implements KeyboardEvent.Observer, MouseClickedEvent.Obs private PlayerController playerController; private GameEndController gameEndController; private Stage mainStage; + private final ConditionEngine conditionEngine; public Controller() { @@ -43,6 +46,8 @@ public Controller() { tagToLocationModelMap = new LinkedHashMap<>(); tagToLocationViewMap = new LinkedHashMap<>(); + + conditionEngine = new ConditionEngine(this); gameEndController = new GameEndController(); } @@ -57,6 +62,8 @@ public Controller(LinkedHashMap tagToLocationModelMap, // TODO: handle errors this.currentModel = this.tagToLocationModelMap.get(rootTag); this.currentView = this.tagToLocationViewMap.get(rootTag); + + conditionEngine = new ConditionEngine(this); } public void setMainStage(Stage mainStage) { @@ -107,40 +114,48 @@ public void consumeAction(Action action) { } private void onAction(LocationChangeAction action) { - if (!this.tagToLocationModelMap.containsKey(action.destinationLocationTag)) { - logger.error("Unknown location tag"); - return; - } + actionGuard(action, () -> { + if (!this.tagToLocationModelMap.containsKey(action.destinationLocationTag)) { + logger.error("Unknown location tag"); + return; + } - LocationView nextView = this.tagToLocationViewMap.get(action.destinationLocationTag); - LocationModel nextModel = this.tagToLocationModelMap.get(action.destinationLocationTag); + LocationView nextView = this.tagToLocationViewMap.get(action.destinationLocationTag); + LocationModel nextModel = this.tagToLocationModelMap.get(action.destinationLocationTag); - playerController.teleportTo(nextModel, nextView, action.playerPosition); + playerController.teleportTo(nextModel, nextView, action.playerPosition); - this.currentModel = nextModel; - this.currentView = nextView; - mainStage.setScene(nextView); + this.currentModel = nextModel; + this.currentView = nextView; + mainStage.setScene(nextView); + }); } private void onAction(DialogueAction action) { - popupController.openDialoguePopup(action.text, action.image, getWindowCenterX(), getWindowCenterY()); + actionGuard(action, () -> { + popupController.openDialoguePopup(action.text, action.image, getWindowCenterX(), getWindowCenterY()); + }); } private void onAction(ShowDescriptionAction action) { - if (!action.description.isEmpty()) { - popupController.openTextImagePopup(action.description, action.image, getWindowCenterX(), getWindowCenterY()); - } + actionGuard(action, () -> { + if (!action.description.isEmpty()) { + popupController.openTextImagePopup(action.description, action.image, getWindowCenterX(), getWindowCenterY()); + } + }); } private void onAction(QuizAction action) { - int pointsCount = action.getPointsToEarn(); - popupController.openQuestionPopup( - action.question, - getWindowCenterX(), getWindowCenterY(), - () -> acceptQuizResult(true, pointsCount), - () -> acceptQuizResult(false, 0) - ); - action.setPointsToEarn(0); + actionGuard(action, () -> { + int pointsCount = action.getPointsToEarn(); + popupController.openQuestionPopup( + action.question, + getWindowCenterX(), getWindowCenterY(), + () -> acceptQuizResult(true, pointsCount), + () -> acceptQuizResult(false, 0) + ); + action.setPointsToEarn(0); + }); } public void acceptQuizResult(boolean correct, int pointsCount) { @@ -156,24 +171,35 @@ public void acceptQuizResult(boolean correct, int pointsCount) { } private void onAction(GameEndAction action) { - gameEndController.showGameEnd(mainStage, action.description); - + actionGuard(action, () -> { + gameEndController.showGameEnd(mainStage, action.description); + }); } private void onAction(BattleAction action) { - Player player = playerController.getPlayer(); - GameObject opponent = action.getOpponent(); - int reward = action.getReward(); - BattleResult result; - if (player.getPoints() > opponent.getStrength()) { - player.addPoints(reward); - result = new BattleResult(BattleResult.Result.VICTORY, reward); - } else if (player.getStrength() < opponent.getStrength()) { - result = new BattleResult(BattleResult.Result.DEFEAT, 0); - } else { - result = new BattleResult(BattleResult.Result.DRAW, 0); + actionGuard(action, () -> { + Player player = playerController.getPlayer(); + GameObject opponent = action.getOpponent(); + int reward = action.getReward(); + BattleResult result; + if (player.getPoints() > opponent.getStrength()) { + player.addPoints(reward); + result = new BattleResult(BattleResult.Result.VICTORY, reward); + } else if (player.getStrength() < opponent.getStrength()) { + result = new BattleResult(BattleResult.Result.DEFEAT, 0); + } else { + result = new BattleResult(BattleResult.Result.DRAW, 0); + } + popupController.openTextPopup(result.getMessage(), getWindowCenterX(), getWindowCenterY()); + }); + } + + private void actionGuard(ConditionalAction action, Runnable actionLogic) { + if (action.getCondition() != null && !action.getCondition().acceptEngine(conditionEngine)) { + logger.info("Action not executed due to condition being not satisfied"); + return; } - popupController.openTextPopup(result.getMessage(), getWindowCenterX(), getWindowCenterY()); + actionLogic.run(); } public Scene getView() { @@ -220,13 +246,10 @@ public void onKeyboardEvent(KeyboardEvent event) { case F -> popupController.openPointsPopup(5, getWindowCenterX(), getWindowCenterY()); case G -> popupController.openTextPopup("Hello!", getWindowCenterX(), getWindowCenterY()); case Q -> popupController.openQuestionPopup(new Question("How many bits are there in one byte?", new String[]{"1/8", "1024", "8", "256"}, 'C'), getWindowCenterX(), getWindowCenterY()); - case L -> consumeAction(new LocationChangeAction("location-2", new Position(1, 2))); - case U -> consumeAction(new GameEndAction("You have pressed the forbidden button")); + case L -> consumeAction(new LocationChangeAction("location-2", new Position(1, 2), null)); + case U -> consumeAction(new GameEndAction("You have pressed the forbidden button", null)); } } - // } else if (payload.getEventType() == KeyEvent.KEY_RELEASED) { - // - // } } private int getWindowCenterX() { diff --git a/src/main/java/io/rpg/model/actions/BattleAction.java b/src/main/java/io/rpg/model/actions/BattleAction.java index b70fc9b0..ab7acfbd 100644 --- a/src/main/java/io/rpg/model/actions/BattleAction.java +++ b/src/main/java/io/rpg/model/actions/BattleAction.java @@ -1,12 +1,14 @@ package io.rpg.model.actions; +import io.rpg.model.actions.condition.Condition; import io.rpg.model.object.GameObject; -public class BattleAction implements Action { +public class BattleAction extends ConditionalAction { private GameObject opponent; private final int reward; - public BattleAction(int reward) { + public BattleAction(int reward, Condition condition) { + super(condition); this.reward = reward; } diff --git a/src/main/java/io/rpg/model/actions/ConditionType.java b/src/main/java/io/rpg/model/actions/ConditionType.java new file mode 100644 index 00000000..6efd7456 --- /dev/null +++ b/src/main/java/io/rpg/model/actions/ConditionType.java @@ -0,0 +1,8 @@ +package io.rpg.model.actions; + +import com.google.gson.annotations.SerializedName; + +public enum ConditionType { + @SerializedName("item-required") + ITEM_REQUIRED +} diff --git a/src/main/java/io/rpg/model/actions/ConditionalAction.java b/src/main/java/io/rpg/model/actions/ConditionalAction.java new file mode 100644 index 00000000..ff6a37ae --- /dev/null +++ b/src/main/java/io/rpg/model/actions/ConditionalAction.java @@ -0,0 +1,18 @@ +package io.rpg.model.actions; + +import io.rpg.model.actions.condition.Condition; +import org.jetbrains.annotations.Nullable; + +public abstract class ConditionalAction implements Action { + @Nullable + private final Condition condition; + + public ConditionalAction(@Nullable Condition condition) { + this.condition = condition; + } + + @Nullable + public Condition getCondition() { + return condition; + } +} diff --git a/src/main/java/io/rpg/model/actions/DialogueAction.java b/src/main/java/io/rpg/model/actions/DialogueAction.java index 153c5827..e3a64a6e 100644 --- a/src/main/java/io/rpg/model/actions/DialogueAction.java +++ b/src/main/java/io/rpg/model/actions/DialogueAction.java @@ -1,15 +1,17 @@ package io.rpg.model.actions; +import io.rpg.model.actions.condition.Condition; import javafx.scene.image.Image; /** * Class for storing local data needed to perform a dialogue action. */ -public class DialogueAction implements Action { +public class DialogueAction extends ConditionalAction { public final String text; public final Image image; - public DialogueAction(String text, Image image) { + public DialogueAction(String text, Image image, Condition condition) { + super(condition); this.text = text; this.image = image; } diff --git a/src/main/java/io/rpg/model/actions/GameEndAction.java b/src/main/java/io/rpg/model/actions/GameEndAction.java index e6b098e0..08dc5840 100644 --- a/src/main/java/io/rpg/model/actions/GameEndAction.java +++ b/src/main/java/io/rpg/model/actions/GameEndAction.java @@ -1,9 +1,12 @@ package io.rpg.model.actions; -public class GameEndAction implements Action { +import io.rpg.model.actions.condition.Condition; + +public class GameEndAction extends ConditionalAction { public final String description; - public GameEndAction(String description) { + public GameEndAction(String description, Condition condition) { + super(condition); this.description = description; } } diff --git a/src/main/java/io/rpg/model/actions/LocationChangeAction.java b/src/main/java/io/rpg/model/actions/LocationChangeAction.java index c33b6d1c..2a1fbbf0 100644 --- a/src/main/java/io/rpg/model/actions/LocationChangeAction.java +++ b/src/main/java/io/rpg/model/actions/LocationChangeAction.java @@ -1,5 +1,6 @@ package io.rpg.model.actions; +import io.rpg.model.actions.condition.Condition; import io.rpg.model.data.Position; import javafx.geometry.Point2D; @@ -7,16 +8,18 @@ * Class for storing local data needed to preform a location change action. */ -public class LocationChangeAction implements Action { +public class LocationChangeAction extends ConditionalAction { public final String destinationLocationTag; public final Point2D playerPosition; - public LocationChangeAction(String destinationLocationTag, Position playerPosition) { + public LocationChangeAction(String destinationLocationTag, Position playerPosition, Condition condition) { + super(condition); this.destinationLocationTag = destinationLocationTag; this.playerPosition = new Point2D(playerPosition.col, playerPosition.row); } - public LocationChangeAction(String destinationLocationTag, Point2D playerPosition) { + public LocationChangeAction(String destinationLocationTag, Point2D playerPosition, Condition condition) { + super(condition); this.destinationLocationTag = destinationLocationTag; this.playerPosition = playerPosition; } diff --git a/src/main/java/io/rpg/model/actions/QuizAction.java b/src/main/java/io/rpg/model/actions/QuizAction.java index 6561c81a..6fc7913d 100644 --- a/src/main/java/io/rpg/model/actions/QuizAction.java +++ b/src/main/java/io/rpg/model/actions/QuizAction.java @@ -1,17 +1,19 @@ package io.rpg.model.actions; +import io.rpg.model.actions.condition.Condition; import io.rpg.model.object.Question; /** * Class for storing local data needed to preform a quiz action. */ -public class QuizAction implements Action { +public class QuizAction extends ConditionalAction { public final Question question; private int pointsToEarn; - public QuizAction(Question question) { + public QuizAction(Question question, Condition condition) { + super(condition); this.question = question; this.pointsToEarn = 10; } diff --git a/src/main/java/io/rpg/model/actions/ShowDescriptionAction.java b/src/main/java/io/rpg/model/actions/ShowDescriptionAction.java index 1ef5aa77..5f667580 100644 --- a/src/main/java/io/rpg/model/actions/ShowDescriptionAction.java +++ b/src/main/java/io/rpg/model/actions/ShowDescriptionAction.java @@ -1,15 +1,17 @@ package io.rpg.model.actions; +import io.rpg.model.actions.condition.Condition; import javafx.scene.image.Image; /** * Class for storing local data needed to perform a show description action. */ -public class ShowDescriptionAction implements Action { +public class ShowDescriptionAction extends ConditionalAction { public final String description; public final Image image; - public ShowDescriptionAction(String description, Image image) { + public ShowDescriptionAction(String description, Image image, Condition condition) { + super(condition); this.description = description; this.image = image; } diff --git a/src/main/java/io/rpg/model/actions/condition/Condition.java b/src/main/java/io/rpg/model/actions/condition/Condition.java new file mode 100644 index 00000000..38766595 --- /dev/null +++ b/src/main/java/io/rpg/model/actions/condition/Condition.java @@ -0,0 +1,24 @@ +package io.rpg.model.actions.condition; + +import io.rpg.model.actions.ConditionType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class Condition { + + @NotNull + private final ConditionType type; + + public Condition(@NotNull ConditionType type) { + //noinspection ConstantConditions + assert type != null; + this.type = type; + } + + @NotNull + public ConditionType getType() { + return type; + } + + public abstract boolean acceptEngine(final ConditionEngine engine); +} diff --git a/src/main/java/io/rpg/model/actions/condition/ConditionEngine.java b/src/main/java/io/rpg/model/actions/condition/ConditionEngine.java new file mode 100644 index 00000000..e07a5194 --- /dev/null +++ b/src/main/java/io/rpg/model/actions/condition/ConditionEngine.java @@ -0,0 +1,26 @@ +package io.rpg.model.actions.condition; + +import io.rpg.controller.Controller; + +import java.lang.ref.WeakReference; + +public class ConditionEngine { + private final WeakReference weakRefControler; + + public ConditionEngine(final Controller controller) { + this.weakRefControler = new WeakReference<>(controller); + } + + public boolean evaluateItemRequiredCondition(ItemRequiredCondition itemRequiredCondition) { + // TODO: Implement this when the inventory gets implemented. + // Scheme: +// return weakRefControler +// .get() +// .getPlayerController() +// .getPlayer() +// .getInventory() +// .getItems() +// .containsItemForTag(itemRequiredCondition.getItemTag()); + return true; + } +} diff --git a/src/main/java/io/rpg/model/actions/condition/ConditionFactory.java b/src/main/java/io/rpg/model/actions/condition/ConditionFactory.java new file mode 100644 index 00000000..b7361ea2 --- /dev/null +++ b/src/main/java/io/rpg/model/actions/condition/ConditionFactory.java @@ -0,0 +1,25 @@ +package io.rpg.model.actions.condition; + +import io.rpg.config.model.ConditionConfigBundle; +import org.jetbrains.annotations.Nullable; + +public class ConditionFactory { + @Nullable + public static Condition fromConfig(ConditionConfigBundle config) { + if (config == null) { + return null; + } + + // config was validated + //noinspection ConstantConditions + switch (config.getType()) { + case ITEM_REQUIRED -> { return itemRequiredFromConfig(config); } + default -> throw new IllegalArgumentException("Not implemented condition type: " + config.getType().toString()); + } + } + + private static ItemRequiredCondition itemRequiredFromConfig(ConditionConfigBundle config) { + assert config.getItemTag() != null; + return new ItemRequiredCondition(config.getItemTag()); + } +} diff --git a/src/main/java/io/rpg/model/actions/condition/ItemRequiredCondition.java b/src/main/java/io/rpg/model/actions/condition/ItemRequiredCondition.java new file mode 100644 index 00000000..c9b97753 --- /dev/null +++ b/src/main/java/io/rpg/model/actions/condition/ItemRequiredCondition.java @@ -0,0 +1,25 @@ +package io.rpg.model.actions.condition; + +import io.rpg.model.actions.ConditionType; +import org.jetbrains.annotations.NotNull; + +public class ItemRequiredCondition extends Condition { + + @NotNull + private final String requiredItemTag; + + public ItemRequiredCondition(@NotNull final String tag) { + super(ConditionType.ITEM_REQUIRED); + this.requiredItemTag = tag; + } + + @Override + public boolean acceptEngine(ConditionEngine engine) { + return engine.evaluateItemRequiredCondition(this); + } + + @NotNull + public String getItemTag() { + return requiredItemTag; + } +} diff --git a/src/main/java/io/rpg/model/location/LocationModel.java b/src/main/java/io/rpg/model/location/LocationModel.java index 0806e10e..833525cb 100644 --- a/src/main/java/io/rpg/model/location/LocationModel.java +++ b/src/main/java/io/rpg/model/location/LocationModel.java @@ -171,7 +171,7 @@ private void emitBoundCrossedAction(GameObject gameObject, Point2D boundsCrossed } String location = directionToLocationMap.get(direction); - LocationChangeAction action = new LocationChangeAction(location, nextPosition); + LocationChangeAction action = new LocationChangeAction(location, nextPosition, null); emitAction(action); } diff --git a/src/main/java/io/rpg/util/ActionFactory.java b/src/main/java/io/rpg/util/ActionFactory.java index 0385eac1..392bad06 100644 --- a/src/main/java/io/rpg/util/ActionFactory.java +++ b/src/main/java/io/rpg/util/ActionFactory.java @@ -2,6 +2,7 @@ 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; @@ -43,27 +44,31 @@ public static Action fromConfig(ActionConfigBundle config) { private static QuizAction quizActionFromConfig(ActionConfigBundle config) { // TODO: as for now only one question is handled but the config API // is capable of handling more than one! - return new QuizAction(config.getQuestions().get(0)); + return new QuizAction(config.getQuestions().get(0), ConditionFactory.fromConfig(config.getCondition())); } private static GameEndAction gameEndActionFromConfig(ActionConfigBundle config) { - return new GameEndAction(config.getDescription()); + return new GameEndAction(config.getDescription(), ConditionFactory.fromConfig(config.getCondition())); } private static DialogueAction dialogueActionFromConfig(ActionConfigBundle config) { // TODO: Move Image creation inside DialogueAction? Idk tbh. - return new DialogueAction(config.getDialogueStatements().get(0), new Image("file:" + config.getAssetPath())); + return new DialogueAction(config.getDialogueStatements().get(0), + new Image("file:" + config.getAssetPath()), ConditionFactory.fromConfig(config.getCondition())); } private static LocationChangeAction locationChangeActionFromConfig(ActionConfigBundle config) { - return new LocationChangeAction(config.getTargetLocationTag(), config.getTargetPosition()); + return new LocationChangeAction(config.getTargetLocationTag(), config.getTargetPosition(), + ConditionFactory.fromConfig(config.getCondition())); } private static ShowDescriptionAction showDescriptionActionFromConfig(ActionConfigBundle config) { - return new ShowDescriptionAction(config.getDescription(), new Image("file:" + config.getAssetPath())); + return new ShowDescriptionAction(config.getDescription(), new Image("file:" + config.getAssetPath()), + ConditionFactory.fromConfig(config.getCondition())); } private static BattleAction battleActionFromConfig(ActionConfigBundle config) { - return new BattleAction(config.getRewardPoints()); + return new BattleAction(config.getRewardPoints(), + ConditionFactory.fromConfig(config.getCondition())); } } diff --git a/src/main/java/io/rpg/util/GameObjectFactory.java b/src/main/java/io/rpg/util/GameObjectFactory.java index 362656f3..54f0f421 100644 --- a/src/main/java/io/rpg/util/GameObjectFactory.java +++ b/src/main/java/io/rpg/util/GameObjectFactory.java @@ -33,7 +33,8 @@ public static GameObject fromConfig(GameObjectConfig config) { DataObjectDescriptionProvider.combineDescriptions( DataObjectDescriptionProvider.getFieldDescription(config, GameObjectConfig.class) ), - new Image("file:" + config.getAssetPath()) + new Image("file:" + config.getAssetPath()), + null ); }