From dd0b867363035c54bb513824de3079e1a34e08f5 Mon Sep 17 00:00:00 2001
From: =
Date: Sat, 23 May 2026 15:08:15 +0200
Subject: [PATCH 01/22] Feat: Added main minigames page
---
.../ntnu/idi/idatt2003/g40/mappe/Main.java | 13 +-
.../widgets/minigames/MiniGamesActions.java | 26 ++++
.../minigames/MiniGamesController.java | 62 +++++++++
.../view/widgets/minigames/MiniGamesView.java | 120 ++++++++++++++++++
.../view/widgets/topbar/TopBarActions.java | 3 +-
.../view/widgets/topbar/TopBarController.java | 34 ++++-
.../mappe/view/widgets/topbar/TopBarView.java | 11 +-
src/main/resources/styles.css | 65 +++++++++-
8 files changed, 326 insertions(+), 8 deletions(-)
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesActions.java
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesController.java
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
index 0e2d3cb..5453765 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
@@ -25,6 +25,8 @@
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.dashboard.DashBoardView;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.market.MarketController;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.market.MarketView;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.MiniGamesController;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.MiniGamesView;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.stats.StatsController;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.stats.StatsView;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.topbar.TopBarController;
@@ -139,6 +141,13 @@ public void start(final Stage stage) throws Exception {
eventManager,
player.getTransactionArchive());
+ MiniGamesView miniGamesView = new MiniGamesView();
+ new MiniGamesController(
+ miniGamesView,
+ eventManager,
+ stocksInFile.getFirst()
+ );
+
// Wire top bar buttons til å bytte mellom dashboard / stats / market /
// transactions. Stats-knappen tar deg til stats-siden.
topBarController.setMarketIntegration(
@@ -147,7 +156,9 @@ public void start(final Stage stage) throws Exception {
marketView.getRootPane(),
statsView.getRootPane(),
transactionsView.getRootPane(),
- transactionsController::refresh);
+ transactionsController::refresh,
+ miniGamesView.getRootPane()
+ );
// Register all views
viewManager.addView(mainMenuView);
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesActions.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesActions.java
new file mode 100644
index 0000000..d2c4de6
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesActions.java
@@ -0,0 +1,26 @@
+package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames;
+
+/**
+ * Action set for the associated {@link MiniGamesView}.
+ * */
+public enum MiniGamesActions {
+ /**
+ * Action when selecting clicker game.
+ * */
+ CLICKER_GAME,
+
+ /**
+ * Action when selecting "find stock" game.
+ * */
+ FIND_STOCK,
+
+ /**
+ * Action when selecting "time click" game.
+ * */
+ TIME_CLICKS,
+
+ /**
+ * Action when clicking the question mark box (help section).
+ * */
+ HELP
+}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesController.java
new file mode 100644
index 0000000..1ebb07a
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesController.java
@@ -0,0 +1,62 @@
+package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames;
+
+import edu.ntnu.idi.idatt2003.g40.mappe.model.Stock;
+import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventManager;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewController;
+
+/**
+ * Controller class for the associated {@link MiniGamesView} object.
+ *
+ * Extends {@link ViewController}
+ * */
+public final class MiniGamesController extends ViewController {
+ private Stock activeStock;
+
+ public MiniGamesController(final MiniGamesView viewElement,
+ final EventManager eventManager,
+ final Stock initialStock) {
+ super(viewElement, eventManager);
+ this.activeStock = initialStock;
+ refresh();
+ }
+
+ @Override
+ protected void initInteractions() {
+ getViewElement().setOnAction(MiniGamesActions.HELP, () -> {
+ // Implement help dialog or print logic
+ });
+
+ getViewElement().setOnAction(MiniGamesActions.CLICKER_GAME, () -> {
+ // Logic for launching Clicker Game
+ });
+
+ getViewElement().setOnAction(MiniGamesActions.FIND_STOCK, () -> {
+ // Logic for launching Find Stock Game
+ });
+
+ getViewElement().setOnAction(MiniGamesActions.TIME_CLICKS, () -> {
+ // Logic for launching Time Clicks Game
+ });
+ }
+
+ /**
+ * Sets the target stock context for the minigames.
+ *
+ * @param stock Chosen active layout context stock.
+ */
+ public void setActiveStock(final Stock stock) {
+ this.activeStock = stock;
+ refresh();
+ }
+
+ /**
+ * Syncs the current model status with view text properties.
+ */
+ public void refresh() {
+ if (activeStock != null) {
+ getViewElement().setSelectedStockText(activeStock.getSymbol());
+ } else {
+ getViewElement().setSelectedStockText("None");
+ }
+ }
+}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java
new file mode 100644
index 0000000..5d9ac4d
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java
@@ -0,0 +1,120 @@
+package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames;
+
+import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewElement;
+import javafx.geometry.Pos;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.Region;
+import javafx.scene.layout.VBox;
+
+/**
+ * Minigames view in the in game section of the application.
+ * */
+public final class MiniGamesView extends ViewElement {
+
+ private HBox headerBar;
+ private HBox gamesContainer;
+
+ private Label titleLabel;
+ private Label selectedStockLabel;
+ private Label stockValueLabel;
+
+ private Button helpBtn;
+ private Button clickerGameBtn;
+ private Button findStockBtn;
+ private Button timeClicksBtn;
+
+ /**
+ * Constructor.
+ */
+ public MiniGamesView() throws IllegalArgumentException {
+ super(new VBox(), MiniGamesActions.class);
+ }
+
+ @Override
+ protected void initLayout() {
+ // Top header layout
+ headerBar = new HBox();
+ headerBar.setAlignment(Pos.TOP_LEFT);
+
+ VBox titleSection = new VBox();
+ titleLabel = new Label("Mini games");
+
+ HBox stockSelectionRow = new HBox();
+ stockSelectionRow.setAlignment(Pos.CENTER_LEFT);
+ selectedStockLabel = new Label("Selected stock: ");
+ stockValueLabel = new Label("AAPL");
+ stockSelectionRow.getChildren().addAll(selectedStockLabel, stockValueLabel);
+
+ titleSection.getChildren().addAll(titleLabel, stockSelectionRow);
+
+ Region topSpacer = new Region();
+ HBox.setHgrow(topSpacer, Priority.ALWAYS);
+
+ helpBtn = new Button("?");
+ headerBar.getChildren().addAll(titleSection, topSpacer, helpBtn);
+
+ // Main central row container for games
+ gamesContainer = new HBox();
+ gamesContainer.setAlignment(Pos.CENTER);
+
+ clickerGameBtn = new Button("Clicker game");
+ findStockBtn = new Button("Find correct\nstock");
+ timeClicksBtn = new Button("Time your clicks");
+
+ // Make buttons fill equal proportions
+ HBox.setHgrow(clickerGameBtn, Priority.ALWAYS);
+ HBox.setHgrow(findStockBtn, Priority.ALWAYS);
+ HBox.setHgrow(timeClicksBtn, Priority.ALWAYS);
+
+ // Equal constraints on dimensions
+ configureGameButton(clickerGameBtn);
+ configureGameButton(findStockBtn);
+ configureGameButton(timeClicksBtn);
+
+ gamesContainer.getChildren().addAll(clickerGameBtn, findStockBtn, timeClicksBtn);
+
+ // Assemble view layers
+ VBox.setVgrow(gamesContainer, Priority.ALWAYS);
+ getRootPane().getChildren().addAll(headerBar, gamesContainer);
+
+ // Map interactions
+ registerButton(MiniGamesActions.HELP, helpBtn);
+ registerButton(MiniGamesActions.CLICKER_GAME, clickerGameBtn);
+ registerButton(MiniGamesActions.FIND_STOCK, findStockBtn);
+ registerButton(MiniGamesActions.TIME_CLICKS, timeClicksBtn);
+ }
+
+ private void configureGameButton(final Button btn) {
+ btn.setMaxWidth(Double.MAX_VALUE);
+ btn.setMaxHeight(Double.MAX_VALUE);
+ btn.setAlignment(Pos.CENTER);
+ }
+
+ /**
+ * Updates the selected stock text.
+ *
+ * @param symbol the symbol representing the stock selected.
+ */
+ public void setSelectedStockText(final String symbol) {
+ stockValueLabel.setText(symbol);
+ }
+
+ @Override
+ protected void initStyling() {
+ getRootPane().getStyleClass().add("minigames-root");
+ headerBar.getStyleClass().add("minigames-headerBar");
+ titleLabel.getStyleClass().add("minigames-titleLabel");
+ selectedStockLabel.getStyleClass().add("minigames-stockLabel");
+ stockValueLabel.getStyleClass().add("minigames-stockValue");
+
+ helpBtn.getStyleClass().add("minigames-helpBtn");
+ gamesContainer.getStyleClass().add("minigames-container");
+
+ clickerGameBtn.getStyleClass().add("minigames-cardBtn");
+ findStockBtn.getStyleClass().add("minigames-cardBtn");
+ timeClicksBtn.getStyleClass().add("minigames-cardBtn");
+ }
+}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarActions.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarActions.java
index 9b71268..6f07799 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarActions.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarActions.java
@@ -5,5 +5,6 @@ public enum TopBarActions {
STATS,
MARKET,
SETTINGS,
- TRANSACTIONS;
+ TRANSACTIONS,
+ MINIGAMES;
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarController.java
index 86c5d2d..051368d 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarController.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarController.java
@@ -39,6 +39,17 @@ public class TopBarController extends ViewController {
*/
private boolean inTransactionsView = false;
+ /**
+ * Whether the minigames screen is currently the active center-view.
+ *
+ *
+ * When true, the quit/back button returns to the dashboard instead
+ * of exiting to the main menu.
+ *
+ */
+ private boolean inMinigamesView = false;
+
+
/**
* {@inheritDoc}.
*/
@@ -83,20 +94,27 @@ protected void initInteractions() {
* @param statsCenter root pane of the stats widget.
* @param transactionsCenter root pane of the transactions widget.
* @param onTransactionUpdate callback invoked when entering transactions.
+ * @param minigamesCenter root pane of the minigames widget.
*/
public void setMarketIntegration(final Consumer centerSwitcher,
final Node dashboardCenter,
final Node marketCenter,
final Node statsCenter,
final Node transactionsCenter,
- final Runnable onTransactionUpdate) {
+ final Runnable onTransactionUpdate,
+ final Node minigamesCenter
+ ) {
getViewElement().setOnAction(TopBarActions.EXIT, () -> {
- if (inMarketView || inStatsView || inTransactionsView) {
+ if (inMarketView
+ || inStatsView
+ || inTransactionsView
+ || inMinigamesView) {
centerSwitcher.accept(dashboardCenter);
getViewElement().setQuitText("Quit");
inMarketView = false;
inStatsView = false;
inTransactionsView = false;
+ inMinigamesView = false;
} else {
changeScene(ViewEnum.MAIN_MENU);
}
@@ -108,6 +126,7 @@ public void setMarketIntegration(final Consumer centerSwitcher,
inMarketView = false;
inStatsView = true;
inTransactionsView = false;
+ inMinigamesView = false;
});
getViewElement().setOnAction(TopBarActions.MARKET, () -> {
@@ -116,6 +135,7 @@ public void setMarketIntegration(final Consumer centerSwitcher,
inMarketView = true;
inStatsView = false;
inTransactionsView = false;
+ inMinigamesView = false;
});
getViewElement().setOnAction(TopBarActions.TRANSACTIONS, () -> {
@@ -125,6 +145,16 @@ public void setMarketIntegration(final Consumer centerSwitcher,
inMarketView = false;
inStatsView = false;
inTransactionsView = true;
+ inMinigamesView = false;
+ });
+
+ getViewElement().setOnAction(TopBarActions.MINIGAMES, () -> {
+ centerSwitcher.accept(minigamesCenter);
+ getViewElement().setQuitText("Back");
+ inMarketView = false;
+ inStatsView = false;
+ inTransactionsView = false;
+ inMinigamesView = true;
});
}
}
\ No newline at end of file
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarView.java
index 30f0259..3be0fcf 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarView.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarView.java
@@ -17,6 +17,7 @@ public class TopBarView extends ViewElement {
private Button marketBtn;
private Button settingsBtn;
private Button transactionsBtn;
+ private Button minigamesBtn;
private SummaryView summaryView;
@@ -48,8 +49,10 @@ protected void initLayout() {
marketBtn = new Button("Market");
settingsBtn = new Button("Settings");
transactionsBtn = new Button("Transactions");
+ minigamesBtn = new Button("Minigames");
- Stream.of(quitBtn, statsBtn, marketBtn, settingsBtn, transactionsBtn).forEach(b -> {
+
+ Stream.of(quitBtn, statsBtn, marketBtn, settingsBtn, transactionsBtn, minigamesBtn).forEach(b -> {
HBox.setHgrow(b, Priority.ALWAYS);
});
@@ -58,7 +61,8 @@ protected void initLayout() {
statsBtn,
marketBtn,
settingsBtn,
- transactionsBtn
+ transactionsBtn,
+ minigamesBtn
);
if (summaryView != null) {
@@ -71,12 +75,13 @@ protected void initLayout() {
registerButton(TopBarActions.MARKET, marketBtn);
registerButton(TopBarActions.SETTINGS, settingsBtn);
registerButton(TopBarActions.TRANSACTIONS, transactionsBtn);
+ registerButton(TopBarActions.MINIGAMES, minigamesBtn);
}
@Override
protected void initStyling() {
getRootPane().getStyleClass().add("top-bar");
- Stream.of(quitBtn, statsBtn, marketBtn, settingsBtn, transactionsBtn)
+ Stream.of(quitBtn, statsBtn, marketBtn, settingsBtn, transactionsBtn, minigamesBtn)
.forEach(b -> b.getStyleClass().add("menu-button"));
}
diff --git a/src/main/resources/styles.css b/src/main/resources/styles.css
index 3b73285..de5dd5d 100644
--- a/src/main/resources/styles.css
+++ b/src/main/resources/styles.css
@@ -797,4 +797,67 @@
-fx-fit-to-height: true;
-fx-background: transparent;
-fx-background-color: transparent;
-}
\ No newline at end of file
+}
+/* -----------------------------------------------*/
+/* ------------------- MINIGAMES -----------------*/
+.minigames-root {
+ -fx-padding: 30px;
+ -fx-background-color: #e0e0e0;
+ -fx-spacing: 40px;
+}
+
+.minigames-headerBar {
+ -fx-padding: 10px 0px;
+}
+
+.minigames-titleLabel {
+ -fx-font-size: 48px;
+ -fx-font-family: "Aptos", "Segoe UI", sans-serif;
+ -fx-text-fill: #000000;
+}
+
+.minigames-stockLabel {
+ -fx-font-size: 24px;
+ -fx-text-fill: #000000;
+}
+
+.minigames-stockValue {
+ -fx-font-size: 24px;
+ -fx-text-fill: #000000;
+ -fx-border-color: #000000;
+ -fx-border-width: 1.5px;
+ -fx-padding: 2px 10px;
+ -fx-background-color: #d8d8d8;
+}
+
+.minigames-helpBtn {
+ -fx-font-size: 28px;
+ -fx-pref-width: 50px;
+ -fx-pref-height: 50px;
+ -fx-background-color: #d8d8d8;
+ -fx-border-color: #000000;
+ -fx-border-width: 1.5px;
+ -fx-text-fill: #000000;
+}
+
+.minigames-container {
+ -fx-spacing: 30px;
+ -fx-padding: 10px 0px;
+}
+
+.minigames-cardBtn {
+ -fx-background-color: #d8d8d8;
+ -fx-border-color: #000000;
+ -fx-border-width: 1.5px;
+ -fx-font-size: 32px;
+ -fx-text-fill: #000000;
+ -fx-text-alignment: center;
+ -fx-pref-height: 250px;
+ -fx-min-height: 200px;
+ -fx-max-width: 350px;
+}
+
+.minigames-cardBtn:hover, .minigames-helpBtn:hover {
+ -fx-background-color: #c0c0c0;
+}
+/* --------------------------------------------- */
\ No newline at end of file
From eacb10334103405cc4a581b39c8c38e6272fd029 Mon Sep 17 00:00:00 2001
From: =
Date: Sat, 23 May 2026 19:00:49 +0200
Subject: [PATCH 02/22] Fix: Update Action enum to be able to quit a minigame
---
.../g40/mappe/view/widgets/minigames/MiniGamesActions.java | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesActions.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesActions.java
index d2c4de6..2796967 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesActions.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesActions.java
@@ -22,5 +22,10 @@ public enum MiniGamesActions {
/**
* Action when clicking the question mark box (help section).
* */
- HELP
+ HELP,
+
+ /**
+ * Action called when quitting a minigame.
+ * */
+ INGAME_QUIT
}
From 625bbf5b1ab93b3ceb7c792ffa37d108dfedeb85 Mon Sep 17 00:00:00 2001
From: =
Date: Sat, 23 May 2026 19:02:06 +0200
Subject: [PATCH 03/22] Feat: Added GameGimmick interface
The interface will function as a content replacement option in the Strategy principle.
---
.../view/widgets/minigames/GameGimmick.java | 30 +++++++++++++++++++
1 file changed, 30 insertions(+)
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameGimmick.java
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameGimmick.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameGimmick.java
new file mode 100644
index 0000000..e1add25
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameGimmick.java
@@ -0,0 +1,30 @@
+package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames;
+
+import java.util.function.IntConsumer;
+import javafx.scene.Node;
+
+/**
+ * Strategy interface defining the central
+ * logic and layout for individual minigames.
+ */
+public interface GameGimmick {
+
+ /**
+ * Getter method for JavaFx root element of this gimmick.
+ *
+ * @return This games root as a {@link Node}
+ */
+ Node getCanvasNode();
+
+ /**
+ * Initializes the game behavior, wiring score changes back to the engine.
+ *
+ * @param scoreModifier Callback function to adjust the global score.
+ */
+ void initialize(IntConsumer scoreModifier);
+
+ /**
+ * Called on every frame tick (or second) by the main game loop.
+ */
+ void updateTick();
+}
From f7c5472808f1fdfdcf78458286329d178b5e4c73 Mon Sep 17 00:00:00 2001
From: =
Date: Sat, 23 May 2026 19:02:41 +0200
Subject: [PATCH 04/22] Added GameEngineView
The view acts as the context module in the Strategy design pattern.
---
.../widgets/minigames/GameEngineView.java | 79 +++++++++++++++++++
1 file changed, 79 insertions(+)
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineView.java
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineView.java
new file mode 100644
index 0000000..e18b372
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineView.java
@@ -0,0 +1,79 @@
+package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames;
+
+import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewElement;
+import javafx.geometry.Pos;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.HBox;
+
+import java.util.function.IntConsumer;
+
+public final class GameEngineView extends ViewElement {
+ private Button quitButton;
+ private Label scoreLabel;
+ private Label timerLabel;
+ private Label rankLabel;
+ private HBox topDashboardBar;
+ private int curScore;
+
+ public GameEngineView() {
+ super(new BorderPane(), MiniGamesActions.class);
+ }
+
+ @Override
+ protected void initLayout() {
+ quitButton = new Button("Quit");
+ quitButton.setPrefSize(100, 50);
+
+ scoreLabel = new Label("Score: 0");
+ timerLabel = new Label("00:00:60");
+ rankLabel = new Label("Rank: E");
+
+ HBox statsDisplay = new HBox(40, scoreLabel, timerLabel, rankLabel);
+ statsDisplay.setAlignment(Pos.CENTER);
+
+ topDashboardBar = new HBox(20, quitButton, statsDisplay);
+ topDashboardBar.setAlignment(Pos.CENTER_LEFT);
+ topDashboardBar.setPadding(new javafx.geometry.Insets(15));
+
+ getRootPane().setTop(topDashboardBar);
+ registerButton(MiniGamesActions.INGAME_QUIT, quitButton);
+ }
+
+ /**
+ * Method for updating the game per tick with score, time and rank.
+ *
+ * @param score the score to show.
+ * @param time the time to show.
+ * @param rank the rank to show.
+ * */
+ public void updateMetadataDisplay(final int score,
+ final String time,
+ final String rank) {
+ scoreLabel.setText("Score: " + score);
+ timerLabel.setText(time);
+ rankLabel.setText("Rank: " + rank);
+ }
+
+ /**
+ * Sets the content of this view based on the game provided through the
+ * {@link GameGimmick} interface.
+ *
+ * @param gimmick a concrete implementation of the {@link GameGimmick}
+ * interface
+ * */
+ public void setGameGimmickContent(final GameGimmick gimmick, final IntConsumer consumer) {
+ getRootPane().setCenter(gimmick.getCanvasNode());
+ gimmick.initialize(consumer);
+ }
+
+ @Override
+ protected void initStyling() {
+ getRootPane().setStyle("-fx-background-color: rgba(180, 180, 180, 0.85);");
+ topDashboardBar.setStyle("-fx-background-color: transparent;");
+ scoreLabel.setStyle("-fx-font-size: 24px; -fx-text-fill: black;");
+ timerLabel.setStyle("-fx-font-size: 24px; -fx-text-fill: black;");
+ rankLabel.setStyle("-fx-font-size: 24px; -fx-text-fill: black;");
+ }
+}
From 4da73008276b1bc07d97b6d9e6be13ce19a65989 Mon Sep 17 00:00:00 2001
From: =
Date: Sat, 23 May 2026 19:03:19 +0200
Subject: [PATCH 05/22] Feat: Added Clicker game functionality
---
.../widgets/minigames/games/ClickerGame.java | 92 +++++++++++++++++++
1 file changed, 92 insertions(+)
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/ClickerGame.java
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/ClickerGame.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/ClickerGame.java
new file mode 100644
index 0000000..f2d9f06
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/ClickerGame.java
@@ -0,0 +1,92 @@
+package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.games;
+
+import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewElement;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.GameGimmick;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.MiniGamesActions;
+import java.util.function.IntConsumer;
+import javafx.scene.Node;
+import javafx.scene.control.Button;
+import javafx.scene.layout.VBox;
+
+/**
+ * Clicker minigame, found in the
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.MiniGamesView}.
+ *
+ * Extends {@link ViewElement}
+ *
+ * Implements {@link GameGimmick}
+ * */
+public final class ClickerGame
+ extends ViewElement
+ implements GameGimmick {
+
+ /**
+ * The score to increase when clicking the main button.
+ * */
+ private int clickValue;
+
+ /**
+ * The current cost of upgrading the amount gained per click.
+ * */
+ private int upgradeCost;
+
+ /**
+ * The click button object.
+ * */
+ private Button clickBtn;
+
+ /**
+ * The upgrade button object.
+ * */
+ private Button upgradeBtn;
+
+ /**
+ * Constructor.
+ * */
+ public ClickerGame() {
+ super(new VBox(), MiniGamesActions.class);
+ }
+
+ @Override
+ protected void initLayout() {
+ clickValue = 1;
+ upgradeCost = 10;
+ clickBtn = new Button("+" + clickValue);
+ upgradeBtn = new Button("+" + clickValue + " per click\n-"
+ + upgradeCost + " points");
+ getRootPane().getChildren().addAll(clickBtn, upgradeBtn);
+ }
+
+ @Override
+ protected void initStyling() {
+ getRootPane().getStyleClass().add("clicker-minigame-root");
+ clickBtn.getStyleClass().add("clicker-minigame-clickBtn");
+ upgradeBtn.getStyleClass().add("clicker-minigame-upgradeBtn");
+ }
+
+ @Override
+ public Node getCanvasNode() {
+ return getRootPane();
+ }
+
+ @Override
+ public void initialize(final IntConsumer scoreModifier) {
+
+ clickBtn.setOnAction(e -> scoreModifier.accept(clickValue));
+
+ upgradeBtn.setOnAction(e -> {
+ // TODO: Change validation to only upgrade if enough score.
+ scoreModifier.accept(-upgradeCost);
+ clickValue += 1;
+ upgradeCost *= 2;
+ clickBtn.setText("+" + clickValue);
+ upgradeBtn.setText("+" + clickValue + " per click\n-"
+ + upgradeCost + " points");
+ });
+ }
+
+ @Override
+ public void updateTick() {
+ // No need to auto update information for this game.
+ }
+}
From 1607c9473c60df91ac147a4672120b6638aca792 Mon Sep 17 00:00:00 2001
From: =
Date: Sat, 23 May 2026 19:06:16 +0200
Subject: [PATCH 06/22] Feat: Added find stock game functionality
---
.../minigames/games/FindStockGame.java | 156 ++++++++++++++++++
1 file changed, 156 insertions(+)
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/FindStockGame.java
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/FindStockGame.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/FindStockGame.java
new file mode 100644
index 0000000..28d92ee
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/FindStockGame.java
@@ -0,0 +1,156 @@
+package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.games;
+
+import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewElement;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.GameGimmick;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.MiniGamesActions;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.IntConsumer;
+import javafx.scene.Node;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.VBox;
+
+/**
+ * Find correct stock game, found in the
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.MiniGamesView}.
+ *
+ * Extends {@link ViewElement}
+ *
+ * Implements {@link GameGimmick}
+ *
+ * @see edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.GameEngineView
+ * @see edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.MiniGamesView
+ * */
+public final class FindStockGame
+ extends ViewElement
+ implements GameGimmick {
+
+ /**
+ * Target stock to find.
+ * */
+ private Label targetLabel;
+
+ /**
+ * Grid of stock choices to select.
+ * */
+ private GridPane grid;
+
+ /**
+ * List of stock symbols to generate selection from.
+ * */
+ private final List availableSymbols;
+
+ /**
+ * The target stocks' symbol.
+ * */
+ private String targetSymbol;
+
+ /**
+ * The logic for changing score.
+ *
+ * Gotten from
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.GameEngineController}
+ * */
+ private IntConsumer scoreModifier;
+
+ /**
+ * Constructor.
+ *
+ * @param symbols a list of stocks to use during the game session.
+ * */
+ public FindStockGame(final List symbols) {
+ super(new VBox(), MiniGamesActions.class);
+ this.availableSymbols = symbols;
+ }
+
+ /**
+ * Generates a new round of "find the stock".
+ *
+ * Gets the target based on the available symbols, and adds it to the
+ * options for the round. Then generates the remaining options based on
+ * the available symbols (Duplicate options are allowed).
+ * When all options are ready, the grid is populated with the options
+ * as buttons.
+ * */
+ private void generateRound() {
+ grid.getChildren().clear();
+ if (availableSymbols.isEmpty()) {
+ return;
+ }
+
+ targetSymbol = availableSymbols.get(
+ (int) (Math.random() * availableSymbols.size())
+ );
+ targetLabel.setText("FIND: " + targetSymbol);
+
+ List roundOptions = new ArrayList<>();
+ roundOptions.add(targetSymbol);
+ while (roundOptions.size() < 8) {
+ String randomSymbol = availableSymbols.get(
+ (int) (Math.random() * availableSymbols.size())
+ );
+ roundOptions.add(randomSymbol);
+ }
+ Collections.shuffle(roundOptions);
+
+ int index = 0;
+ for (int row = 0; row < 2; row++) {
+ for (int col = 0; col < 4; col++) {
+ String symbol = roundOptions.get(index++);
+ Button optBtn = new Button(symbol);
+ optBtn.setPrefSize(120, 100);
+ optBtn.setOnAction(e -> handleChoice(symbol));
+ grid.add(optBtn, col, row);
+ }
+ }
+ }
+
+ /**
+ * Checks if the chosen stock (button press) is the correct stock.
+ *
+ * Accesses the given score modifier consumer to modify
+ * the score of this session.
+ *
+ * @param chosen the symbol of the chosen stock.
+ * */
+ private void handleChoice(final String chosen) {
+ if (chosen.equals(targetSymbol)) {
+ scoreModifier.accept(2);
+ } else {
+ scoreModifier.accept(-1);
+ }
+ generateRound();
+ }
+
+ @Override
+ protected void initLayout() {
+ targetLabel = new Label();
+ grid = new GridPane();
+ getRootPane().getChildren().addAll(targetLabel, grid);
+ }
+
+ @Override
+ protected void initStyling() {
+ getRootPane().getStyleClass().add("find-stock-minigame-root");
+ grid.getStyleClass().add("find-stock-minigame-grid");
+ }
+
+ @Override
+ public Node getCanvasNode() {
+ return getRootPane();
+ }
+
+ @Override
+ public void initialize(final IntConsumer scoreModifier) {
+ this.scoreModifier = scoreModifier;
+ generateRound();
+ }
+
+ @Override
+ public void updateTick() {
+ // No automatic updates for this game.
+ }
+}
From c31d0ec22b501686f18a34da420bed35c5e4f712 Mon Sep 17 00:00:00 2001
From: =
Date: Sat, 23 May 2026 19:09:53 +0200
Subject: [PATCH 07/22] Feat: Added Timed input game
---
.../minigames/games/TimeInputsGame.java | 168 ++++++++++++++++++
1 file changed, 168 insertions(+)
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/TimeInputsGame.java
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/TimeInputsGame.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/TimeInputsGame.java
new file mode 100644
index 0000000..85aabc9
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/TimeInputsGame.java
@@ -0,0 +1,168 @@
+package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.games;
+
+import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewElement;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.GameGimmick;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.MiniGamesActions;
+import java.util.Random;
+import java.util.function.IntConsumer;
+import javafx.scene.Node;
+import javafx.scene.canvas.Canvas;
+import javafx.scene.canvas.GraphicsContext;
+import javafx.scene.input.KeyCode;
+import javafx.scene.layout.StackPane;
+import javafx.scene.paint.Color;
+
+/**
+ * Timed clicks game found in the
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.MiniGamesView}.
+ *
+ * Extends {@link edu.ntnu.idi.idatt2003.g40.mappe.view.ViewElement}
+ *
+ * Implements {@link GameGimmick}
+ * */
+public final class TimeInputsGame
+ extends ViewElement
+ implements GameGimmick {
+
+ /**
+ * Canvas for the game.
+ * */
+ private Canvas canvas;
+
+ /**
+ * Random generator for angle.
+ * */
+ private Random random;
+
+ /**
+ * Angle of the indicator (the mark you use to "hit" the green area).
+ * */
+ private double indicatorAngle;
+
+ /**
+ * Start point of the success zone (green area).
+ * */
+ private double successZoneStart;
+
+ /**
+ * How "far" the success zone stretches across the circle.
+ * */
+ private final double successZoneExtent = 30;
+
+ /**
+ * Consumer given by {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.GameEngineController}
+ * That determines how to calculate point gains/losses.
+ * */
+ private IntConsumer scoreModifier;
+
+ /**
+ * Constructor.
+ * */
+ public TimeInputsGame() {
+ super(new StackPane(), MiniGamesActions.class);
+ }
+
+ /**
+ * Evaluates a hit (when pressing space/enter).
+ *
+ * Calculates the normalized angle of the current hit section (white part).
+ * Then, checks if that angle is within the success zone defined by a start
+ * and length. Then adds or subtracts points based on result,
+ * and generates a new success zone.
+ * */
+ private void evaluateHit() {
+ // Due to indicator angle being decreased instead of increased,
+ // We need to increase it by 360 to normalize it.
+ double normalizedAngle = (indicatorAngle + 360) % 360;
+
+ // -10 due to some visual latency causing invalid hits to appear valid.
+ if (normalizedAngle >= successZoneStart - 10 && normalizedAngle <= (successZoneStart + successZoneExtent)) {
+ scoreModifier.accept(6);
+ } else {
+ scoreModifier.accept(-2);
+ }
+
+ // Changes target area.
+ this.successZoneStart = generateRandomAngle();
+
+ // Resets indicator angle.
+ indicatorAngle = 90;
+ }
+
+ /**
+ * Generates a new random number based on the area of a success zone.
+ */
+ private double generateRandomAngle() {
+ return random.nextDouble() * (360.0 - successZoneExtent);
+ }
+
+ /**
+ * Renders the canvas, updating the current indicator and success zone.
+ * */
+ private void renderCanvas() {
+ GraphicsContext gc = canvas.getGraphicsContext2D();
+ gc.clearRect(0, 0, 300, 300);
+
+ double centerX = 150;
+ double centerY = 150;
+ double radius = 100;
+
+ // Draws circle.
+ gc.setStroke(Color.BLACK);
+ gc.setLineWidth(6);
+ gc.strokeOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
+
+ // Draws an arc representing the success zone.
+ gc.setStroke(Color.CHARTREUSE);
+ gc.setLineWidth(12);
+ gc.strokeArc(centerX - radius, centerY - radius, radius * 2, radius * 2, successZoneStart, successZoneExtent, javafx.scene.shape.ArcType.OPEN);
+
+ // Calculates and draws the indicator line based on radius and angle.
+ double rad = Math.toRadians(-indicatorAngle);
+ double startX = centerX + (radius - 15) * Math.cos(rad);
+ double startY = centerY + (radius - 15) * Math.sin(rad);
+ double endX = centerX + (radius + 15) * Math.cos(rad);
+ double endY = centerY + (radius + 15) * Math.sin(rad);
+
+ gc.setStroke(Color.WHITE);
+ gc.setLineWidth(4);
+ gc.strokeLine(startX, startY, endX, endY);
+ }
+
+ @Override
+ protected void initLayout() {
+ canvas = new Canvas(300,300);
+ random = new Random();
+ successZoneStart = generateRandomAngle();
+ getRootPane().getChildren().add(canvas);
+ }
+
+ @Override
+ protected void initStyling() {
+ getRootPane().getStyleClass().add("time-inputs-minigame-root");
+ }
+
+ @Override
+ public Node getCanvasNode() {
+ return getRootPane();
+ }
+
+ @Override
+ public void initialize(final IntConsumer scoreModifier) {
+ this.scoreModifier = scoreModifier;
+
+ getRootPane().setOnKeyPressed(e -> {
+ if (e.getCode() == KeyCode.SPACE || e.getCode() == KeyCode.ENTER) {
+ evaluateHit();
+ }
+ });
+ getRootPane().requestFocus();
+ renderCanvas();
+ }
+
+ @Override
+ public void updateTick() {
+ indicatorAngle = (indicatorAngle - 8) % 360;
+ renderCanvas();
+ }
+}
From 5cc0d08d0a4e33888c84e370fff1a63c5b56cfa8 Mon Sep 17 00:00:00 2001
From: =
Date: Sat, 23 May 2026 19:10:34 +0200
Subject: [PATCH 08/22] Feat: Updated several classes to work with minigames
---
.../ntnu/idi/idatt2003/g40/mappe/Main.java | 26 ++++++-
.../minigames/GameEngineController.java | 78 +++++++++++++++++++
.../minigames/MiniGamesController.java | 35 +++++++--
.../view/widgets/minigames/MiniGamesView.java | 1 +
src/main/resources/styles.css | 34 +++++++-
5 files changed, 164 insertions(+), 10 deletions(-)
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
index 5453765..35296a9 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
@@ -25,8 +25,10 @@
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.dashboard.DashBoardView;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.market.MarketController;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.market.MarketView;
-import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.MiniGamesController;
-import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.MiniGamesView;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.*;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.games.ClickerGame;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.games.FindStockGame;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.games.TimeInputsGame;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.stats.StatsController;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.stats.StatsView;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.topbar.TopBarController;
@@ -34,7 +36,6 @@
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.transactions.TransactionsController;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.transactions.TransactionsView;
import javafx.application.Application;
-import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.text.Font;
@@ -141,11 +142,28 @@ public void start(final Stage stage) throws Exception {
eventManager,
player.getTransactionArchive());
+ ClickerGame clickerGame = new ClickerGame();
+ FindStockGame findStockGame = new FindStockGame(
+ stocksInFile.stream()
+ .map(Stock::getSymbol)
+ .toList()
+ );
+ TimeInputsGame timeInputsGame = new TimeInputsGame();
+
+ GameEngineView gameEngineView = new GameEngineView();
+ GameEngineController gameEngineController = new GameEngineController(gameEngineView, eventManager);
+
MiniGamesView miniGamesView = new MiniGamesView();
new MiniGamesController(
miniGamesView,
eventManager,
- stocksInFile.getFirst()
+ stocksInFile.getFirst(),
+ gameEngineView,
+ gameEngineController,
+ clickerGame,
+ inGameView,
+ findStockGame,
+ timeInputsGame
);
// Wire top bar buttons til å bytte mellom dashboard / stats / market /
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
new file mode 100644
index 0000000..6db58dd
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
@@ -0,0 +1,78 @@
+package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames;
+
+import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventManager;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewController;
+import javafx.animation.KeyFrame;
+import javafx.animation.Timeline;
+import javafx.util.Duration;
+
+public final class GameEngineController extends ViewController {
+
+ private int currentScore = 0;
+ private int frameCounter = 0;
+ private int secondsRemaining = 60;
+ private GameGimmick activeGimmick;
+ private Timeline engineLoop;
+
+ public GameEngineController(final GameEngineView viewElement,
+ final EventManager eventManager) throws IllegalArgumentException {
+ super(viewElement, eventManager);
+
+ engineLoop = new Timeline(new KeyFrame(Duration.millis(16.6), e -> {
+ activeGimmick.updateTick();
+
+ frameCounter++;
+ if (frameCounter >= 60) {
+ secondsRemaining--;
+ frameCounter = 0;
+ refreshMetrics();
+ }
+ }));
+ engineLoop.setCycleCount(Timeline.INDEFINITE);
+ }
+
+ @Override
+ protected void initInteractions() {
+ getViewElement().setOnAction(MiniGamesActions.INGAME_QUIT, this::stopGameSession);
+ }
+
+ public void launchGimmickSession(final GameGimmick gimmick) {
+ this.activeGimmick = gimmick;
+ this.currentScore = 0;
+ this.frameCounter = 0;
+ this.secondsRemaining = 60;
+ refreshMetrics();
+
+ // Connect interactions.
+ getViewElement().setGameGimmickContent(gimmick, (scoreDelta) -> {
+ if (this.currentScore + scoreDelta >= 0) {
+ this.currentScore += scoreDelta;
+ refreshMetrics();
+ }
+ });
+ engineLoop.play();
+ }
+
+ private void refreshMetrics() {
+ int hours = secondsRemaining / 3600;
+ int minutes = (secondsRemaining % 3600) / 60;
+ int seconds = secondsRemaining % 60;
+ String formattedTime = String.format("%02d:%02d:%02d", hours, minutes, seconds);
+
+ // Dynamic Rank classification engine evaluations
+ String rank = "E";
+ if (currentScore > 50) rank = "A";
+ else if (currentScore > 30) rank = "B";
+ else if (currentScore > 15) rank = "C";
+ else if (currentScore > 5) rank = "D";
+
+ getViewElement().updateMetadataDisplay(currentScore, formattedTime, rank);
+ }
+
+ private void stopGameSession() {
+ if (engineLoop != null) {
+ engineLoop.stop();
+ }
+ // Fire architecture EventManager updates here to go back to the menu view cleanly
+ }
+}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesController.java
index 1ebb07a..da8bcbe 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesController.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesController.java
@@ -3,6 +3,10 @@
import edu.ntnu.idi.idatt2003.g40.mappe.model.Stock;
import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventManager;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewController;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.InGameView;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.games.ClickerGame;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.games.FindStockGame;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.games.TimeInputsGame;
/**
* Controller class for the associated {@link MiniGamesView} object.
@@ -11,12 +15,30 @@
* */
public final class MiniGamesController extends ViewController {
private Stock activeStock;
+ private final GameEngineView gameEngineView;
+ private final GameEngineController gameEngineController;
+ private final ClickerGame clickerGame;
+ private final InGameView inGameView;
+ private final FindStockGame findStockGame;
+ private final TimeInputsGame timeInputsGame;
public MiniGamesController(final MiniGamesView viewElement,
final EventManager eventManager,
- final Stock initialStock) {
- super(viewElement, eventManager);
+ final Stock initialStock,
+ final GameEngineView gameEngineView,
+ final GameEngineController gameEngineController,
+ final ClickerGame clickerGame,
+ final InGameView inGameView,
+ final FindStockGame findStockGame,
+ final TimeInputsGame timeInputsGame) {
this.activeStock = initialStock;
+ this.gameEngineView = gameEngineView;
+ this.gameEngineController = gameEngineController;
+ this.clickerGame = clickerGame;
+ this.inGameView = inGameView;
+ this.findStockGame = findStockGame;
+ this.timeInputsGame = timeInputsGame;
+ super(viewElement, eventManager);
refresh();
}
@@ -27,15 +49,18 @@ protected void initInteractions() {
});
getViewElement().setOnAction(MiniGamesActions.CLICKER_GAME, () -> {
- // Logic for launching Clicker Game
+ inGameView.changeCenterView(gameEngineView.getRootPane());
+ gameEngineController.launchGimmickSession(clickerGame);
});
getViewElement().setOnAction(MiniGamesActions.FIND_STOCK, () -> {
- // Logic for launching Find Stock Game
+ inGameView.changeCenterView(gameEngineView.getRootPane());
+ gameEngineController.launchGimmickSession(findStockGame);
});
getViewElement().setOnAction(MiniGamesActions.TIME_CLICKS, () -> {
- // Logic for launching Time Clicks Game
+ inGameView.changeCenterView(gameEngineView.getRootPane());
+ gameEngineController.launchGimmickSession(timeInputsGame);
});
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java
index 5d9ac4d..6d854d4 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java
@@ -2,6 +2,7 @@
import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewElement;
import javafx.geometry.Pos;
+import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
diff --git a/src/main/resources/styles.css b/src/main/resources/styles.css
index de5dd5d..1a753f3 100644
--- a/src/main/resources/styles.css
+++ b/src/main/resources/styles.css
@@ -860,4 +860,36 @@
.minigames-cardBtn:hover, .minigames-helpBtn:hover {
-fx-background-color: #c0c0c0;
}
-/* --------------------------------------------- */
\ No newline at end of file
+/* --------------------------------------------- */
+/* --------------- FIND STOCK GAME ------------*/
+.find-stock-minigame-root {
+ -fx-spacing: 15;
+ -fx-alignment: CENTER;
+}
+
+.find-stock-minigame-grid {
+ -fx-hgap: 15px;
+ -fx-vgap: 15px;
+ -fx-alignment: center;
+}
+/*----------------------------------------------*/
+/*--------------- CLICKER GAME -----------------*/
+.clicker-minigame-root {
+ -fx-spacing: 20;
+ -fx-alignment: CENTER;
+}
+
+.clicker-minigame-clickBtn {
+ -fx-pref-width: 100;
+ -fx-pref-height: 100;
+}
+
+.clicker-minigame-upgradeBtn {
+ -fx-text-alignment: center;
+}
+/*--------------- TIMED INPUT GAME -------------*/
+.time-inputs-minigame-root {
+ -fx-background-color: transparent;
+ -fx-focus-traversable: true;
+}
+/*-----------------------------------------------*/
\ No newline at end of file
From bfb3228837f66ba8b299962b7f71b8635157ce00 Mon Sep 17 00:00:00 2001
From: =
Date: Sat, 23 May 2026 19:45:00 +0200
Subject: [PATCH 09/22] Feat: WIP for generating report after game
---
.../ntnu/idi/idatt2003/g40/mappe/Main.java | 6 +-
.../minigames/GameEngineController.java | 10 ++-
.../widgets/minigames/GameEngineView.java | 84 ++++++++++++++-----
.../widgets/minigames/MiniGamesActions.java | 7 +-
4 files changed, 84 insertions(+), 23 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
index 35296a9..f8deb83 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
@@ -151,7 +151,11 @@ public void start(final Stage stage) throws Exception {
TimeInputsGame timeInputsGame = new TimeInputsGame();
GameEngineView gameEngineView = new GameEngineView();
- GameEngineController gameEngineController = new GameEngineController(gameEngineView, eventManager);
+ GameEngineController gameEngineController = new GameEngineController(
+ gameEngineView,
+ eventManager,
+ stocksInFile.getFirst()
+ );
MiniGamesView miniGamesView = new MiniGamesView();
new MiniGamesController(
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
index 6db58dd..3695ad0 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
@@ -1,5 +1,6 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames;
+import edu.ntnu.idi.idatt2003.g40.mappe.model.Stock;
import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventManager;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewController;
import javafx.animation.KeyFrame;
@@ -13,9 +14,12 @@ public final class GameEngineController extends ViewController {
private int secondsRemaining = 60;
private GameGimmick activeGimmick;
private Timeline engineLoop;
+ private Stock chosenStock;
public GameEngineController(final GameEngineView viewElement,
- final EventManager eventManager) throws IllegalArgumentException {
+ final EventManager eventManager,
+ final Stock chosenStock) throws IllegalArgumentException {
+ this.chosenStock = chosenStock;
super(viewElement, eventManager);
engineLoop = new Timeline(new KeyFrame(Duration.millis(16.6), e -> {
@@ -53,6 +57,10 @@ public void launchGimmickSession(final GameGimmick gimmick) {
engineLoop.play();
}
+ public void setChosenStock(final Stock newStock) {
+ chosenStock = newStock;
+ }
+
private void refreshMetrics() {
int hours = secondsRemaining / 3600;
int minutes = (secondsRemaining % 3600) / 60;
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineView.java
index e18b372..7cfa586 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineView.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineView.java
@@ -6,6 +6,7 @@
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
+import javafx.scene.layout.VBox;
import java.util.function.IntConsumer;
@@ -17,30 +18,16 @@ public final class GameEngineView extends ViewElement
Date: Sun, 24 May 2026 14:26:34 +0200
Subject: [PATCH 10/22] Feat: Added fortune to stock
Fortune double value represents how "lucky" that stock will be in the next week. Setter and getter method for value. Also added compatibilty with exchange advance week method.
---
.../idatt2003/g40/mappe/engine/Exchange.java | 7 +++--
.../idi/idatt2003/g40/mappe/model/Stock.java | 27 +++++++++++++++++++
2 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/Exchange.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/Exchange.java
index 9c5796a..b73f634 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/Exchange.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/Exchange.java
@@ -208,7 +208,9 @@ public Transaction sell(final Share share, final Player player)
*
* @throws IllegalArgumentException if any parameter is null, or if player does not have enough shares.
* */
- public List sell(BigDecimal amount, final String stockSymbol, final Player player)
+ public List sell(BigDecimal amount,
+ final String stockSymbol,
+ final Player player)
throws IllegalArgumentException {
if (amount == null || player == null || !Validator.NOT_EMPTY.isValid(stockSymbol)) {
throw new IllegalArgumentException("Invalid sell!");
@@ -253,7 +255,8 @@ public void advance() {
for (Stock stock : stockMap.values()) {
BigDecimal currentPrice = stock.getSalesPrice();
- double change = (random.nextDouble() * 0.10) - 0.05;
+ double change = ((random.nextDouble() * 0.10) - 0.05) + stock.getFortune();
+ stock.setFortune(0);
BigDecimal factor = BigDecimal.valueOf(1 + change);
BigDecimal newPrice = currentPrice.multiply(factor);
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Stock.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Stock.java
index 11a444e..1ca9664 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Stock.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Stock.java
@@ -26,6 +26,14 @@ public final class Stock {
* */
private final List prices = new ArrayList<>();
+ /**
+ * Value indicating this stocks fortune.
+ *
+ * Higher fortune yields a higher
+ * increase when stock market changes price.
+ * */
+ private double fortune;
+
/**
* Creates a new {@code Stock} with an initial sales price.
*
@@ -42,10 +50,29 @@ public Stock(final String symbol,
} else {
this.symbol = symbol;
this.company = company;
+ this.fortune = 0;
prices.add(salesPrice);
}
}
+ /**
+ * Setter method for fortune.
+ *
+ * @param newFortune the new value to set this stocks' fortune.
+ * */
+ public void setFortune(final double newFortune) {
+ fortune = newFortune;
+ }
+
+ /**
+ * Getter method for fortune.
+ *
+ * @return fortune.
+ * */
+ public double getFortune() {
+ return fortune;
+ }
+
/**
* Returns the stock symbol.
*
From e62eb66adb82e8ac01ec632dc7ad9b4506bd7465 Mon Sep 17 00:00:00 2001
From: =
Date: Sun, 24 May 2026 14:27:24 +0200
Subject: [PATCH 11/22] Fix: Rounding transactions numbers
Bigdecimal values can have extreme amounts of decimals. Transaction cards now round by converting to float (only visually)
---
.../mappe/view/widgets/transactions/TransactionsController.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/transactions/TransactionsController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/transactions/TransactionsController.java
index 3069e8c..7179630 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/transactions/TransactionsController.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/transactions/TransactionsController.java
@@ -67,7 +67,7 @@ private void filterData(final String searchKeyword, final Integer weekTarget) {
t.getShare().getStock().getSymbol(),
t.getShare().getStock().getCompany(),
sharePrefix + t.getShare().getQuantity().floatValue() + " shares",
- moneyPrefix + t.getCalculator().calculateTotal().toString() + " NOK",
+ moneyPrefix + t.getCalculator().calculateTotal().floatValue() + " NOK",
weekTarget.toString());
}
});
From 21723220218ac1a0812cdcfd3af7f0d49ad4115a Mon Sep 17 00:00:00 2001
From: =
Date: Sun, 24 May 2026 14:28:37 +0200
Subject: [PATCH 12/22] Feat: Added widget enum
Added widget enum that functions similarily to ViewEnum. Also added event subscribing to ingamecontroller so any publisher can change widget.
---
.../mappe/view/ingame/InGameController.java | 26 +++++++++++++++++--
.../g40/mappe/view/widgets/WidgetEnum.java | 10 +++++++
2 files changed, 34 insertions(+), 2 deletions(-)
create mode 100644 src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/WidgetEnum.java
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/InGameController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/InGameController.java
index eda5729..6c84780 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/InGameController.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/InGameController.java
@@ -1,21 +1,43 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view.ingame;
+import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventData;
import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventManager;
+import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventSubscriber;
+import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventType;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewController;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.WidgetEnum;
+import javafx.scene.Node;
+import java.util.EnumMap;
-public class InGameController extends ViewController {
+public final class InGameController extends ViewController
+ implements EventSubscriber {
+
+ private final EnumMap widgetMap = new EnumMap<>(WidgetEnum.class);
/**
* {@inheritDoc}.
*/
- protected InGameController(final InGameView viewElement,
+ public InGameController(final InGameView viewElement,
final EventManager eventManager)
throws IllegalArgumentException {
super(viewElement, eventManager);
+ eventManager.addSubscriber(this, EventType.CHANGE_INGAME_CENTER);
+ }
+
+ public void addwidget(final WidgetEnum widgetEnum, final Node widgetRoot) {
+ widgetMap.put(widgetEnum, widgetRoot);
}
@Override
protected void initInteractions() {
}
+
+ @Override
+ public void handleEvent(final EventData data) {
+ if (!(data.data() instanceof WidgetEnum) || !widgetMap.containsKey(data.data())) {
+ throw new IllegalArgumentException("Invalid event thrown!");
+ }
+ getViewElement().changeCenterView(widgetMap.get(data.data()));
+ }
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/WidgetEnum.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/WidgetEnum.java
new file mode 100644
index 0000000..5efcbb0
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/WidgetEnum.java
@@ -0,0 +1,10 @@
+package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets;
+
+public enum WidgetEnum {
+ DASHBOARD,
+ MARKET,
+ MINIGAMES_OVERVIEW,
+ MINIGAMES_ENGINE,
+ STATS,
+ TRANSACTIONS
+}
From 355628eaf008b7bdd9c7a638fb6b9304978a0315 Mon Sep 17 00:00:00 2001
From: =
Date: Sun, 24 May 2026 14:30:20 +0200
Subject: [PATCH 13/22] Feat: Overall changes
Overall improvements across various classes.
Documentation and setting up simple helper methods, as well as disabling button pressing by pressing space or enter (key used in minigame(s)).
---
.../ntnu/idi/idatt2003/g40/mappe/Main.java | 15 +++
.../g40/mappe/service/event/EventType.java | 16 ++-
.../g40/mappe/view/ViewController.java | 11 ++
.../g40/mappe/view/ingame/InGameView.java | 11 --
.../widgets/financialsummary/SummaryView.java | 1 +
.../widgets/minigames/GameEngineView.java | 103 +++++++++++++-----
.../widgets/minigames/MiniGamesActions.java | 6 +-
.../minigames/MiniGamesController.java | 45 +++++++-
.../view/widgets/minigames/MiniGamesView.java | 89 +++++++++------
.../mappe/view/widgets/topbar/TopBarView.java | 2 +-
src/main/resources/styles.css | 54 ++++++++-
11 files changed, 276 insertions(+), 77 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
index f8deb83..7b55201 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
@@ -9,6 +9,7 @@
import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventManager;
import edu.ntnu.idi.idatt2003.g40.mappe.utils.ConfigValues;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewManager;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.InGameController;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.InGameView;
import edu.ntnu.idi.idatt2003.g40.mappe.view.mainmenu.MainMenuController;
import edu.ntnu.idi.idatt2003.g40.mappe.view.mainmenu.MainMenuView;
@@ -19,6 +20,8 @@
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
+
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.WidgetEnum;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.financialsummary.SummaryController;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.financialsummary.SummaryView;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.dashboard.DashBoardController;
@@ -134,6 +137,10 @@ public void start(final Stage stage) throws Exception {
// In-game (Change "topBarView" to "topBarView2" if no summary section).
// Dashboard er default center-view.
InGameView inGameView = new InGameView(topBarView, dashBoardView.getRootPane());
+ InGameController inGameController = new InGameController(
+ inGameView,
+ eventManager
+ );
// Transaction history page
TransactionsView transactionsView = new TransactionsView();
@@ -189,6 +196,14 @@ public void start(final Stage stage) throws Exception {
viewManager.addView(inGameView);
viewManager.setScene(mainMenuView);
+ // Register all widgets
+ inGameController.addwidget(WidgetEnum.DASHBOARD, dashBoardView.getRootPane());
+ inGameController.addwidget(WidgetEnum.MARKET, marketView.getRootPane());
+ inGameController.addwidget(WidgetEnum.MINIGAMES_OVERVIEW, miniGamesView.getRootPane());
+ inGameController.addwidget(WidgetEnum.MINIGAMES_ENGINE, gameEngineView.getRootPane());
+ inGameController.addwidget(WidgetEnum.STATS, statsView.getRootPane());
+ inGameController.addwidget(WidgetEnum.TRANSACTIONS, transactionsView.getRootPane());
+
stage.show();
}
}
\ No newline at end of file
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventType.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventType.java
index 4231866..777602d 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventType.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventType.java
@@ -22,7 +22,21 @@ public enum EventType implements EventChannel {
* @see edu.ntnu.idi.idatt2003.g40.mappe.view.ViewManager
*
*/
- SCENE_CHANGE;
+ SCENE_CHANGE,
+
+ /**
+ * Event type representing events that causes the center view in the
+ * current {@link edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.InGameView}
+ * object to change.
+ *
+ * Primarily handled by the active
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.InGameController}
+ * object.
+ *
+ * @see edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.InGameController
+ *
+ */
+ CHANGE_INGAME_CENTER;
/**
* {@inheritDoc}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ViewController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ViewController.java
index fed6cfa..63a2ec3 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ViewController.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ViewController.java
@@ -82,6 +82,17 @@ protected void changeScene(final ViewEnum viewName) {
invoke(eventData, eventManager);
}
+ /**
+ * Overloaded invoke method to reduce parameters, by using
+ * internal reference to event manager.
+ *
+ * @param the type of data to send.
+ * @param data the data to send.
+ * */
+ protected void invoke(final EventData data) {
+ invoke(data, eventManager);
+ }
+
@Override
public final void invoke(final EventData data,
final EventManager eventManager) {
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/InGameView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/InGameView.java
index b3b00b7..29a298d 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/InGameView.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/ingame/InGameView.java
@@ -1,23 +1,12 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view.ingame;
-import edu.ntnu.idi.idatt2003.g40.mappe.model.Stock;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewElement;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewEnum;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.topbar.TopBarView;
-import javafx.geometry.Pos;
import javafx.scene.Node;
-import javafx.scene.chart.LineChart;
-import javafx.scene.chart.NumberAxis;
-import javafx.scene.chart.XYChart;
-import javafx.scene.control.Button;
-import javafx.scene.control.Label;
-import javafx.scene.control.Separator;
-import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
-import java.util.ArrayList;
-
public class InGameView extends ViewElement {
private final TopBarView topBarView;
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/financialsummary/SummaryView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/financialsummary/SummaryView.java
index 092e407..9c3b899 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/financialsummary/SummaryView.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/financialsummary/SummaryView.java
@@ -89,6 +89,7 @@ protected void initLayout() {
navInfo.setAlignment(Pos.TOP_CENTER);
nextBtn = new Button("next");
+ nextBtn.setFocusTraversable(false);
weekLabel = new Label("week: 1");
weekLabel.getStyleClass().add("week-label");
Region spacerR = new Region();
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineView.java
index 7cfa586..379d6f7 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineView.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineView.java
@@ -1,6 +1,7 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewElement;
+import java.util.function.IntConsumer;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
@@ -8,22 +9,67 @@
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
-import java.util.function.IntConsumer;
+/**
+ * Minigame context class as described in the Strategy pattern.
+ *
+ * Extends {@link ViewElement}
+ * */
+public final class GameEngineView
+ extends ViewElement {
-public final class GameEngineView extends ViewElement {
+ /**
+ * Quit button (does not generate results).
+ * */
private Button quitButton;
+
+ /**
+ * Label for current score.
+ * */
private Label scoreLabel;
+
+ /**
+ * Label for time left.
+ * */
private Label timerLabel;
+
+ /**
+ * Label for current rank.
+ * */
private Label rankLabel;
+
+ /**
+ * Container for score, timer and rank.
+ * */
private HBox topDashboardBar;
- private int curScore;
+ /**
+ * Container for final game status report.
+ * */
private VBox reportContainer;
+
+ /**
+ * Label for report title.
+ * */
private Label reportTitleLabel;
+
+ /**
+ * Label for result rank.
+ * */
private Label rankResultLabel;
+
+ /**
+ * Label for describing what effects on the stock will apply.
+ * */
private Label stockEffectLabel;
+
+ /**
+ * Return button on the report (generates results on the stock market).
+ * */
private Button closeReportBtn;
+ /**
+ * Constructor.
+ * */
public GameEngineView() {
super(new BorderPane(), MiniGamesActions.class);
}
@@ -32,12 +78,12 @@ public GameEngineView() {
* Method for updating the game per tick with score, time and rank.
*
* @param score the score to show.
- * @param time the time to show.
- * @param rank the rank to show.
+ * @param time the time to show.
+ * @param rank the rank to show.
* */
public void updateMetadataDisplay(final int score,
final String time,
- final String rank) {
+ final char rank) {
scoreLabel.setText("Score: " + score);
timerLabel.setText(time);
rankLabel.setText("Rank: " + rank);
@@ -58,35 +104,30 @@ public void setGameGimmickContent(final GameGimmick gimmick, final IntConsumer c
/**
* Displays the report after a minigames timers is finished.
*
- * @param rank the rank the player got.
- * @param stockSymbol the symbol of the affected stock.
- * @param isPositive whether the change is positive or not.
+ * @param rank the rank the player got.
+ * @param effect the effect caused by the results.
* */
- public void showGameReport(final String rank,
- final String stockSymbol,
- final boolean isPositive) {
+ public void showGameReport(final char rank,
+ final String effect) {
getRootPane().setCenter(null);
- reportContainer = new VBox(25);
- reportContainer.setAlignment(Pos.CENTER);
- reportContainer.getStyleClass().add("minigames-report-box");
+ reportContainer = new VBox();
+ reportContainer.getStyleClass().add("gameEngine-report-box");
reportTitleLabel = new Label("GAME OVER - REPORT");
- reportTitleLabel.setStyle("-fx-font-size: 32px; -fx-font-weight: bold;");
+ reportTitleLabel.getStyleClass().add("gameEngine-report-title");
rankResultLabel = new Label("Final Rank: " + rank);
- rankResultLabel.setStyle("-fx-font-size: 24px;");
+ rankResultLabel.getStyleClass().add("gameEngine-report-rank-result");
- String effectText = isPositive
+ /*String effectText = isPositive
? "Performance impact: Positive change for " + stockSymbol + " next week! 📈"
: "Performance impact: Negative change for " + stockSymbol + " next week... 📉";
- stockEffectLabel = new Label(effectText);
- stockEffectLabel.setStyle("-fx-font-size: 18px; -fx-text-fill: " + (isPositive ? "green;" : "red;"));
- closeReportBtn = new Button("Return to Menu");
- closeReportBtn.setPrefSize(200, 50);
- registerButton(MiniGamesActions.CLOSE_REPORT, closeReportBtn);
+ stockEffectLabel.setStyle("-fx-font-size: 18px; -fx-text-fill: " + (isPositive ? "green;" : "red;"));*/
+ stockEffectLabel = new Label(effect);
+ stockEffectLabel.getStyleClass().add("gameEngine-report-effect");
reportContainer.getChildren().addAll(reportTitleLabel, rankResultLabel, stockEffectLabel, closeReportBtn);
getRootPane().setCenter(reportContainer);
@@ -96,6 +137,7 @@ public void showGameReport(final String rank,
protected void initLayout() {
quitButton = new Button("Quit");
quitButton.setPrefSize(100, 50);
+ quitButton.setFocusTraversable(false);
scoreLabel = new Label("Score: 0");
timerLabel = new Label("00:00:60");
@@ -107,17 +149,22 @@ protected void initLayout() {
topDashboardBar = new HBox(20, quitButton, statsDisplay);
topDashboardBar.setAlignment(Pos.CENTER_LEFT);
topDashboardBar.setPadding(new javafx.geometry.Insets(15));
+ closeReportBtn = new Button("Return");
+ closeReportBtn.setFocusTraversable(false);
getRootPane().setTop(topDashboardBar);
+
registerButton(MiniGamesActions.INGAME_QUIT, quitButton);
+ registerButton(MiniGamesActions.INGAME_RETURN, closeReportBtn);
}
@Override
protected void initStyling() {
- getRootPane().setStyle("-fx-background-color: rgba(180, 180, 180, 0.85);");
- topDashboardBar.setStyle("-fx-background-color: transparent;");
- scoreLabel.setStyle("-fx-font-size: 24px; -fx-text-fill: black;");
- timerLabel.setStyle("-fx-font-size: 24px; -fx-text-fill: black;");
- rankLabel.setStyle("-fx-font-size: 24px; -fx-text-fill: black;");
+ getRootPane().getStyleClass().add("gameEngine-root");
+ topDashboardBar.getStyleClass().add("gameEngine-topBar");
+ scoreLabel.getStyleClass().add("gameEngine-topBar-Label");
+ timerLabel.getStyleClass().add("gameEngine-topBar-Label");
+ rankLabel.getStyleClass().add("gameEngine-topBar-Label");
+ closeReportBtn.getStyleClass().add("gameEngine-report-closeButton");
}
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesActions.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesActions.java
index c15b43c..279d17d 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesActions.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesActions.java
@@ -25,12 +25,12 @@ public enum MiniGamesActions {
HELP,
/**
- * Action called when quitting a minigame.
+ * Action called when quitting a minigame (no reward).
* */
INGAME_QUIT,
/**
- * Action called when closing the report at the end of a minigame.
+ * Action for when a player returns from a minigame (with rewards).
* */
- CLOSE_REPORT
+ INGAME_RETURN;
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesController.java
index da8bcbe..ee9a2d9 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesController.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesController.java
@@ -14,14 +14,55 @@
* Extends {@link ViewController}
* */
public final class MiniGamesController extends ViewController {
+
+ /**
+ * The currently selected stock for the minigame.
+ * */
private Stock activeStock;
+
+ /**
+ * The game engine view to delegate games towards.
+ * */
private final GameEngineView gameEngineView;
+
+ /**
+ * The game engine controller.
+ * */
private final GameEngineController gameEngineController;
+
+ /**
+ * The clicker game instance.
+ * */
private final ClickerGame clickerGame;
+
+ /**
+ * The in game view.
+ * */
private final InGameView inGameView;
+
+ /**
+ * The find stock game instance.
+ * */
private final FindStockGame findStockGame;
+
+ /**
+ * The timed inputs game instance.
+ * */
private final TimeInputsGame timeInputsGame;
+ /**
+ * Constructor.
+ *
+ * @param viewElement the associated {@link MiniGamesView}.
+ * @param eventManager the associated {@link EventManager}.
+ * @param initialStock the initial selected stock.
+ * @param gameEngineView the game engine view.
+ * @param gameEngineController the game engine controller.
+ * @param clickerGame the clicker game instance.
+ * @param inGameView the in game view instance.
+ * @param findStockGame the find stock game instance.
+ * @param timeInputsGame the timed inputs game.
+ * */
public MiniGamesController(final MiniGamesView viewElement,
final EventManager eventManager,
final Stock initialStock,
@@ -30,7 +71,8 @@ public MiniGamesController(final MiniGamesView viewElement,
final ClickerGame clickerGame,
final InGameView inGameView,
final FindStockGame findStockGame,
- final TimeInputsGame timeInputsGame) {
+ final TimeInputsGame timeInputsGame
+ ) {
this.activeStock = initialStock;
this.gameEngineView = gameEngineView;
this.gameEngineController = gameEngineController;
@@ -71,6 +113,7 @@ protected void initInteractions() {
*/
public void setActiveStock(final Stock stock) {
this.activeStock = stock;
+ gameEngineController.setChosenStock(stock);
refresh();
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java
index 6d854d4..ca00af3 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java
@@ -1,8 +1,6 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewElement;
-import javafx.geometry.Pos;
-import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
@@ -12,20 +10,67 @@
/**
* Minigames view in the in game section of the application.
+ *
+ * Extends {@link ViewElement}
+ *
+ * Functions as an overview page before choosing a game.
+ * To see the elements creating the minigames themselves,
+ * see {@link GameEngineView}.
* */
public final class MiniGamesView extends ViewElement {
+ /**
+ * Top section of the page (Title, selected stock, question mark block).
+ * */
private HBox headerBar;
+
+ /**
+ * Container for games boxes.
+ * */
private HBox gamesContainer;
+ /**
+ * Row containing "Stock Selected:" and current stock.
+ * */
+ private HBox stockSelectionRow;
+
+ /**
+ * Title (Minigames).
+ * */
private Label titleLabel;
+
+ /**
+ * Selected stock.
+ * */
private Label selectedStockLabel;
+
+ /**
+ * Stock symbol box.
+ * */
private Label stockValueLabel;
+ /**
+ * Question mark button (displays a short tutorial).
+ * */
private Button helpBtn;
+
+ /**
+ * Button to start an
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.games.ClickerGame} instance.
+ * */
private Button clickerGameBtn;
+
+ /**
+ * Button to start an
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.games.FindStockGame} instance.
+ * */
private Button findStockBtn;
- private Button timeClicksBtn;
+
+ /**
+ * Button to start an
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.games.TimeInputsGame} instance.
+ * */
+ private Button timeInputsBtn;
/**
* Constructor.
@@ -36,19 +81,15 @@ public MiniGamesView() throws IllegalArgumentException {
@Override
protected void initLayout() {
- // Top header layout
headerBar = new HBox();
- headerBar.setAlignment(Pos.TOP_LEFT);
-
- VBox titleSection = new VBox();
titleLabel = new Label("Mini games");
- HBox stockSelectionRow = new HBox();
- stockSelectionRow.setAlignment(Pos.CENTER_LEFT);
+ stockSelectionRow = new HBox();
selectedStockLabel = new Label("Selected stock: ");
stockValueLabel = new Label("AAPL");
stockSelectionRow.getChildren().addAll(selectedStockLabel, stockValueLabel);
+ VBox titleSection = new VBox();
titleSection.getChildren().addAll(titleLabel, stockSelectionRow);
Region topSpacer = new Region();
@@ -57,41 +98,26 @@ protected void initLayout() {
helpBtn = new Button("?");
headerBar.getChildren().addAll(titleSection, topSpacer, helpBtn);
- // Main central row container for games
gamesContainer = new HBox();
- gamesContainer.setAlignment(Pos.CENTER);
clickerGameBtn = new Button("Clicker game");
- findStockBtn = new Button("Find correct\nstock");
- timeClicksBtn = new Button("Time your clicks");
+ findStockBtn = new Button("Find stock");
+ timeInputsBtn = new Button("Timed inputs");
- // Make buttons fill equal proportions
HBox.setHgrow(clickerGameBtn, Priority.ALWAYS);
HBox.setHgrow(findStockBtn, Priority.ALWAYS);
- HBox.setHgrow(timeClicksBtn, Priority.ALWAYS);
-
- // Equal constraints on dimensions
- configureGameButton(clickerGameBtn);
- configureGameButton(findStockBtn);
- configureGameButton(timeClicksBtn);
+ HBox.setHgrow(timeInputsBtn, Priority.ALWAYS);
- gamesContainer.getChildren().addAll(clickerGameBtn, findStockBtn, timeClicksBtn);
+ gamesContainer.getChildren().addAll(clickerGameBtn,
+ findStockBtn, timeInputsBtn);
- // Assemble view layers
VBox.setVgrow(gamesContainer, Priority.ALWAYS);
getRootPane().getChildren().addAll(headerBar, gamesContainer);
- // Map interactions
registerButton(MiniGamesActions.HELP, helpBtn);
registerButton(MiniGamesActions.CLICKER_GAME, clickerGameBtn);
registerButton(MiniGamesActions.FIND_STOCK, findStockBtn);
- registerButton(MiniGamesActions.TIME_CLICKS, timeClicksBtn);
- }
-
- private void configureGameButton(final Button btn) {
- btn.setMaxWidth(Double.MAX_VALUE);
- btn.setMaxHeight(Double.MAX_VALUE);
- btn.setAlignment(Pos.CENTER);
+ registerButton(MiniGamesActions.TIME_CLICKS, timeInputsBtn);
}
/**
@@ -107,6 +133,7 @@ public void setSelectedStockText(final String symbol) {
protected void initStyling() {
getRootPane().getStyleClass().add("minigames-root");
headerBar.getStyleClass().add("minigames-headerBar");
+ stockSelectionRow.getStyleClass().add("minigames-stockSelectionRow");
titleLabel.getStyleClass().add("minigames-titleLabel");
selectedStockLabel.getStyleClass().add("minigames-stockLabel");
stockValueLabel.getStyleClass().add("minigames-stockValue");
@@ -116,6 +143,6 @@ protected void initStyling() {
clickerGameBtn.getStyleClass().add("minigames-cardBtn");
findStockBtn.getStyleClass().add("minigames-cardBtn");
- timeClicksBtn.getStyleClass().add("minigames-cardBtn");
+ timeInputsBtn.getStyleClass().add("minigames-cardBtn");
}
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarView.java
index 3be0fcf..471dfbb 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarView.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/topbar/TopBarView.java
@@ -51,9 +51,9 @@ protected void initLayout() {
transactionsBtn = new Button("Transactions");
minigamesBtn = new Button("Minigames");
-
Stream.of(quitBtn, statsBtn, marketBtn, settingsBtn, transactionsBtn, minigamesBtn).forEach(b -> {
HBox.setHgrow(b, Priority.ALWAYS);
+ b.setFocusTraversable(false);
});
navRow.getChildren().addAll(
diff --git a/src/main/resources/styles.css b/src/main/resources/styles.css
index 1a753f3..ad0cde6 100644
--- a/src/main/resources/styles.css
+++ b/src/main/resources/styles.css
@@ -807,9 +807,14 @@
}
.minigames-headerBar {
+ -fx-alignment: TOP_LEFT;
-fx-padding: 10px 0px;
}
+.minigames-stockSelectionRow {
+ -fx-alignment: CENTER_LEFT;
+}
+
.minigames-titleLabel {
-fx-font-size: 48px;
-fx-font-family: "Aptos", "Segoe UI", sans-serif;
@@ -841,11 +846,13 @@
}
.minigames-container {
+ -fx-alignment: CENTER;
-fx-spacing: 30px;
-fx-padding: 10px 0px;
}
.minigames-cardBtn {
+ -fx-alignment: CENTER;
-fx-background-color: #d8d8d8;
-fx-border-color: #000000;
-fx-border-width: 1.5px;
@@ -861,7 +868,52 @@
-fx-background-color: #c0c0c0;
}
/* --------------------------------------------- */
-/* --------------- FIND STOCK GAME ------------*/
+/* --------- MINIGAMES ENGINE CONTEXT ---------- */
+.gameEngine-root {
+ -fx-background-color: rgba(180, 180, 180, 0.85);
+}
+
+.gameEngine-topBar {
+ -fx-background-color: transparent;
+}
+
+.gameEngine-topBar-Label {
+ -fx-font-size: 24px;
+ -fx-text-fill: black;
+}
+
+.gameEngine-report-box {
+ -fx-spacing: 25px;
+ -fx-alignment: CENTER;
+ -fx-background-color: #ffffff;
+ -fx-border-color: #000000;
+ -fx-border-width: 2px;
+ -fx-padding: 40px;
+ -fx-max-width: 500px;
+ -fx-max-height: 350px;
+ -fx-background-radius: 5px;
+ -fx-border-radius: 5px;
+}
+
+.gameEngine-report-title {
+ -fx-font-size: 32px;
+ -fx-font-weight: bold;
+}
+
+.gameEngine-report-rank-result {
+ -fx-font-size: 24px;
+}
+
+.gameEngine-report-effect {
+ -fx-font-size: 18px;
+}
+
+.gameEngine-report-closeButton {
+ -fx-pref-width: 200;
+ -fx-pref-height: 50;
+}
+/* ----------------------------------------------*/
+/* --------------- FIND STOCK GAME ------------- */
.find-stock-minigame-root {
-fx-spacing: 15;
-fx-alignment: CENTER;
From a6591ada7d3cebff78336abab467a25b15cf12a8 Mon Sep 17 00:00:00 2001
From: =
Date: Sun, 24 May 2026 14:30:47 +0200
Subject: [PATCH 14/22] Feat: Game Engine changing fortune
The game engine controller now changes the fortune of a stock based on game results.
---
.../minigames/GameEngineController.java | 75 +++++++++++++++----
1 file changed, 60 insertions(+), 15 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
index 3695ad0..92a9a22 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
@@ -1,8 +1,11 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames;
import edu.ntnu.idi.idatt2003.g40.mappe.model.Stock;
+import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventData;
import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventManager;
+import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventType;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewController;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.WidgetEnum;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.util.Duration;
@@ -12,9 +15,13 @@ public final class GameEngineController extends ViewController {
private int currentScore = 0;
private int frameCounter = 0;
private int secondsRemaining = 60;
+ private char currentRank = 'E';
+ private String rankEffectString;
+ private double fortuneToSet;
private GameGimmick activeGimmick;
private Timeline engineLoop;
private Stock chosenStock;
+ private boolean reportActive = false;
public GameEngineController(final GameEngineView viewElement,
final EventManager eventManager,
@@ -31,23 +38,29 @@ public GameEngineController(final GameEngineView viewElement,
frameCounter = 0;
refreshMetrics();
}
+ if (secondsRemaining <= 0) {
+ reportActive = true;
+ stopGameSession(reportActive);
+ }
}));
engineLoop.setCycleCount(Timeline.INDEFINITE);
}
@Override
protected void initInteractions() {
- getViewElement().setOnAction(MiniGamesActions.INGAME_QUIT, this::stopGameSession);
+ getViewElement().setOnAction(MiniGamesActions.INGAME_QUIT, this::returnToOverview);
+ getViewElement().setOnAction(MiniGamesActions.INGAME_RETURN, this::returnToOverview);
}
public void launchGimmickSession(final GameGimmick gimmick) {
- this.activeGimmick = gimmick;
- this.currentScore = 0;
- this.frameCounter = 0;
- this.secondsRemaining = 60;
+ activeGimmick = gimmick;
+ currentScore = 0;
+ frameCounter = 0;
+ currentRank = 'E';
+ reportActive = false;
+ secondsRemaining = 60;
refreshMetrics();
- // Connect interactions.
getViewElement().setGameGimmickContent(gimmick, (scoreDelta) -> {
if (this.currentScore + scoreDelta >= 0) {
this.currentScore += scoreDelta;
@@ -67,20 +80,52 @@ private void refreshMetrics() {
int seconds = secondsRemaining % 60;
String formattedTime = String.format("%02d:%02d:%02d", hours, minutes, seconds);
- // Dynamic Rank classification engine evaluations
- String rank = "E";
- if (currentScore > 50) rank = "A";
- else if (currentScore > 30) rank = "B";
- else if (currentScore > 15) rank = "C";
- else if (currentScore > 5) rank = "D";
+ if (currentScore > 400) {
+ currentRank = 'S';
+ rankEffectString = "Extremely good fortune awaits " + chosenStock.getSymbol();
+ fortuneToSet = 0.10;
+
+ } else if (currentScore > 300) {
+ currentRank = 'A';
+ rankEffectString = "Really good fortune awaits " + chosenStock.getSymbol();
+ fortuneToSet = 0.5;
+
+ } else if (currentScore > 200) {
+ currentRank = 'B';
+ rankEffectString = "Good fortune awaits " + chosenStock.getSymbol();
+ fortuneToSet = 0.2;
+
+ } else if (currentScore > 150) {
+ currentRank = 'C';
+ rankEffectString = "Bad fortune awaits " + chosenStock.getSymbol();
+ fortuneToSet = -0.2;
+
+ } else if (currentScore > 100) {
+ currentRank = 'D';
+ rankEffectString = "Really bad fortune awaits " + chosenStock.getSymbol();
+ fortuneToSet = -0.5;
- getViewElement().updateMetadataDisplay(currentScore, formattedTime, rank);
+ } else {
+ currentRank = 'E';
+ rankEffectString = "Extremely bad fortune awaits " + chosenStock.getSymbol();
+ fortuneToSet = -0.10;
+ }
+
+ getViewElement().updateMetadataDisplay(currentScore, formattedTime, currentRank);
}
- private void stopGameSession() {
+ private void stopGameSession(final boolean showReport) {
if (engineLoop != null) {
engineLoop.stop();
+ if(showReport) {
+ chosenStock.setFortune(fortuneToSet);
+ getViewElement().showGameReport(currentRank, rankEffectString);
+ }
}
- // Fire architecture EventManager updates here to go back to the menu view cleanly
+ }
+
+ private void returnToOverview() {
+ EventData eventData = new EventData<>(EventType.CHANGE_INGAME_CENTER, WidgetEnum.MINIGAMES_OVERVIEW);
+ invoke(eventData);
}
}
From e3219f2b02267188181f94688b8564a0cacb124b Mon Sep 17 00:00:00 2001
From: =
Date: Sun, 24 May 2026 14:44:54 +0200
Subject: [PATCH 15/22] Docs: Updated javadocs
---
.../g40/mappe/view/widgets/WidgetEnum.java | 29 +++++++
.../minigames/GameEngineController.java | 80 +++++++++++++++++++
.../widgets/minigames/GameEngineView.java | 6 --
3 files changed, 109 insertions(+), 6 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/WidgetEnum.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/WidgetEnum.java
index 5efcbb0..9bf85ac 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/WidgetEnum.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/WidgetEnum.java
@@ -1,10 +1,39 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets;
+/**
+ * Enum used to define the various widgets for the application.
+ *
+ * Primarily handled by the {@link edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.InGameController}
+ * for changing the active section of the game.
+ * */
public enum WidgetEnum {
+ /**
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.dashboard.DashBoardView}.
+ * */
DASHBOARD,
+
+ /**
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.market.MarketView}.
+ * */
MARKET,
+
+ /**
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.MiniGamesView}.
+ * */
MINIGAMES_OVERVIEW,
+
+ /**
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.GameEngineView}.
+ * */
MINIGAMES_ENGINE,
+
+ /**
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.stats.StatsView}.
+ * */
STATS,
+
+ /**
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.transactions.TransactionsView}.
+ * */
TRANSACTIONS
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
index 92a9a22..58912c3 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
@@ -10,19 +10,75 @@
import javafx.animation.Timeline;
import javafx.util.Duration;
+/**
+ * Controller for the {@link GameEngineView}.
+ *
+ * Extends {@link ViewController}
+ * */
public final class GameEngineController extends ViewController {
+ /**
+ * Current score.
+ * */
private int currentScore = 0;
+
+ /**
+ * Current frame for animation loop.
+ * */
private int frameCounter = 0;
+
+ /**
+ * Current seconds remaining before minigame
+ * is over.
+ * */
private int secondsRemaining = 60;
+
+ /**
+ * Current rank the player has for this minigame.
+ * */
private char currentRank = 'E';
+
+ /**
+ * String shown to describe the effect of the game,
+ * based on rank given during report.
+ * */
private String rankEffectString;
+
+ /**
+ * The amount of fortune to apply to the chosen stock,
+ * based on rank gotten.
+ * */
private double fortuneToSet;
+
+ /**
+ * Active {@link GameGimmick} implementation.
+ * */
private GameGimmick activeGimmick;
+
+ /**
+ * {@link Timeline} object functioning as an animation.
+ * */
private Timeline engineLoop;
+
+ /**
+ * Chosen stock to set fortune to based on game results (rank).
+ * */
private Stock chosenStock;
+
+ /**
+ * Whether the report is active or not.
+ *
+ * If report is not active, the player can exit without affecting the market.
+ * If report is active, exiting will cause effect.
+ * */
private boolean reportActive = false;
+ /**
+ * Constructor.
+ *
+ * @param viewElement the associated {@link GameEngineView}.
+ * @param chosenStock the chosen {@link Stock} object.
+ * */
public GameEngineController(final GameEngineView viewElement,
final EventManager eventManager,
final Stock chosenStock) throws IllegalArgumentException {
@@ -52,6 +108,11 @@ protected void initInteractions() {
getViewElement().setOnAction(MiniGamesActions.INGAME_RETURN, this::returnToOverview);
}
+ /**
+ * Launches a given {@link GameGimmick} session.
+ *
+ * @param gimmick the gimmick to launch.
+ * */
public void launchGimmickSession(final GameGimmick gimmick) {
activeGimmick = gimmick;
currentScore = 0;
@@ -70,10 +131,18 @@ public void launchGimmickSession(final GameGimmick gimmick) {
engineLoop.play();
}
+ /**
+ * Setter method for chosen stock.
+ *
+ * @param newStock the new {@link Stock} object to set.
+ * */
public void setChosenStock(final Stock newStock) {
chosenStock = newStock;
}
+ /**
+ * Refreshes the metrics shown and updates appropriate values.
+ * */
private void refreshMetrics() {
int hours = secondsRemaining / 3600;
int minutes = (secondsRemaining % 3600) / 60;
@@ -114,6 +183,14 @@ private void refreshMetrics() {
getViewElement().updateMetadataDisplay(currentScore, formattedTime, currentRank);
}
+ /**
+ * Stops the game session.
+ *
+ * If showReport is true, fortune will be set.
+ * if not, market is unaffected.
+ *
+ * @param showReport value indicating whether to show report or not.
+ * */
private void stopGameSession(final boolean showReport) {
if (engineLoop != null) {
engineLoop.stop();
@@ -124,6 +201,9 @@ private void stopGameSession(final boolean showReport) {
}
}
+ /**
+ * Changes widget to {@link MiniGamesView}.
+ * */
private void returnToOverview() {
EventData eventData = new EventData<>(EventType.CHANGE_INGAME_CENTER, WidgetEnum.MINIGAMES_OVERVIEW);
invoke(eventData);
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineView.java
index 379d6f7..4a9a710 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineView.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineView.java
@@ -120,12 +120,6 @@ public void showGameReport(final char rank,
rankResultLabel = new Label("Final Rank: " + rank);
rankResultLabel.getStyleClass().add("gameEngine-report-rank-result");
- /*String effectText = isPositive
- ? "Performance impact: Positive change for " + stockSymbol + " next week! 📈"
- : "Performance impact: Negative change for " + stockSymbol + " next week... 📉";
-
-
- stockEffectLabel.setStyle("-fx-font-size: 18px; -fx-text-fill: " + (isPositive ? "green;" : "red;"));*/
stockEffectLabel = new Label(effect);
stockEffectLabel.getStyleClass().add("gameEngine-report-effect");
From 004693f17c073c15f62d4510aa329bd14991cbce Mon Sep 17 00:00:00 2001
From: =
Date: Sun, 24 May 2026 16:14:59 +0200
Subject: [PATCH 16/22] Feat: Imported example stock file
---
.../ntnu/idi/idatt2003/g40/mappe/Main.java | 2 +-
.../{dummydata.txt => dummydata.csv} | 0
src/main/resources/sp500.csv | 506 ++++++++++++++++++
3 files changed, 507 insertions(+), 1 deletion(-)
rename src/main/resources/{dummydata.txt => dummydata.csv} (100%)
create mode 100644 src/main/resources/sp500.csv
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
index 7b55201..6162207 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
@@ -78,7 +78,7 @@ public void start(final Stage stage) throws Exception {
ViewManager viewManager = new ViewManager(stage, eventManager);
List stocksInFile;
- FileParser parser1 = new FileParser("/dummydata.txt");
+ FileParser parser1 = new FileParser("/sp500.csv");
FileConverter converter1 = new FileConverter();
stocksInFile = converter1.getStocksFromStrings(parser1.readFile());
diff --git a/src/main/resources/dummydata.txt b/src/main/resources/dummydata.csv
similarity index 100%
rename from src/main/resources/dummydata.txt
rename to src/main/resources/dummydata.csv
diff --git a/src/main/resources/sp500.csv b/src/main/resources/sp500.csv
new file mode 100644
index 0000000..d9cec61
--- /dev/null
+++ b/src/main/resources/sp500.csv
@@ -0,0 +1,506 @@
+# S&P 500 Companies by Market Cap
+# Ticker,Name,Price
+
+NVDA,Nvidia,191.27
+AAPL,Apple Inc.,276.43
+MSFT,Microsoft,404.68
+AMZN,Amazon,204.62
+GOOGL,Alphabet Inc. (Class A),311.20
+GOOG,Alphabet Inc. (Class C),311.62
+META,Meta Platforms,669.41
+AVGO,Broadcom,343.35
+TSLA,Tesla Inc.,426.52
+BRK.B,Berkshire Hathaway,501.05
+WMT,Walmart,128.75
+LLY,Lilly (Eli),1014.43
+JPM,JPMorgan Chase,311.14
+XOM,ExxonMobil,155.28
+V,Visa Inc.,329.54
+JNJ,Johnson & Johnson,240.70
+MA,Mastercard,539.52
+MU,Micron Technology,411.25
+ORCL,Oracle Corporation,157.08
+COST,Costco,979.71
+BAC,Bank of America,54.06
+ABBV,AbbVie,220.17
+HD,Home Depot (The),389.46
+PG,Procter & Gamble,159.45
+CVX,Chevron Corporation,185.66
+CAT,Caterpillar Inc.,773.53
+AMD,Advanced Micro Devices,213.00
+CSCO,Cisco,85.82
+KO,Coca-Cola Company (The),78.51
+NFLX,Netflix,79.94
+GE,GE Aerospace,314.37
+PLTR,Palantir Technologies,135.59
+LRCX,Lam Research,236.60
+MRK,Merck & Co.,118.79
+PM,Philip Morris International,185.99
+GS,Goldman Sachs,949.29
+MS,Morgan Stanley,176.86
+WFC,Wells Fargo,89.07
+AMAT,Applied Materials,342.19
+RTX,RTX Corporation,197.56
+IBM,IBM,273.86
+UNH,UnitedHealth Group,278.79
+AXP,American Express,355.18
+INTC,Intel,47.85
+TMUS,T-Mobile US,207.62
+PEP,PepsiCo,168.71
+MCD,McDonald's,323.50
+GEV,GE Vernova,822.50
+LIN,Linde plc,466.04
+C,Citigroup,117.93
+TXN,Texas Instruments,226.34
+VZ,Verizon,48.55
+T,AT&T,28.21
+TMO,Thermo Fisher Scientific,525.00
+AMGN,Amgen,364.77
+ABT,Abbott Laboratories,112.97
+KLAC,KLA Corporation,1492.27
+GILD,Gilead Sciences,155.71
+DIS,Walt Disney Company (The),108.30
+NEE,NextEra Energy,91.19
+BA,Boeing,236.98
+ANET,Arista Networks,141.06
+APH,Amphenol,144.60
+ISRG,Intuitive Surgical,496.14
+CRM,Salesforce,184.94
+SCHW,Charles Schwab Corporation,95.50
+BLK,BlackRock,1083.35
+TJX,TJX Companies,150.56
+DE,Deere & Company,610.03
+ADI,Analog Devices,336.71
+LOW,Lowe's,286.57
+PFE,Pfizer,27.77
+UNP,Union Pacific Corporation,261.95
+DHR,Danaher Corporation,219.80
+APP,AppLovin Corporation,459.27
+HON,Honeywell,243.56
+ETN,Eaton Corporation,394.94
+QCOM,Qualcomm,141.90
+UBER,Uber,70.72
+LMT,Lockheed Martin,630.54
+WELL,Welltower,208.65
+ACN,Accenture,230.79
+BKNG,Booking Holdings,4322.85
+SYK,Stryker Corporation,362.53
+COP,ConocoPhillips,110.75
+NEM,Newmont,123.89
+COF,Capital One,214.93
+PLD,Prologis,140.35
+MDT,Medtronic,100.87
+CB,Chubb Limited,328.82
+PH,Parker Hannifin,998.24
+PGR,Progressive Corporation,209.33
+BMY,Bristol Myers Squibb,60.18
+HCA,HCA Healthcare,531.83
+SPGI,S&P Global,396.65
+CMCSA,Comcast,32.53
+VRTX,Vertex Pharmaceuticals,459.93
+MCK,McKesson Corporation,944.20
+PANW,Palo Alto Networks,165.49
+GLW,Corning Inc.,134.16
+SBUX,Starbucks,99.03
+INTU,Intuit,401.05
+MO,Altria,65.72
+BSX,Boston Scientific,73.76
+CME,CME Group,303.44
+NOW,ServiceNow,101.55
+ADBE,Adobe Inc.,258.39
+TT,Trane Technologies,473.75
+CRWD,CrowdStrike,414.94
+BX,Blackstone Inc.,133.29
+UPS,United Parcel Service,119.93
+SO,Southern Company,90.86
+CEG,Constellation Energy,274.37
+DUK,Duke Energy,124.86
+CVS,CVS Health,76.36
+MAR,Marriott International,360.71
+NOC,Northrop Grumman,680.45
+PNC,PNC Financial Services,237.28
+WM,Waste Management,234.67
+GD,General Dynamics,348.79
+WDC,Western Digital,277.26
+KKR,KKR,105.28
+HWM,Howmet Aerospace,233.13
+FCX,Freeport-McMoRan,65.30
+NKE,Nike Inc.,62.43
+USB,U.S. Bancorp,59.25
+MMM,3M,173.46
+SHW,Sherwin-Williams,364.16
+RCL,Royal Caribbean Group,331.76
+SNDK,Sandisk Corporation,607.86
+STX,Seagate Technology,409.41
+EMR,Emerson Electric,156.30
+ADP,Automatic Data Processing,217.59
+WMB,Williams Companies,71.48
+ICE,Intercontinental Exchange,153.60
+FDX,FedEx,368.49
+ITW,Illinois Tool Works,298.50
+JCI,Johnson Controls,140.75
+CRH,CRH plc,127.89
+ECL,Ecolab,301.35
+EQIX,Equinix,863.66
+BK,BNY Mellon,122.83
+MRSH,Marsh & McLennan Companies Inc.,174.09
+AMT,American Tower,179.46
+CMI,Cummins,601.45
+SNPS,Synopsys,433.56
+REGN,Regeneron Pharmaceuticals,780.09
+DELL,Dell Technologies,124.37
+CDNS,Cadence Design Systems,298.74
+CTAS,Cintas,201.10
+ORLY,O'Reilly Auto Parts,93.87
+MNST,Monster Beverage,80.88
+MDLZ,Mondelez International,61.45
+PWR,Quanta Services,523.69
+CI,Cigna,292.46
+CSX,CSX Corporation,41.30
+CL,Colgate-Palmolive,95.04
+SLB,Schlumberger,51.14
+HLT,Hilton Worldwide,327.38
+DASH,DoorDash,175.41
+TDG,TransDigm Group,1325.26
+MCO,Moody's Corporation,415.20
+APO,Apollo Global Management,127.53
+ELV,Elevance Health,329.59
+ABNB,Airbnb,119.56
+GM,General Motors,79.78
+NSC,Norfolk Southern Railway,316.73
+COR,Cencora,365.43
+MSI,Motorola Solutions,423.10
+KMI,Kinder Morgan,31.64
+RSG,Republic Services,226.72
+HOOD,Robinhood Markets Inc.,77.55
+WBD,Warner Bros. Discovery,28.01
+TFC,Truist Financial,54.42
+PCAR,Paccar,129.93
+AON,Aon,314.02
+TEL,TE Connectivity,227.16
+APD,Air Products,293.38
+AEP,American Electric Power,122.18
+FTNT,Fortinet,87.72
+TRV,Travelers Companies (The),299.75
+PSX,Phillips 66,161.13
+LHX,L3Harris,341.14
+EOG,EOG Resources,117.39
+SPG,Simon Property Group,195.66
+NXPI,NXP Semiconductors,249.26
+ROST,Ross Stores,192.31
+VLO,Valero Energy,203.89
+AZO,AutoZone,3733.09
+MPC,Marathon Petroleum,207.85
+BKR,Baker Hughes,61.16
+AFL,Aflac,116.20
+DLR,Digital Realty,174.16
+SRE,Sempra,90.83
+O,Realty Income,64.39
+MPWR,Monolithic Power Systems,1197.55
+GWW,W. W. Grainger,1202.13
+ZTS,Zoetis,128.19
+CARR,Carrier Global,66.80
+D,Dominion Energy,64.61
+F,Ford Motor Company,13.78
+URI,United Rentals,870.17
+AME,Ametek,236.33
+VST,Vistra Corp.,160.43
+FAST,Fastenal,47.14
+ALL,Allstate,205.91
+OKE,ONEOK,85.03
+AJG,Arthur J. Gallagher & Co.,207.61
+CAH,Cardinal Health,225.15
+CVNA,Carvana Co.,365.94
+IDXX,Idexx Laboratories,647.63
+MET,MetLife,78.87
+TGT,Target Corporation,114.12
+PSA,Public Storage,293.33
+BDX,Becton Dickinson,179.62
+CTVA,Corteva,75.48
+TER,Teradyne,323.92
+EA,Electronic Arts,201.72
+ADSK,Autodesk,232.93
+FITB,Fifth Third Bancorp,54.59
+CMG,Chipotle Mexican Grill,37.35
+FANG,Diamondback Energy,168.93
+TRGP,Targa Resources,222.03
+FIX,Comfort Systems USA Inc.,1345.62
+DHI,D. R. Horton,163.35
+HSY,Hershey Company (The),231.46
+OXY,Occidental Petroleum,47.34
+DAL,Delta Air Lines,71.16
+ROK,Rockwell Automation,413.43
+NDAQ,Nasdaq Inc.,81.05
+XEL,Xcel Energy,77.79
+EW,Edwards Lifesciences,78.67
+CCL,Carnival,32.80
+CBRE,CBRE Group,151.76
+ETR,Entergy,100.79
+EXC,Exelon,44.57
+AMP,Ameriprise Financial,489.27
+NUE,Nucor,194.78
+DDOG,Datadog,126.70
+YUM,Yum! Brands,160.35
+MCHP,Microchip Technology,80.90
+WAB,Wabtec,255.15
+KR,Kroger,68.68
+AIG,American International Group,79.36
+VMC,Vulcan Materials Company,321.01
+CIEN,Ciena Corporation,301.11
+SYY,Sysco,88.04
+PEG,Public Service Enterprise Group,83.85
+COIN,Coinbase Global,152.61
+ODFL,Old Dominion,195.74
+KEYS,Keysight Technologies,237.88
+KDP,Keurig Dr Pepper,29.84
+VTR,Ventas,85.29
+MLM,Martin Marietta Materials,663.38
+GRMN,Garmin,206.52
+ED,Consolidated Edison,109.36
+HIG,Hartford (The),142.02
+LVS,Las Vegas Sands,57.75
+CPRT,Copart,39.73
+EL,Estée Lauder Companies (The),106.09
+IR,Ingersoll Rand,96.98
+WDAY,Workday Inc.,145.19
+MSCI,MSCI,519.16
+TTWO,Take-Two Interactive,204.25
+RMD,ResMed,259.29
+EBAY,eBay,82.95
+PCG,PG&E Corporation,17.02
+CCI,Crown Castle,85.66
+PYPL,PayPal,40.26
+PRU,Prudential Financial,105.34
+WEC,WEC Energy Group,113.19
+UAL,United Airlines Holdings,113.50
+STT,State Street Corporation,131.37
+HBAN,Huntington Bancshares,18.02
+A,Agilent Technologies,128.22
+GEHC,GE HealthCare,79.29
+MTB,M&T Bank,235.06
+EME,EMCOR Group Inc.,803.53
+ACGL,Arch Capital Group,98.49
+KMB,Kimberly-Clark,107.35
+ROP,Roper Technologies,333.96
+EQT,EQT Corporation,56.73
+KVUE,Kenvue,18.44
+LYV,Live Nation Entertainment,150.60
+OTIS,Otis Worldwide,89.85
+AXON,Axon Enterprise,436.36
+NRG,NRG Energy,160.11
+CTSH,Cognizant,71.22
+IBKR,Interactive Brokers Group,76.54
+PAYX,Paychex,94.49
+FISV,Fiserv Inc.,62.72
+ADM,Archer Daniels Midland,69.24
+XYZ,Block Inc.,53.87
+FICO,Fair Isaac,1369.86
+DG,Dollar General,147.49
+DOV,Dover Corporation,232.52
+ROL,Rollins Inc.,65.74
+HPE,Hewlett Packard Enterprise,23.62
+RJF,Raymond James Financial,159.60
+TPR,Tapestry Inc.,154.43
+VICI,Vici Properties,29.18
+TDY,Teledyne Technologies,657.92
+XYL,Xylem Inc.,126.71
+CHTR,Charter Communications,241.08
+ARES,Ares Management Corporation,137.90
+ULTA,Ulta Beauty,684.25
+STLD,Steel Dynamics,206.43
+EXR,Extra Space Storage,142.02
+LEN,Lennar,120.76
+IQV,IQVIA,175.80
+IRM,Iron Mountain,99.67
+KHC,Kraft Heinz,24.88
+PPG,PPG Industries,130.53
+HAL,Halliburton,34.84
+ATO,Atmos Energy,175.22
+DTE,DTE Energy,139.17
+TSCO,Tractor Supply,54.53
+EXPE,Expedia Group,235.08
+CFG,Citizens Financial Group,66.87
+AEE,Ameren,106.08
+TPL,Texas Pacific Land Corporation,416.14
+CBOE,Cboe Global Markets,271.99
+ON,ON Semiconductor,70.68
+MTD,Mettler Toledo,1391.33
+STZ,Constellation Brands,163.02
+BIIB,Biogen,191.29
+DVN,Devon Energy,44.78
+FE,FirstEnergy,47.94
+JBL,Jabil,260.92
+NTRS,Northern Trust,147.45
+HUBB,Hubbell Incorporated,513.63
+WTW,Willis Towers Watson,282.86
+WRB,W. R. Berkley Corporation,71.20
+RF,Regions Financial Corporation,30.86
+PHM,PulteGroup,139.04
+CNP,CenterPoint Energy,40.91
+PPL,PPL Corporation,35.97
+DXCM,Dexcom,68.19
+SW,Smurfit WestRock,50.23
+ES,Eversource Energy,69.77
+GIS,General Mills,48.40
+EIX,Edison International,66.94
+IP,International Paper,48.64
+WSM,Williams-Sonoma,214.52
+CINF,Cincinnati Financial,164.11
+LUV,Southwest Airlines,51.66
+AVB,AvalonBay Communities,179.80
+SYF,Synchrony Financial,72.95
+FIS,Fidelity National Information Services,48.73
+KEY,KeyCorp,22.67
+DLTR,Dollar Tree,125.35
+EQR,Equity Residential,65.09
+EXE,Expand Energy,103.09
+DRI,Darden Restaurants,212.58
+FSLR,First Solar,227.60
+DOW,Dow Inc.,33.98
+CPAY,Corpay,346.25
+AWK,American Water Works,123.54
+CHD,Church & Dwight,100.17
+LH,LabCorp,289.08
+VRSK,Verisk Analytics,171.87
+Q,Qnity Electronics,114.06
+CTRA,Coterra,31.48
+STE,Steris,243.09
+EFX,Equifax,197.29
+VLTO,Veralto,95.33
+BG,Bunge Global,121.39
+DGX,Quest Diagnostics,209.53
+CHRW,C.H. Robinson,196.77
+AMCR,Amcor,49.62
+TSN,Tyson Foods,64.52
+L,Loews Corporation,110.15
+CMS,CMS Energy,74.16
+BRO,Brown & Brown,67.07
+LDOS,Leidos,174.83
+PKG,Packaging Corporation of America,244.06
+JBHT,J.B. Hunt,231.62
+OMC,Omnicom Group,69.53
+EXPD,Expeditors International,163.06
+RL,Ralph Lauren Corporation,359.55
+NVR,NVR Inc.,8082.38
+DD,DuPont,51.29
+HUM,Humana,176.34
+NI,NiSource,44.78
+NTAP,NetApp,105.69
+GPC,Genuine Parts Company,149.43
+LULU,Lululemon Athletica,176.88
+ALB,Albemarle Corporation,176.03
+TROW,T. Rowe Price,94.24
+PFG,Principal Financial Group,92.86
+CSGP,CoStar Group,48.09
+GPN,Global Payments,72.67
+SBAC,SBA Communications,190.43
+SNA,Snap-on,383.21
+CNC,Centene Corporation,40.26
+VRSN,Verisign,215.66
+WAT,Waters Corporation,331.52
+IFF,International Flavors & Fragrances,76.65
+BR,Broadridge Financial Solutions,167.88
+WY,Weyerhaeuser,27.09
+INCY,Incyte,99.35
+LII,Lennox International,553.57
+LYB,LyondellBasell,59.29
+SMCI,Supermicro,31.69
+MKC,McCormick & Company,70.30
+ZBH,Zimmer Biomet,95.21
+PTC,PTC Inc.,155.52
+FTV,Fortive,58.93
+VTRS,Viatris,16.02
+EVRG,Evergy,78.94
+BALL,Ball Corporation,67.29
+HPQ,HP Inc.,19.63
+WST,West Pharmaceutical Services,247.87
+PODD,Insulet Corporation,253.09
+APTV,Aptiv,83.64
+CDW,CDW,135.32
+LNT,Alliant Energy,68.17
+TXT,Textron,96.68
+ESS,Essex Property Trust,262.76
+HOLX,Hologic,75.11
+J,Jacobs Solutions,142.70
+INVH,Invitation Homes,27.16
+TKO,TKO Group Holdings,210.88
+NDSN,Nordson Corporation,295.64
+DECK,Deckers Brands,115.15
+PNR,Pentair,99.79
+COO,Cooper Companies (The),82.84
+MAA,Mid-America Apartment Communities,136.74
+FFIV,F5 Inc.,282.22
+MAS,Masco,76.24
+IEX,IDEX Corporation,211.28
+MRNA,Moderna,40.21
+TRMB,Trimble Inc.,65.06
+ALLE,Allegion,179.40
+HII,Huntington Ingalls Industries,392.15
+CLX,Clorox,125.65
+CF,CF Industries,97.23
+GEN,Gen Digital,24.64
+AVY,Avery Dennison,192.77
+KIM,Kimco Realty,21.96
+HAS,Hasbro,105.26
+ERIE,Erie Indemnity,279.84
+TYL,Tyler Technologies,339.51
+UHS,Universal Health Services,231.22
+BEN,Franklin Resources,27.64
+ALGN,Align Technology,197.24
+SOLV,Solventum,81.25
+BBY,Best Buy,66.84
+REG,Regency Centers,76.49
+SWK,Stanley Black & Decker,90.31
+BF.B,Brown–Forman,30.11
+BLDR,Builders FirstSource,125.44
+HST,Host Hotels & Resorts,19.98
+AKAM,Akamai Technologies,95.00
+EG,Everest Group,331.67
+UDR,UDR Inc.,39.84
+TTD,The Trade Desk Inc.,27.19
+HRL,Hormel Foods,23.79
+DPZ,Domino's,385.50
+ZBRA,Zebra Technologies,250.71
+GNRC,Generac,214.94
+FOX,Fox Corporation (Class B),56.02
+FOXA,Fox Corporation (Class A),61.76
+GDDY,GoDaddy,91.44
+PSKY,Paramount Skydance Corp,10.96
+WYNN,Wynn Resorts,115.18
+JKHY,Jack Henry & Associates,165.63
+CPT,Camden Property Trust,111.66
+DOC,Healthpeak Properties,16.95
+SJM,J.M. Smucker Company (The),109.98
+IVZ,Invesco,26.42
+AES,AES Corporation,16.45
+IT,Gartner,160.21
+GL,Globe Life,144.35
+BAX,Baxter International,22.30
+PNW,Pinnacle West,95.57
+RVTY,Revvity,100.89
+AOS,A. O. Smith,80.03
+AIZ,Assurant,216.77
+TAP,Molson Coors Beverage Company,52.98
+NCLH,Norwegian Cruise Line Holdings,22.76
+POOL,Pool Corporation,270.70
+EPAM,EPAM Systems,180.79
+APA,APA Corporation,28.11
+TECH,Bio-Techne,63.46
+MOS,Mosaic Company (The),31.21
+BXP,BXP Inc.,61.61
+DVA,DaVita,144.55
+SWKS,Skyworks Solutions,63.62
+HSIC,Henry Schein,81.21
+CAG,Conagra Brands,19.95
+MGM,MGM Resorts,36.39
+ARE,Alexandria Real Estate Equities,53.92
+FRT,Federal Realty Investment Trust,107.14
+CPB,Campbell Soup Company,29.16
+NWSA,News Corp (Class A),23.30
+CRL,Charles River Laboratories,164.83
+MTCH,Match Group,31.27
+FDS,FactSet,193.29
+LW,Lamb Weston,50.33
+PAYC,Paycom,117.68
+MOH,Molina Healthcare,122.46
+NWS,News Corp (Class B),26.91
From 5f53564c3fbe03483d34289a9480fc7c03b451fd Mon Sep 17 00:00:00 2001
From: =
Date: Sun, 24 May 2026 16:57:37 +0200
Subject: [PATCH 17/22] Feat: Added help section in minigames overview
---
.../minigames/MiniGamesController.java | 20 ++-
.../view/widgets/minigames/MiniGamesView.java | 159 ++++++++++++++++--
2 files changed, 161 insertions(+), 18 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesController.java
index ee9a2d9..acad65a 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesController.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesController.java
@@ -1,7 +1,10 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames;
import edu.ntnu.idi.idatt2003.g40.mappe.model.Stock;
+import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventData;
import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventManager;
+import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventSubscriber;
+import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventType;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewController;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.InGameView;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.games.ClickerGame;
@@ -13,7 +16,9 @@
*
* Extends {@link ViewController}
* */
-public final class MiniGamesController extends ViewController {
+public final class MiniGamesController
+ extends ViewController
+ implements EventSubscriber {
/**
* The currently selected stock for the minigame.
@@ -81,13 +86,14 @@ public MiniGamesController(final MiniGamesView viewElement,
this.findStockGame = findStockGame;
this.timeInputsGame = timeInputsGame;
super(viewElement, eventManager);
+ eventManager.addSubscriber(this, EventType.SELECT_STOCK_FOR_MINIGAME);
refresh();
}
@Override
protected void initInteractions() {
getViewElement().setOnAction(MiniGamesActions.HELP, () -> {
- // Implement help dialog or print logic
+ getViewElement().showHelpSection();
});
getViewElement().setOnAction(MiniGamesActions.CLICKER_GAME, () -> {
@@ -109,10 +115,11 @@ protected void initInteractions() {
/**
* Sets the target stock context for the minigames.
*
- * @param stock Chosen active layout context stock.
+ * @param stock stock to set.
*/
public void setActiveStock(final Stock stock) {
this.activeStock = stock;
+ getViewElement().setSelectedStockText(stock.getSymbol());
gameEngineController.setChosenStock(stock);
refresh();
}
@@ -127,4 +134,11 @@ public void refresh() {
getViewElement().setSelectedStockText("None");
}
}
+
+ @Override
+ public void handleEvent(EventData data) {
+ if (data.data() instanceof Stock s) {
+ setActiveStock(s);
+ }
+ }
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java
index ca00af3..633c400 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java
@@ -1,12 +1,18 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewElement;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
+import javafx.scene.control.ScrollPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
+import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
+import javafx.scene.text.TextFlow;
/**
* Minigames view in the in game section of the application.
@@ -17,7 +23,13 @@
* To see the elements creating the minigames themselves,
* see {@link GameEngineView}.
* */
-public final class MiniGamesView extends ViewElement {
+public final class MiniGamesView
+ extends ViewElement {
+
+ /**
+ * Main layout container.
+ * */
+ private VBox mainLayoutContainer;
/**
* Top section of the page (Title, selected stock, question mark block).
@@ -72,21 +84,146 @@ public final class MiniGamesView extends ViewElement {
* */
private Button timeInputsBtn;
+ /**
+ * Overlay for help section when pressing help button.
+ * */
+ private StackPane helpOverlay;
+
/**
* Constructor.
*/
public MiniGamesView() throws IllegalArgumentException {
- super(new VBox(), MiniGamesActions.class);
+ super(new StackPane(), MiniGamesActions.class);
+ }
+
+ /**
+ * Updates the selected stock text.
+ *
+ * @param symbol the symbol representing the stock selected.
+ */
+ public void setSelectedStockText(final String symbol) {
+ stockValueLabel.setText(symbol);
+ }
+
+ /**
+ * Method for showing the help section for minigames.
+ * */
+ public void showHelpSection() {
+ if (helpOverlay != null) {
+ return;
+ }
+
+ helpOverlay = new StackPane();
+ helpOverlay.getStyleClass().add("minigames-help-overlay-dimmer");
+
+ StackPane modalCard = new StackPane();
+ modalCard.getStyleClass().add("minigames-help-container");
+
+ VBox textContainer = new VBox();
+ textContainer.getStyleClass().add("minigames-help-text-vbox");
+
+ textContainer.getChildren().add(createTextParagraph("MINIGAMES",
+ "Welcome to the minigames section! Here you can boost a selected stock (choose in dashboard page)"
+ + " by playing minigames! A minigame takes one minute, and you are able to exit before the time runs out."
+ + " This will not have any negative effects. "
+ + " When you complete a minigame, you get a rank based on your score. Higher scores yield a higher rank."
+ + " The higher rank you are at the end of the round, the more fortune the selected stock will get."
+ + " Every stock can only be boosted one time per week by playing minigames, so play minigames for all your investments!"));
+
+ textContainer.getChildren().add(createTextParagraph("What are minigames?",
+ "A minigame is a short interactive experience where you are able to gain points by performing"
+ + " task(s) that are differ from minigame to minigame. Each minigame session takes exactly one minute to complete"
+ + " from start to finish, and you will gain a report based on your performance at the end of the round."
+ + " You can also choose to exit before a round ends to go back, but note that quitting after the round ends"
+ + " will still cause the effect."));
+
+ textContainer.getChildren().add(createTextParagraph("Rank",
+ "When playing minigames, you gain score. By earning enough score, you increase your rank."
+ + " At the end of a round, you are given a game report that shows your rank."
+ + " The higher your rank, the better the fortune for the selected stock will be."));
+
+ textContainer.getChildren().add(createTextParagraph("Fortune",
+ "In the minigame page, you can see your selected stock. This stock will then get a"
+ + " positive or negative flat percent amount added to their next weekly price change, based on your rank."
+ + " This is called the stocks fortune."
+ + " Each stock can only be manipulated once per week by playing minigames, so be sure to"
+ + " play minigames for all your investments!"));
+
+ textContainer.getChildren().add(createTextParagraph("Minigame 1: Clicker Minigame",
+ "Click the primary action tile to increase points. Balance your point allocation strategy between immediate click returns and structural upgrades."));
+
+ textContainer.getChildren().add(createTextParagraph("Minigame 2: Find The Stock",
+ "Scan the choice matrix panel grid and find the symbol matching the target description. Incorrect selections will deduct points."));
+
+ textContainer.getChildren().add(createTextParagraph("Minigame 3: Timed Inputs.",
+ "Track the white line that moves across the circle circumference. Fire your strike command inputs using SPACE or ENTER precisely inside the highlighted chartreuse section"
+ + " to gain points. Incorrect firing will deduct points."));
+
+ ScrollPane scrollPane = new ScrollPane(textContainer);
+ scrollPane.getStyleClass().add("minigames-help-scroll-pane");
+ scrollPane.setFitToWidth(true);
+ scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
+ scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
+
+ modalCard.getChildren().add(scrollPane);
+
+ Button closeBtn = new Button("X");
+ closeBtn.setFocusTraversable(false);
+
+ closeBtn.getStyleClass().add("minigames-help-closeBtn");
+
+ closeBtn.setOnAction(e -> hideHelpSection());
+
+ modalCard.getChildren().add(closeBtn);
+ StackPane.setAlignment(closeBtn, Pos.TOP_RIGHT);
+ StackPane.setMargin(closeBtn, new Insets(10, 10, 0, 0));
+
+ helpOverlay.getChildren().add(modalCard);
+ getRootPane().getChildren().add(helpOverlay);
+ }
+
+ /**
+ * Helper method for formatting a {@link TextFlow}
+ * object with a header and paragraph.
+ *
+ * @param headerText the title of the paragraph.
+ * @param descText the paragraph itself.
+ *
+ * @return formatted {@link TextFlow} object.
+ */
+ private TextFlow createTextParagraph(final String headerText,
+ final String descText) {
+ TextFlow textFlow = new TextFlow();
+ Text header = new Text(headerText + "\n");
+ Text desc = new Text(descText);
+
+ textFlow.getStyleClass().add("minigames-help-textflow");
+ header.getStyleClass().add("minigames-help-header");
+ desc.getStyleClass().add("minigames-help-description");
+
+ textFlow.getChildren().addAll(header, desc);
+ return textFlow;
+ }
+
+ /**
+ * Cleans down the operational help window layer state.
+ */
+ public void hideHelpSection() {
+ if (helpOverlay != null) {
+ getRootPane().getChildren().remove(helpOverlay);
+ helpOverlay = null;
+ }
}
@Override
protected void initLayout() {
+ mainLayoutContainer = new VBox();
headerBar = new HBox();
- titleLabel = new Label("Mini games");
+ titleLabel = new Label("Minigames");
stockSelectionRow = new HBox();
selectedStockLabel = new Label("Selected stock: ");
- stockValueLabel = new Label("AAPL");
+ stockValueLabel = new Label("");
stockSelectionRow.getChildren().addAll(selectedStockLabel, stockValueLabel);
VBox titleSection = new VBox();
@@ -112,7 +249,8 @@ protected void initLayout() {
findStockBtn, timeInputsBtn);
VBox.setVgrow(gamesContainer, Priority.ALWAYS);
- getRootPane().getChildren().addAll(headerBar, gamesContainer);
+ mainLayoutContainer.getChildren().addAll(headerBar, gamesContainer);
+ getRootPane().getChildren().add(mainLayoutContainer);
registerButton(MiniGamesActions.HELP, helpBtn);
registerButton(MiniGamesActions.CLICKER_GAME, clickerGameBtn);
@@ -120,18 +258,9 @@ protected void initLayout() {
registerButton(MiniGamesActions.TIME_CLICKS, timeInputsBtn);
}
- /**
- * Updates the selected stock text.
- *
- * @param symbol the symbol representing the stock selected.
- */
- public void setSelectedStockText(final String symbol) {
- stockValueLabel.setText(symbol);
- }
-
@Override
protected void initStyling() {
- getRootPane().getStyleClass().add("minigames-root");
+ mainLayoutContainer.getStyleClass().add("minigames-root");
headerBar.getStyleClass().add("minigames-headerBar");
stockSelectionRow.getStyleClass().add("minigames-stockSelectionRow");
titleLabel.getStyleClass().add("minigames-titleLabel");
From db2bcfc5fc8ca05f6fb71fc1d0cf2145b73328cf Mon Sep 17 00:00:00 2001
From: =
Date: Sun, 24 May 2026 16:57:54 +0200
Subject: [PATCH 18/22] Feat: Added css layout for additions
---
src/main/resources/styles.css | 59 +++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/src/main/resources/styles.css b/src/main/resources/styles.css
index ad0cde6..8b78901 100644
--- a/src/main/resources/styles.css
+++ b/src/main/resources/styles.css
@@ -177,6 +177,8 @@
.summary-container {
-fx-border-color: black;
-fx-border-width: 1 0 1 0;
+ -fx-max-height: 100px;
+ -fx-min-height: 100px;
-fx-padding: 10;
}
@@ -867,6 +869,63 @@
.minigames-cardBtn:hover, .minigames-helpBtn:hover {
-fx-background-color: #c0c0c0;
}
+
+.minigames-help-overlay-dimmer {
+ -fx-background-color: rgba(0, 0, 0, 0.6);
+ -fx-alignment: center;
+}
+
+.minigames-help-container {
+ -fx-alignment: CENTER;
+ -fx-max-width: 700px;
+ -fx-max-height: 500px;
+ -fx-pref-width: 700px;
+ -fx-pref-height: 500px;
+ -fx-background-color: #ffffff;
+ -fx-border-color: #333333;
+ -fx-border-width: 2px;
+ -fx-border-radius: 5px;
+ -fx-background-radius: 5px;
+}
+
+.minigames-help-text-vbox {
+ -fx-spacing: 20px;
+ -fx-alignment: TOP_LEFT;
+ -fx-padding: 20px, 20px, 20px,20px;
+ -fx-background-color: transparent;
+}
+
+.minigames-help-scroll-pane {
+ -fx-background-color: transparent;
+ -fx-background-insets: 0;
+ -fx-padding: 10px;
+}
+
+.minigames-help-closeBtn {
+ -fx-pref-width: 40px;
+ -fx-pref-height: 40px;
+ -fx-background-color: #333333;
+ -fx-text-fill: white;
+ -fx-font-weight: bold;
+ -fx-font-size: 18px;
+ -fx-background-radius: 20px;
+ -fx-border-radius: 20px;
+ -fx-cursor: hand;
+}
+
+.minigames-help-textflow {
+ -fx-pref-width: 600;
+}
+
+.minigames-help-header {
+ -fx-font-weight: bold;
+ -fx-font-size: 20px;
+}
+
+.minigames-help-description {
+ -fx-font-size: 16px;
+}
+
/* --------------------------------------------- */
/* --------- MINIGAMES ENGINE CONTEXT ---------- */
.gameEngine-root {
From 3ab8e989a854d4798ada1c56049c68ee4272d4b6 Mon Sep 17 00:00:00 2001
From: =
Date: Sun, 24 May 2026 17:06:12 +0200
Subject: [PATCH 19/22] Feat: Minigames integration
Integrated minigames with the application.
It is now possible to select a stock you want to boost in dashboard page. This will take you to the minigames section and select the stock for you.
---
.../g40/mappe/service/event/EventType.java | 16 +++++++++++++++-
.../view/widgets/dashboard/DashBoardActions.java | 7 ++++++-
.../widgets/dashboard/DashBoardController.java | 8 ++++++++
.../view/widgets/dashboard/DashBoardView.java | 15 ++++++++++++++-
4 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventType.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventType.java
index 777602d..ace4933 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventType.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/service/event/EventType.java
@@ -36,7 +36,21 @@ public enum EventType implements EventChannel {
* @see edu.ntnu.idi.idatt2003.g40.mappe.view.ingame.InGameController
*
*/
- CHANGE_INGAME_CENTER;
+ CHANGE_INGAME_CENTER,
+
+ /**
+ * Event type representing events that change the center view to
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.MiniGamesView},
+ * and selects a given stock for the minigames.
+ *
+ * Primarily handled by the active
+ * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.MiniGamesController}
+ * object.
+ *
+ * @see edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.dashboard.DashBoardController
+ *
+ */
+ SELECT_STOCK_FOR_MINIGAME;
/**
* {@inheritDoc}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardActions.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardActions.java
index 75b6639..1e92502 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardActions.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardActions.java
@@ -32,5 +32,10 @@ public enum DashBoardActions {
/**
* Increasing quantity of shares to buy/sell by five.
* */
- INCREASE_5;
+ INCREASE_5,
+
+ /**
+ * Selecting viewed stock to boost by playing minigames.
+ * */
+ MINIGAME;
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardController.java
index 64280dc..9d31d0d 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardController.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardController.java
@@ -2,9 +2,12 @@
import edu.ntnu.idi.idatt2003.g40.mappe.engine.Exchange;
import edu.ntnu.idi.idatt2003.g40.mappe.model.*;
+import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventData;
import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventManager;
+import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventType;
import edu.ntnu.idi.idatt2003.g40.mappe.utils.Validator;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewController;
+import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.WidgetEnum;
import javafx.scene.control.Button;
import javafx.scene.control.TextFormatter;
import java.math.BigDecimal;
@@ -180,6 +183,11 @@ protected void initInteractions() {
.add(new BigDecimal("5")).toString());
});
+ getViewElement().setOnAction(DashBoardActions.MINIGAME, () -> {
+ invoke(new EventData<>(EventType.SELECT_STOCK_FOR_MINIGAME, getViewElement().getCurrentStock()));
+ invoke(new EventData<>(EventType.CHANGE_INGAME_CENTER, WidgetEnum.MINIGAMES_OVERVIEW));
+ });
+
exchange.weekProperty().addListener((observable,o,n) -> {
getViewElement().updateGraph(selectedTimeRange);
populateStockList(selectedFilter);
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardView.java
index 6ba9bb8..d7edb2a 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardView.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardView.java
@@ -173,6 +173,11 @@ public final class DashBoardView extends ViewElement {
* */
private Button sellSharesBtn;
+ /**
+ * Button to boost this stock.
+ * */
+ private Button boostStockBtn;
+
/**
* The selected stock symbol label.
* */
@@ -268,7 +273,13 @@ protected void initLayout() {
stockFullNameLabel = new Label();
ownedQuantityLabel = new Label();
- stockIdentity.getChildren().addAll(selectedStockLabel, stockFullNameLabel, ownedQuantityLabel);
+ boostStockBtn = new Button("Boost");
+ stockIdentity.getChildren().addAll(
+ selectedStockLabel,
+ stockFullNameLabel,
+ ownedQuantityLabel,
+ boostStockBtn
+ );
priceStats = new VBox();
selectedStockPriceLabel = new Label();
@@ -334,6 +345,7 @@ protected void initLayout() {
registerButton(DashBoardActions.DECREASE_1, m1QtyBtn);
registerButton(DashBoardActions.INCREASE_1, p1QtyBtn);
registerButton(DashBoardActions.INCREASE_5, p5QtyBtn);
+ registerButton(DashBoardActions.MINIGAME, boostStockBtn);
}
private ColumnConstraints makeCol(final float w) {
@@ -349,6 +361,7 @@ protected void initStyling() {
completeSideBar.getStyleClass().add("dashboard-complete-sidebar");
sidebar.getStyleClass().add("dashboard-sidebar-content");
selectedStockLabel.getStyleClass().add("dashboard-selected-stock-pill");
+ boostStockBtn.getStyleClass().add("dashboard-selected-stock-pill");
selectedStockPriceLabel.getStyleClass().add("dashboard-selected-stock-pill");
shareQuantityInputField.getStyleClass().add("dashboard-qtyTextField");
chart.getStyleClass().add("dashboard-chart");
From 5253d19f9cb957d7d9c265e0129ad7af6e8bfb6d Mon Sep 17 00:00:00 2001
From: =
Date: Sun, 24 May 2026 17:54:23 +0200
Subject: [PATCH 20/22] Feat: Fixed clicker game
Fixed bug where player could buy upgrade even if they did not have enough score, by adding an internal reference to score in the clicker game game.
---
.../widgets/minigames/games/ClickerGame.java | 26 +++++++++++++------
1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/ClickerGame.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/ClickerGame.java
index f2d9f06..b7fd9d7 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/ClickerGame.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/ClickerGame.java
@@ -25,6 +25,11 @@ public final class ClickerGame
* */
private int clickValue;
+ /**
+ * Local reference to current score.
+ */
+ private int score;
+
/**
* The current cost of upgrading the amount gained per click.
* */
@@ -71,17 +76,22 @@ public Node getCanvasNode() {
@Override
public void initialize(final IntConsumer scoreModifier) {
-
- clickBtn.setOnAction(e -> scoreModifier.accept(clickValue));
+ score = 0;
+ clickBtn.setOnAction(e -> {
+ scoreModifier.accept(clickValue);
+ score += clickValue;
+ });
upgradeBtn.setOnAction(e -> {
- // TODO: Change validation to only upgrade if enough score.
scoreModifier.accept(-upgradeCost);
- clickValue += 1;
- upgradeCost *= 2;
- clickBtn.setText("+" + clickValue);
- upgradeBtn.setText("+" + clickValue + " per click\n-"
- + upgradeCost + " points");
+ if (upgradeCost <= score) {
+ score -= upgradeCost;
+ clickValue += 1;
+ upgradeCost *= 2;
+ clickBtn.setText("+" + clickValue);
+ upgradeBtn.setText("+1 per click\n-"
+ + upgradeCost + " points");
+ }
});
}
From 8888d4431b53f7b3be0124e82bd8c0a1f106294a Mon Sep 17 00:00:00 2001
From: =
Date: Sun, 24 May 2026 18:52:21 +0200
Subject: [PATCH 21/22] Feat: Rebalancing/timing for minigames
Reduced time for minigames, and increased amount of points gained to compensate.
---
.../minigames/GameEngineController.java | 20 +++++++++----------
.../minigames/games/FindStockGame.java | 4 ++--
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
index 58912c3..27d6366 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
@@ -20,23 +20,23 @@ public final class GameEngineController extends ViewController {
/**
* Current score.
* */
- private int currentScore = 0;
+ private int currentScore;
/**
* Current frame for animation loop.
* */
- private int frameCounter = 0;
+ private int frameCounter;
/**
* Current seconds remaining before minigame
* is over.
* */
- private int secondsRemaining = 60;
+ private int secondsRemaining;
/**
* Current rank the player has for this minigame.
* */
- private char currentRank = 'E';
+ private char currentRank;
/**
* String shown to describe the effect of the game,
@@ -119,7 +119,7 @@ public void launchGimmickSession(final GameGimmick gimmick) {
frameCounter = 0;
currentRank = 'E';
reportActive = false;
- secondsRemaining = 60;
+ secondsRemaining = 20;
refreshMetrics();
getViewElement().setGameGimmickContent(gimmick, (scoreDelta) -> {
@@ -149,27 +149,27 @@ private void refreshMetrics() {
int seconds = secondsRemaining % 60;
String formattedTime = String.format("%02d:%02d:%02d", hours, minutes, seconds);
- if (currentScore > 400) {
+ if (currentScore > 150) {
currentRank = 'S';
rankEffectString = "Extremely good fortune awaits " + chosenStock.getSymbol();
fortuneToSet = 0.10;
- } else if (currentScore > 300) {
+ } else if (currentScore > 120) {
currentRank = 'A';
rankEffectString = "Really good fortune awaits " + chosenStock.getSymbol();
fortuneToSet = 0.5;
- } else if (currentScore > 200) {
+ } else if (currentScore > 80) {
currentRank = 'B';
rankEffectString = "Good fortune awaits " + chosenStock.getSymbol();
fortuneToSet = 0.2;
- } else if (currentScore > 150) {
+ } else if (currentScore > 50) {
currentRank = 'C';
rankEffectString = "Bad fortune awaits " + chosenStock.getSymbol();
fortuneToSet = -0.2;
- } else if (currentScore > 100) {
+ } else if (currentScore > 20) {
currentRank = 'D';
rankEffectString = "Really bad fortune awaits " + chosenStock.getSymbol();
fortuneToSet = -0.5;
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/FindStockGame.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/FindStockGame.java
index 28d92ee..c70ca90 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/FindStockGame.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/FindStockGame.java
@@ -118,9 +118,9 @@ private void generateRound() {
* */
private void handleChoice(final String chosen) {
if (chosen.equals(targetSymbol)) {
- scoreModifier.accept(2);
+ scoreModifier.accept(14);
} else {
- scoreModifier.accept(-1);
+ scoreModifier.accept(-7);
}
generateRound();
}
From 544cae73fc31263290c09a85d397f181bb4be021 Mon Sep 17 00:00:00 2001
From: =
Date: Sun, 24 May 2026 20:47:51 +0200
Subject: [PATCH 22/22] Feat: Clicker game rework
Reworked the clicker game. Previously, the game was designed around clicking a static button and buying an upgrade for it. Now, the game works more like an aim trainer, where the button teleports after every click.
---
.../minigames/GameEngineController.java | 10 +-
.../view/widgets/minigames/MiniGamesView.java | 16 ++--
.../widgets/minigames/games/ClickerGame.java | 92 ++++++++++---------
src/main/resources/styles.css | 10 +-
4 files changed, 68 insertions(+), 60 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
index 27d6366..206cba1 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/GameEngineController.java
@@ -149,27 +149,27 @@ private void refreshMetrics() {
int seconds = secondsRemaining % 60;
String formattedTime = String.format("%02d:%02d:%02d", hours, minutes, seconds);
- if (currentScore > 150) {
+ if (currentScore >= 150) {
currentRank = 'S';
rankEffectString = "Extremely good fortune awaits " + chosenStock.getSymbol();
fortuneToSet = 0.10;
- } else if (currentScore > 120) {
+ } else if (currentScore >= 120) {
currentRank = 'A';
rankEffectString = "Really good fortune awaits " + chosenStock.getSymbol();
fortuneToSet = 0.5;
- } else if (currentScore > 80) {
+ } else if (currentScore >= 80) {
currentRank = 'B';
rankEffectString = "Good fortune awaits " + chosenStock.getSymbol();
fortuneToSet = 0.2;
- } else if (currentScore > 50) {
+ } else if (currentScore >= 50) {
currentRank = 'C';
rankEffectString = "Bad fortune awaits " + chosenStock.getSymbol();
fortuneToSet = -0.2;
- } else if (currentScore > 20) {
+ } else if (currentScore >= 20) {
currentRank = 'D';
rankEffectString = "Really bad fortune awaits " + chosenStock.getSymbol();
fortuneToSet = -0.5;
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java
index 633c400..dad45a7 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/MiniGamesView.java
@@ -122,17 +122,18 @@ public void showHelpSection() {
VBox textContainer = new VBox();
textContainer.getStyleClass().add("minigames-help-text-vbox");
- textContainer.getChildren().add(createTextParagraph("MINIGAMES",
+ textContainer.getChildren().add(createTextParagraph("Minigames",
"Welcome to the minigames section! Here you can boost a selected stock (choose in dashboard page)"
- + " by playing minigames! A minigame takes one minute, and you are able to exit before the time runs out."
+ + " by playing minigames! A minigame takes 20 seconds, and you are able to exit before the time runs out."
+ " This will not have any negative effects. "
+ " When you complete a minigame, you get a rank based on your score. Higher scores yield a higher rank."
+ " The higher rank you are at the end of the round, the more fortune the selected stock will get."
- + " Every stock can only be boosted one time per week by playing minigames, so play minigames for all your investments!"));
+ + " Every stock can only be boosted one time per week by playing minigames, so play minigames for all your investments!"
+ + " (Multiple minigames for same stock overrides previous fortune.)"));
textContainer.getChildren().add(createTextParagraph("What are minigames?",
"A minigame is a short interactive experience where you are able to gain points by performing"
- + " task(s) that are differ from minigame to minigame. Each minigame session takes exactly one minute to complete"
+ + " task(s) that are differ from minigame to minigame. Each minigame session takes 20 seconds to complete"
+ " from start to finish, and you will gain a report based on your performance at the end of the round."
+ " You can also choose to exit before a round ends to go back, but note that quitting after the round ends"
+ " will still cause the effect."));
@@ -146,11 +147,12 @@ public void showHelpSection() {
"In the minigame page, you can see your selected stock. This stock will then get a"
+ " positive or negative flat percent amount added to their next weekly price change, based on your rank."
+ " This is called the stocks fortune."
- + " Each stock can only be manipulated once per week by playing minigames, so be sure to"
- + " play minigames for all your investments!"));
+ + " Each stock can only have a single fortune active per week, so be sure to"
+ + " play minigames for all your investments! Playing multiple minigames for the same"
+ + " stock will override the stocks' fortune."));
textContainer.getChildren().add(createTextParagraph("Minigame 1: Clicker Minigame",
- "Click the primary action tile to increase points. Balance your point allocation strategy between immediate click returns and structural upgrades."));
+ "Click the button to earns points. The button changes location after every click!"));
textContainer.getChildren().add(createTextParagraph("Minigame 2: Find The Stock",
"Scan the choice matrix panel grid and find the symbol matching the target description. Incorrect selections will deduct points."));
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/ClickerGame.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/ClickerGame.java
index b7fd9d7..3fe6d86 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/ClickerGame.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/minigames/games/ClickerGame.java
@@ -6,67 +6,71 @@
import java.util.function.IntConsumer;
import javafx.scene.Node;
import javafx.scene.control.Button;
-import javafx.scene.layout.VBox;
+import javafx.scene.layout.Pane;
/**
- * Clicker minigame, found in the
- * {@link edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.minigames.MiniGamesView}.
+ * Clicker minigame where the goal is to hit the targets as much
+ * as possible.
*
* Extends {@link ViewElement}
*
* Implements {@link GameGimmick}
* */
public final class ClickerGame
- extends ViewElement
+ extends ViewElement
implements GameGimmick {
/**
- * The score to increase when clicking the main button.
+ * How many points to get after clicking the button.
* */
private int clickValue;
/**
- * Local reference to current score.
- */
- private int score;
-
- /**
- * The current cost of upgrading the amount gained per click.
- * */
- private int upgradeCost;
-
- /**
- * The click button object.
+ * Button pressed to give points.
* */
private Button clickBtn;
- /**
- * The upgrade button object.
- * */
- private Button upgradeBtn;
-
/**
* Constructor.
* */
public ClickerGame() {
- super(new VBox(), MiniGamesActions.class);
+ super(new Pane(), MiniGamesActions.class);
}
@Override
protected void initLayout() {
- clickValue = 1;
- upgradeCost = 10;
+ clickValue = 6;
clickBtn = new Button("+" + clickValue);
- upgradeBtn = new Button("+" + clickValue + " per click\n-"
- + upgradeCost + " points");
- getRootPane().getChildren().addAll(clickBtn, upgradeBtn);
+ clickBtn.setFocusTraversable(false);
+
+ // Initial position.
+ clickBtn.setLayoutX(260);
+ clickBtn.setLayoutY(160);
+
+ getRootPane().getChildren().add(clickBtn);
+
+ // Responsive listener for width. Pushes the button to the edge of the
+ // screen if it is outside of it.
+ getRootPane().widthProperty().addListener((obs, oldVal, newVal) -> {
+ double maxAllowedX = newVal.doubleValue() - clickBtn.getWidth();
+ if (clickBtn.getLayoutX() > maxAllowedX) {
+ clickBtn.setLayoutX(Math.max(10, maxAllowedX));
+ }
+ });
+
+ // Same responsive listener for height.
+ getRootPane().heightProperty().addListener((obs, oldVal, newVal) -> {
+ double maxAllowedY = newVal.doubleValue() - clickBtn.getHeight();
+ if (clickBtn.getLayoutY() > maxAllowedY) {
+ clickBtn.setLayoutY(Math.max(10, maxAllowedY));
+ }
+ });
}
@Override
protected void initStyling() {
getRootPane().getStyleClass().add("clicker-minigame-root");
clickBtn.getStyleClass().add("clicker-minigame-clickBtn");
- upgradeBtn.getStyleClass().add("clicker-minigame-upgradeBtn");
}
@Override
@@ -76,23 +80,29 @@ public Node getCanvasNode() {
@Override
public void initialize(final IntConsumer scoreModifier) {
- score = 0;
clickBtn.setOnAction(e -> {
scoreModifier.accept(clickValue);
- score += clickValue;
+ teleportTarget();
});
+ }
- upgradeBtn.setOnAction(e -> {
- scoreModifier.accept(-upgradeCost);
- if (upgradeCost <= score) {
- score -= upgradeCost;
- clickValue += 1;
- upgradeCost *= 2;
- clickBtn.setText("+" + clickValue);
- upgradeBtn.setText("+1 per click\n-"
- + upgradeCost + " points");
- }
- });
+ /**
+ * Teleports the click target to a new random coordinate
+ * set inside the current view boundaries.
+ *
+ * Calculates maximum allowed x and y position
+ * based on the view/button width/height.
+ */
+ private void teleportTarget() {
+
+ double maxX = getRootPane().getWidth() - clickBtn.getWidth();
+ double maxY = getRootPane().getHeight() - clickBtn.getHeight();
+
+ double randomX = Math.random() * maxX;
+ double randomY = Math.random() * maxY;
+
+ clickBtn.setLayoutX(Math.max(10, randomX));
+ clickBtn.setLayoutY(Math.max(10, randomY));
}
@Override
diff --git a/src/main/resources/styles.css b/src/main/resources/styles.css
index 8b78901..2e10832 100644
--- a/src/main/resources/styles.css
+++ b/src/main/resources/styles.css
@@ -862,7 +862,7 @@
-fx-text-fill: #000000;
-fx-text-alignment: center;
-fx-pref-height: 250px;
- -fx-min-height: 200px;
+ -fx-min-height: 100px;
-fx-max-width: 350px;
}
@@ -991,12 +991,8 @@
}
.clicker-minigame-clickBtn {
- -fx-pref-width: 100;
- -fx-pref-height: 100;
-}
-
-.clicker-minigame-upgradeBtn {
- -fx-text-alignment: center;
+ -fx-pref-width: 80;
+ -fx-pref-height: 80;
}
/*--------------- TIMED INPUT GAME -------------*/
.time-inputs-minigame-root {