Skip to content

Commit

Permalink
Merge branch 'Buyable-perks' into 'main'
Browse files Browse the repository at this point in the history
Buyable perks

See merge request Maurycyt/idlearn!57
  • Loading branch information
Maurycyt committed May 25, 2022
2 parents a1bfae6 + bf19b51 commit 537c717
Show file tree
Hide file tree
Showing 16 changed files with 320 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import mimuw.idlearn.scenes.preloading.LoadTask;
import mimuw.idlearn.scoring.PointsGiver;
import mimuw.idlearn.userdata.DataManager;
import mimuw.idlearn.userdata.PerkManager;

import java.io.IOException;
import java.util.ArrayList;
Expand Down Expand Up @@ -57,6 +58,9 @@ public void start(Stage stage) throws IOException {
// Start data manager
DataManager.init();

// Start perk manager
PerkManager.init();

// Start points giver
PointsGiver.loadSpeeds();

Expand Down
12 changes: 6 additions & 6 deletions scenes/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
<artifactId>scoring</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>mimuw</groupId>
<artifactId>userdata</artifactId>
<version>${revision}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
Expand All @@ -52,11 +58,5 @@
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mimuw</groupId>
<artifactId>userdata</artifactId>
<version>2.0.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
23 changes: 23 additions & 0 deletions scenes/src/main/java/mimuw/idlearn/scenes/ResourceHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,29 @@ public static Alert createAlert(Alert.AlertType alertType, String s, ButtonType.
return alert;
}

/**
* Wrapper for creating a clickable green button with styling.
* @param s: the button's text
* @param maxWidth: the max width of the button
* @return the button
*/
public static Button createGreenButton(String s, double maxWidth) {
Button btn = new Button(s);
btn.setMaxWidth(maxWidth);
btn.getStylesheets().add(ResourceHandler.Style.toExternalForm());
btn.getStyleClass().add("greenButton");
return btn;
}

/**
* Changes the style of the button for a completed/unlocked asset,
* so that it's different from the others of its type.
* @param taskBtn: button of an asset
*/
public static void setStyleForUnlockedAsset(Button taskBtn) {
taskBtn.setStyle("-fx-background-color: #029c5b;");
}

//TODO: remove this
private static final String loremIpsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
public static String repeatLorem(int n) { return loremIpsum.repeat(Math.max(0, n)); }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,80 @@
package mimuw.idlearn.scenes.controllers;

import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import mimuw.idlearn.scenes.ResourceHandler;
import mimuw.idlearn.userdata.NotEnoughPointsException;
import mimuw.idlearn.userdata.PerkManager;
import mimuw.idlearn.userdata.ReachedMaxLevelException;

import java.io.IOException;
import java.net.URL;
import java.util.AbstractMap;
import java.util.ResourceBundle;
import java.util.Set;

public class PerkStoreController extends GenericController {
@FXML
private VBox perksVBox;
@FXML
private BorderPane mainBorderPane;

@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
Button pointsBtn = ResourceHandler.createUserPointsButton();
mainBorderPane.setTop(pointsBtn);

Set<String> perks = PerkManager.getPerkNames();
double btnWidth = perksVBox.getMaxWidth();
for (String perkName : perks) {
Button perkBtn = ResourceHandler.createGreenButton(
perkName + " (" + PerkManager.getLevel(perkName) + "/" + PerkManager.getMaxLevel(perkName) + ")",
btnWidth
);
perksVBox.getChildren().add(perkBtn);
perkBtn.setOnAction((event) -> buyPerk(perkName));

// make the style and text change dynamically
PerkManager.connectToPerkUnlocking(event -> {
var perkUpgrade = (AbstractMap.SimpleEntry<String, Integer>) event.value();
if (perkName.equals(perkUpgrade.getKey())) {
ResourceHandler.setStyleForUnlockedAsset(perkBtn);
String newText = perkName + " (" + perkUpgrade.getValue() + "/" + PerkManager.getMaxLevel(perkName) + ")";
perkBtn.setText(newText);
}
});
if (PerkManager.getLevel(perkName) > 0)
ResourceHandler.setStyleForUnlockedAsset(perkBtn);
}
}

private void buyPerk(String title) {
Alert alert;
try {
PerkManager.upgradePerk(title);

alert = ResourceHandler.createAlert(Alert.AlertType.INFORMATION,
"Acquired perk \"" + title + "\"", ButtonType.OK
);
alert.setHeaderText("Success!");
} catch (ReachedMaxLevelException e) {
alert = ResourceHandler.createAlert(Alert.AlertType.WARNING,
"This perk can't be upgraded anymore!", ButtonType.OK
);
alert.setHeaderText("Max perk level achieved!");
} catch (NotEnoughPointsException e) {
alert = ResourceHandler.createAlert(Alert.AlertType.WARNING,
"Gather more points and try again", ButtonType.OK
);
alert.setHeaderText("Not enough points!");
} catch (IOException e) {
e.printStackTrace();
return;
}
alert.show();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,21 @@ private void submitSolution(CodeBox codeBox) {
String tmp = e.toString();
alert = ResourceHandler.createAlert(Alert.AlertType.ERROR, tmp.substring(2 + tmp.indexOf(":")), ButtonType.OK);
alert.setHeaderText("Out of array bounds!");
} catch (SimulationException | IOException e) {
} catch (Exception e) {
String text = "A";
if (e instanceof IOException) {
text += "n internal I/O";
// the two cases below should never occur
} else if (e instanceof SimulationException) {
assert false;
text += " compilation";
} else {
assert false;
text += "n unexpected";
}
text += " error occurred!";
alert = ResourceHandler.createAlert(Alert.AlertType.ERROR, "Contact your local IdLearn developer for help", ButtonType.OK);
alert.setHeaderText("An " + (e instanceof IOException? "internal I/O" : "unexpected") + " error occurred!");
alert.setHeaderText(text);
e.printStackTrace();
} finally {
assert alert != null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,40 +21,28 @@ public class TaskSelectionController extends GenericController {
@FXML
private BorderPane mainBorderPane;

/**
* Makes the button of a completed task darker and gives it a popup on click.
* This assumes the task's text has been set.
* @param taskBtn: button of a task
*/
private void setStyleOfButtonForCompletedTask(Button taskBtn) {
taskBtn.setStyle("-fx-background-color: #029c5b;");
}

/** Loads all the user's available tasks as clickable buttons **/
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
Set<String> completedTasks = PointsGiver.getCompletedTasks();
Button pointsBtn = ResourceHandler.createUserPointsButton();
mainBorderPane.setTop(pointsBtn);
Set<String> completedTasks = PointsGiver.getCompletedTasks();

List<String> tasks = new java.util.ArrayList<>(DataManager.getUnlockedTasks());
Collections.sort(tasks);

double btnWidth = tasksVBox.getMaxWidth();
for (final String taskTitle : tasks) {
Button taskBtn = new Button(taskTitle);
taskBtn.setMaxWidth(btnWidth);
taskBtn.getStylesheets().add(ResourceHandler.Style.toExternalForm());
taskBtn.getStyleClass().add("greenButton");
for (String taskTitle : tasks) {
Button taskBtn = ResourceHandler.createGreenButton(taskTitle, btnWidth);
tasksVBox.getChildren().add(taskBtn);

// make the style change dynamically
PointsGiver.connectToTaskCompletion(event -> {
if (event.value() == taskTitle)
setStyleOfButtonForCompletedTask(taskBtn);
ResourceHandler.setStyleForUnlockedAsset(taskBtn);
});
if (completedTasks.contains(taskTitle))
setStyleOfButtonForCompletedTask(taskBtn);
ResourceHandler.setStyleForUnlockedAsset(taskBtn);

taskBtn.setOnAction((event) -> {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ private void buyTask(Difficulty difficulty) throws IOException {
);
} else {
try {
DataManager.payPoints(0); //todo: replace with actual cost
DataManager.payPoints(100); //todo: replace with actual cost
DataManager.unlockTask(task.get().getTitle());

alert = ResourceHandler.createAlert(Alert.AlertType.INFORMATION,
"Acquired task \"" + task.get().getTitle() + "\"", ButtonType.OK
);
alert.setHeaderText("Success!");
DataManager.unlockTask(task.get().getTitle());
} catch (NotEnoughPointsException e) {
alert = ResourceHandler.createAlert(Alert.AlertType.WARNING,
"Gather more points and try again", ButtonType.OK
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>

<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ScrollBar?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>

<BorderPane fx:id="mainBorderPane" maxHeight="-Infinity" maxWidth="-Infinity" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" fx:controller="mimuw.idlearn.scenes.controllers.PerkStoreController">
<BorderPane fx:id="mainBorderPane" maxHeight="-Infinity" maxWidth="-Infinity" prefHeight="800.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="mimuw.idlearn.scenes.controllers.PerkStoreController">
<bottom>
<Button styleClass="greenButton" mnemonicParsing="false" onAction="#goBack" prefHeight="40.0" prefWidth="203.0" text="Back" BorderPane.alignment="CENTER">
<Button mnemonicParsing="false" onAction="#goBack" prefHeight="40.0" prefWidth="203.0" styleClass="greenButton" text="Back" BorderPane.alignment="CENTER">
<font>
<Font name="System Bold" size="13.0" />
</font>
Expand All @@ -28,10 +32,19 @@
</Button>
</top>
<center>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" prefHeight="600.0" prefWidth="800.0" styleClass="menuVBox" BorderPane.alignment="CENTER" />
<ScrollPane fitToHeight="true" fitToWidth="true" maxHeight="-Infinity" maxWidth="-Infinity" prefHeight="600.0" prefWidth="800.0" BorderPane.alignment="CENTER">
<content>
<HBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="600.0" prefWidth="800.0" styleClass="pane">
<children>
<ScrollBar disable="true" orientation="VERTICAL" visible="false" />
<VBox fx:id="perksVBox" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="600.0" prefWidth="800.0" styleClass="menuVBox" HBox.hgrow="ALWAYS" />
</children>
</HBox>
</content>
</ScrollPane>
</center>
<stylesheets>
<URL value="@../style.css" />
<URL value="@../common_style.css" />
</stylesheets>
<stylesheets>
<URL value="@../style.css" />
<URL value="@../common_style.css" />
</stylesheets>
</BorderPane>
38 changes: 35 additions & 3 deletions scoring/src/main/java/mimuw/idlearn/scoring/PointsGiver.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import mimuw.idlearn.core.Emitter;
import mimuw.idlearn.core.Listener;
import mimuw.idlearn.userdata.DataManager;
import mimuw.idlearn.userdata.PerkManager;

import java.io.IOException;
import javafx.application.Platform;
Expand All @@ -11,6 +12,8 @@

public class PointsGiver {
private static final Timer givingTimer = new Timer();

private static double speedMultiplier = 1.0;
private static final Map<String, PointsTimerTask> givingTasks = new HashMap<>();
private static final Map<String, Long> timeStamps = new HashMap<>();
private static final Semaphore mutex = new Semaphore(1);
Expand Down Expand Up @@ -65,7 +68,7 @@ public static void setSolutionSpeed(String problem, long timeInMillis, long time
task.cancel();
}

task = new PointsTimerTask(timeInMillis, pointsPerGiving);
task = new PointsTimerTask((long)(timeInMillis / speedMultiplier), pointsPerGiving);
task.start();
givingTasks.put(problem, task);
timeStamps.put(problem, timeStamp);
Expand Down Expand Up @@ -96,7 +99,6 @@ public static void resetSolutions() {

for (Map.Entry<String, PointsTimerTask> entry : givingTasks.entrySet()) {
entry.getValue().cancel();
//todo: couldn't this just be `resetSolution`?
}
timeStamps.clear();
givingTasks.clear();
Expand All @@ -109,7 +111,15 @@ public static void exit() {
}

public static void loadSpeeds() {
HashMap<String, DataManager.PointsGiving> speeds = DataManager.getPointsGiving();
// Make it so that PerkManager informs PointsGiver of new speed.
PerkManager.connectToOnUpgradeEmitter("Speed", event -> {
if (event.value() instanceof Double) {
setSpeedMultiplier((Double)event.value());
}
});

// Prepare the usual stuff.
Map<String, DataManager.PointsGiving> speeds = DataManager.getPointsGiving();
Date date = new Date();

for (Map.Entry<String, DataManager.PointsGiving> entry : speeds.entrySet()) {
Expand All @@ -118,5 +128,27 @@ public static void loadSpeeds() {
givingTasks.put(entry.getKey(), task);
timeStamps.put(entry.getKey(), date.getTime());
}

// Force PerkManager to inform of speed, which was read from user data.
PerkManager.refreshPerk("Speed");
}

public static void reloadSpeeds() {
Map<String, DataManager.PointsGiving> speeds = DataManager.getPointsGiving();

for (Map.Entry<String, DataManager.PointsGiving> entry : speeds.entrySet()) {
try {
setSolutionSpeed(entry.getKey(), entry.getValue().timeInterval, entry.getValue().points);
} catch (IOException e) {
e.printStackTrace();
// TODO: clean this up.
}
}
}

public static void setSpeedMultiplier(double newSpeedMultiplier) {
speedMultiplier = newSpeedMultiplier;
resetSolutions();
reloadSpeeds();
}
}
Loading

0 comments on commit 537c717

Please sign in to comment.