Skip to content

Commit

Permalink
feat: allow for before & after actions configuration (#79)
Browse files Browse the repository at this point in the history
* bookmark: @kkafar/before-and-after-actions begin

* feat: allow for before- and after-action configruation

* fix: implement missing getters

* chore: handle case when before- || after-actions are not specified

* chore: update config

* chore: add better action validation

* fix: unresponsive buttons

* fix: layout calculations

* fix: defer call to emitAction while calculating animations

* docs: update

* chore: update docs

* chore: remove souts

* refact: remove commented code

* refact: mage get{Before/After}Action return Optional
  • Loading branch information
kkafar authored Jun 4, 2022
1 parent 1dcb9c8 commit 96b522f
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
{
"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"}
"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",
"before": {
"tag": "message",
"type": "show-description",
"description": "Hurra, you are about to pickup a key!",
"assetPath": "assets/key.png"
},
"after": {
"tag": "followup-message",
"type": "show-description",
"description": "Hurra, the key was picked up!",
"assetPath": "assets/key.png"
}
}
}
6 changes: 3 additions & 3 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ following props:
* `locations` - List of location tags. All the locations specified in `locations` are loaded, however this field is left
for backward-compatibility.
* `player` - Player object specification. It follows the `GameObject` specification
rules. (TODO: add hyperlink to that section)
rules. See [game object configuration][#game-object-configuration]
* `rootLocation` - `tag` of first-to-be-displayed location.
* `textPopupBackground` - Url of a picture to be used as a background for all TextPopups
* `textPopupButton` - Url of a picture to be used as a button image for all TextPopups
Expand Down Expand Up @@ -181,9 +181,9 @@ common part first. Each action consists of following properties
* *(optional)* `condition` - Condition configuration. The action won't be executed until the condition is satisfied.
Aliases: `requires`. See [condition configuration](#condition-configuration)
* *(optional)* `before` - Configuration of action to be triggered before the proper action is executed.
e.g. you may want to change location before starting the dialogue. (TODO: Logic is not implemented as for now).
e.g. you may want to change location before starting the dialogue.
* *(optional)* `after` - Configuration of action to be triggered after the proper action is executed, e.g. you may want
give player some output or item. (TODO: Logic is not implemented as for now).
give player some output or item.

Let's look at specific action types:

Expand Down
14 changes: 14 additions & 0 deletions src/main/java/io/rpg/config/model/ActionConfigBundle.java
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,20 @@ public Result<Void, Exception> validate() {
return result;
}

if (beforeAction != null) {
result = beforeAction.validate();
if (result.isErr()) {
return result;
}
}

if (afterAction != null) {
result = afterAction.validate();
if (result.isErr()) {
return result;
}
}

// actionType can not be null here, guaranteed by validateBasic method
//noinspection ConstantConditions
switch (actionType) {
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/io/rpg/config/model/GameObjectConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,16 @@ public Result<Void, Exception> validate() {
builder.append("No position provided");
}

if (onRightClick != null) {
onRightClick.validate().ifErr(err -> builder.combine(err.getMessage()));
}
if (onLeftClick != null) {
onLeftClick.validate().ifErr(err -> builder.combine(err.getMessage()));
}
if (onApproach != null) {
onApproach.validate().ifErr(err -> builder.combine(err.getMessage()));
}

return builder.isEmpty() ? Result.ok() : Result.err(new Exception(builder.toString()));
}

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/io/rpg/controller/Controller.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ public void consumeAction(Action action) {
return;
}

logger.info("Consuming action");

action.acceptActionEngine(actionEngine);
}

Expand Down
60 changes: 38 additions & 22 deletions src/main/java/io/rpg/controller/PopupController.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,33 @@ public PopupController() {
});
}

public void openTextPopup(String text, int x, int y){
public void openTextPopup(String text, int x, int y) {
TextPopup popupScene = new TextPopup(text);
popupStage.setScene(popupScene);

popupStage.show();

popupStage.setX(x - popupScene.getWidth() / 2);
popupStage.setY(y - popupScene.getHeight() / 2);

popupScene.setButtonCallback(event -> popupStage.hide());

popupStage.onShownProperty().setValue(event -> {
popupStage.setX(x - popupScene.getWidth() / 2);
popupStage.setY(y - popupScene.getHeight() / 2);
});
if (!popupStage.isShowing()) {
popupStage.showAndWait();
}
}

public void openTextImagePopup(String text, Image image, int x, int y){
public void openTextImagePopup(String text, Image image, int x, int y) {
TextImagePopup popupScene = new TextImagePopup(text, image);
popupStage.setScene(popupScene);

popupStage.show();

popupStage.setX(x - popupScene.getWidth() / 2);
popupStage.setY(y - popupScene.getHeight() / 2);

popupScene.setButtonCallback(event -> popupStage.hide());
popupStage.onShownProperty().setValue(event -> {
popupStage.setX(x - popupScene.getWidth() / 2);
popupStage.setY(y - popupScene.getHeight() / 2);
});
if (!popupStage.isShowing()) {
popupStage.showAndWait();
}
}

public void openPointsPopup(int pointsCount, int x, int y) {
Expand All @@ -56,29 +61,40 @@ public void openQuestionPopup(Question question, int x, int y, Runnable successC
popupScene.setSuccessCallback(successCallback);
popupScene.setFailureCallback(failureCallback);
popupStage.setScene(popupScene);
popupStage.show();
popupStage.setX(x - popupScene.getWidth() / 2);
popupStage.setY(y - popupScene.getHeight() / 2);
popupStage.onShownProperty().setValue(event -> {
popupStage.setX(x - popupScene.getWidth() / 2);
popupStage.setY(y - popupScene.getHeight() / 2);
});
if (!popupStage.isShowing()) {
popupStage.showAndWait();
}
}

public void openQuestionPopup(Question question, int x, int y) {
QuestionPopup popupScene = new QuestionPopup(question);
popupStage.setScene(popupScene);
popupStage.show();
popupStage.setX(x - popupScene.getWidth() / 2);
popupStage.setY(y - popupScene.getHeight() / 2);
popupStage.onShownProperty().setValue(event -> {
popupStage.setX(x - popupScene.getWidth() / 2);
popupStage.setY(y - popupScene.getHeight() / 2);
});
if (!popupStage.isShowing()) {
popupStage.showAndWait();
}
}

public void openDialoguePopup(String text, Image npcImage, int x, int y) {
DialoguePopup popupScene = new DialoguePopup(text, npcImage);
popupStage.setScene(popupScene);

popupStage.show();

popupStage.setX(x - popupScene.getWidth() / 2);
popupStage.setY(y - popupScene.getHeight() / 2);
popupStage.onShownProperty().setValue(event -> {
popupStage.setX(x - popupScene.getWidth() / 2);
popupStage.setY(y - popupScene.getHeight() / 2);
});

popupScene.setCloseButtonCallback(event -> popupStage.hide());
if (!popupStage.isShowing()) {
popupStage.showAndWait();
}
}


Expand Down
31 changes: 31 additions & 0 deletions src/main/java/io/rpg/model/actions/Action.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import io.rpg.model.object.GameObject;
import org.jetbrains.annotations.Nullable;

import java.util.Optional;

/**
* A marker interface for action classes.
*/
Expand All @@ -22,6 +24,26 @@ public void setEmitter(GameObject emitter) {
public @Nullable GameObject getEmitter() {
return null;
}

@Override
public void setBeforeAction(Action action) {
/* noop */
}

@Override
public void setAfterAction(Action action) {
/* noop */
}

@Override
public Optional<Action> getBeforeAction() {
return Optional.empty();
}

@Override
public Optional<Action> getAfterAction() {
return Optional.empty();
}
};

void acceptActionEngine(final ActionEngine engine);
Expand All @@ -30,4 +52,13 @@ public void setEmitter(GameObject emitter) {

@Nullable
GameObject getEmitter();

void setBeforeAction(Action action);

void setAfterAction(Action action);

Optional<Action> getBeforeAction();

@Nullable
Optional<Action> getAfterAction();
}
2 changes: 1 addition & 1 deletion src/main/java/io/rpg/model/actions/ActionEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import io.rpg.model.object.Player;
import io.rpg.util.BattleResult;
import io.rpg.view.LocationView;
import javafx.application.Platform;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -83,7 +84,6 @@ public void acceptQuizResult(boolean correct, int pointsCount) {
var controller = controller();
if (correct) {
controller.getPlayerController().addPoints(pointsCount);
controller.getPopupController().hidePopup();
if (pointsCount > 0)
controller.getPopupController().openPointsPopup(pointsCount, controller.getWindowCenterX(), controller.getWindowCenterY());
} else {
Expand Down
29 changes: 28 additions & 1 deletion src/main/java/io/rpg/model/actions/BaseAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,23 @@

import io.rpg.model.actions.condition.Condition;
import io.rpg.model.object.GameObject;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Optional;

public abstract class BaseAction implements Action {
@Nullable
private final Condition condition;

@Nullable
private GameObject emitter;

@Nullable
private Action afterAction;

@Nullable
private Action beforeAction;

public BaseAction(@Nullable Condition condition) {
this.condition = condition;
}
Expand All @@ -29,4 +36,24 @@ public void setEmitter(GameObject emitter) {
public GameObject getEmitter() {
return emitter;
}

@Override
public void setAfterAction(Action action) {
afterAction = action;
}

@Override
public void setBeforeAction(Action action) {
beforeAction = action;
}

@Override
public Optional<Action> getBeforeAction() {
return Optional.ofNullable(beforeAction);
}

@Override
public Optional<Action> getAfterAction() {
return Optional.ofNullable(afterAction);
}
}
2 changes: 2 additions & 0 deletions src/main/java/io/rpg/model/actions/BaseActionEmitter.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ public abstract class BaseActionEmitter implements ActionEmitter {
private ActionConsumer consumer = (a) -> {};

protected void emitAction(Action action) {
action.getBeforeAction().ifPresent(a -> consumer.consumeAction(a));
consumer.consumeAction(action);
action.getAfterAction().ifPresent(a -> consumer.consumeAction(a));
}

@Override
Expand Down
17 changes: 13 additions & 4 deletions src/main/java/io/rpg/model/object/GameObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import io.rpg.model.data.GameObjectStateChange;
import io.rpg.model.data.Position;
import io.rpg.util.DataObjectDescriptionProvider;
import javafx.application.Platform;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Point2D;
Expand Down Expand Up @@ -116,12 +117,12 @@ public void setPosition(Position playerPosition) {

public void setOnRightClickAction(@NotNull Action onRightClickAction) {
this.onRightClickAction = onRightClickAction;
this.onRightClickAction.setEmitter(this);
setThisAsEmitter(this.onRightClickAction);
}

public void setOnLeftClickAction(@NotNull Action onLeftClickAction) {
this.onLeftClickAction = onLeftClickAction;
this.onLeftClickAction.setEmitter(this);
setThisAsEmitter(this.onLeftClickAction);
}

public void onRightClick() {
Expand All @@ -141,11 +142,19 @@ public void onApproach() {
return;
}
wasOnApproachFired = true;
emitAction(onApproach);
Platform.runLater(() -> emitAction(onApproach));
}

public void setOnApproach(Action onApproach) {
this.onApproach = onApproach;
this.onApproach.setEmitter(this);
setThisAsEmitter(this.onApproach);
}

private void setThisAsEmitter(Action action) {
if (action != null) {
action.setEmitter(this);
action.getAfterAction().ifPresent(a -> a.setEmitter(this));
action.getBeforeAction().ifPresent(a -> a.setEmitter(this));
}
}
}
17 changes: 17 additions & 0 deletions src/main/java/io/rpg/util/ActionFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ public static Action fromConfig(ActionConfigBundle config) {
assert config.getActionType() != null : "Null action type! Make sure to call validation " +
"method after the config object is inflated from JSON!";

Action result = actionByType(config);
initBeforeAndAfterActions(result, config);

return result;
}

private static Action actionByType(ActionConfigBundle config) {
switch (config.getActionType()) {
case Quiz -> {
return quizActionFromConfig(config);
Expand All @@ -43,6 +50,7 @@ public static Action fromConfig(ActionConfigBundle config) {
throw new IllegalArgumentException("Unexpected action type!");
}
}

}

private static QuizAction quizActionFromConfig(ActionConfigBundle config) {
Expand Down Expand Up @@ -75,4 +83,13 @@ private static BattleAction battleActionFromConfig(ActionConfigBundle config) {
return new BattleAction(config.getRewardPoints(),
ConditionFactory.fromConfig(config.getCondition()));
}

private static void initBeforeAndAfterActions(Action action, ActionConfigBundle config) {
if (config.getBeforeAction() != null) {
action.setBeforeAction(actionByType(config.getBeforeAction()));
}
if (config.getAfterAction() != null) {
action.setAfterAction(actionByType(config.getAfterAction()));
}
}
}

0 comments on commit 96b522f

Please sign in to comment.