diff --git a/src/main/java/de/siphalor/was/content/quest/RandomQuestGenerator.java b/src/main/java/de/siphalor/was/content/quest/RandomQuestGenerator.java index bf9daac..6ed2764 100644 --- a/src/main/java/de/siphalor/was/content/quest/RandomQuestGenerator.java +++ b/src/main/java/de/siphalor/was/content/quest/RandomQuestGenerator.java @@ -40,7 +40,7 @@ public class RandomQuestGenerator implements QuestGenerator { Product product = WhatAStorage.getInstance().getProductManager().randomProduct(RANDOM); return new Quest( RANDOM.nextBoolean() ? Quest.Type.IN : Quest.Type.OUT, - RANDOM.nextInt(15) * 100 * product.getDepth(), + (RANDOM.nextInt(14) + 1) * 100 * product.getDepth(), product ); } diff --git a/src/main/java/de/siphalor/was/game/Options.java b/src/main/java/de/siphalor/was/game/Options.java index 8f3898d..23ef1a7 100644 --- a/src/main/java/de/siphalor/was/game/Options.java +++ b/src/main/java/de/siphalor/was/game/Options.java @@ -18,6 +18,10 @@ public class Options { * Allow resolving of two quests that target the same product. One asks to deposit it, the other to deliver it */ private boolean allowQuestResolving; + /** + * Whether the sound is enabled + */ + private boolean soundEnabled; /** * Gets whether quest resolving is enabled. @@ -44,13 +48,29 @@ public class Options { } /** - * Gets whether fulfilled quests should automatically be refilled. + * Sets whether fulfilled quests should automatically be refilled. * @param autoRefillQuests Whether fulfilled quests should automatically be refilled */ public void setAutoRefillQuests(boolean autoRefillQuests) { this.autoRefillQuests = autoRefillQuests; } + /** + * Gets whether the sound is enabled. + * @return Whether the sound is enabled + */ + public boolean getSoundEnabled() { + return soundEnabled; + } + + /** + * Sets whether the sound should be enabled. + * @param soundEnabled Whether the sound should be enabled + */ + public void setSoundEnabled(boolean soundEnabled) { + this.soundEnabled = soundEnabled; + } + /** * Gets a reference to the preferences object used for session independent storage. * @return The preferences object @@ -66,6 +86,7 @@ public class Options { Preferences preferences = getPreferences(); autoRefillQuests = preferences.getBoolean("auto-refill-quests", false); allowQuestResolving = preferences.getBoolean("allow-quest-resolving", true); + soundEnabled = preferences.getBoolean("sound-enabled", false); String lang = preferences.get("preferred-lang", Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry()); I18n.getInstance().setLang(lang, WhatAStorage.getInstance().getContentManager()); @@ -78,6 +99,7 @@ public class Options { Preferences preferences = getPreferences(); preferences.putBoolean("auto-refill-quests", autoRefillQuests); preferences.putBoolean("allow-quest-resolving", allowQuestResolving); + preferences.putBoolean("sound-enabled", soundEnabled); preferences.put("preferred-lang", I18n.getInstance().getLang().getCode()); } } diff --git a/src/main/java/de/siphalor/was/visual/JFXVisual.java b/src/main/java/de/siphalor/was/visual/JFXVisual.java index 193bbda..0cb8f57 100644 --- a/src/main/java/de/siphalor/was/visual/JFXVisual.java +++ b/src/main/java/de/siphalor/was/visual/JFXVisual.java @@ -84,6 +84,7 @@ public class JFXVisual extends Application implements Visual { primaryStage.setTitle(WhatAStorage.TITLE); primaryStage.setMinWidth(850); primaryStage.setMinHeight(500); + primaryStage.getIcons().add(JFXUtil.getIcon()); loadOptionsScene(); @@ -137,6 +138,8 @@ public class JFXVisual extends Application implements Visual { private void setupBalanceStage() { if (balanceStage != null) { + balanceStage.getIcons().add(JFXUtil.getIcon()); + balanceController = new BalanceController(); Scene scene = JFXUtil.loadScene("balance", balanceController, I18n.getInstance()); @@ -270,9 +273,11 @@ public class JFXVisual extends Application implements Visual { if (transaction.getChange() != 0) { gameController.budgetChangeLabel.getStyleClass().clear(); if (transaction.getChange() > 0) { + JFXUtil.playAudio("earn-money"); JFXUtil.setStyleClass(gameController.budgetChangeLabel, "green", true); gameController.budgetChangeLabel.setText(i18n.format("game.budget.change.income", transaction.getChange())); } else { + JFXUtil.playAudio("lose-money"); JFXUtil.setStyleClass(gameController.budgetChangeLabel, "red", true); gameController.budgetChangeLabel.setText(i18n.format("game.budget.change.loss", transaction.getChange())); } diff --git a/src/main/java/de/siphalor/was/visual/jfx/controller/GameController.java b/src/main/java/de/siphalor/was/visual/jfx/controller/GameController.java index fc200fb..5fe38ac 100644 --- a/src/main/java/de/siphalor/was/visual/jfx/controller/GameController.java +++ b/src/main/java/de/siphalor/was/visual/jfx/controller/GameController.java @@ -3,6 +3,7 @@ package de.siphalor.was.visual.jfx.controller; import de.siphalor.was.WhatAStorage; import de.siphalor.was.assets.AssetsManager; import de.siphalor.was.visual.jfx.util.DraggedProduct; +import de.siphalor.was.visual.jfx.util.JFXUtil; import javafx.animation.FadeTransition; import javafx.animation.Interpolator; import javafx.fxml.FXML; @@ -91,12 +92,15 @@ public class GameController { dragEvent.setDropCompleted(true); dragEvent.consume(); + + JFXUtil.playAudio("destroy"); return; } else if (origin instanceof DraggedProduct.Slot) { was.userDestroyProduct(((DraggedProduct.Slot) origin).x, ((DraggedProduct.Slot) origin).y); dragEvent.setDropCompleted(true); dragEvent.consume(); + JFXUtil.playAudio("destroy"); return; } } diff --git a/src/main/java/de/siphalor/was/visual/jfx/controller/OptionsController.java b/src/main/java/de/siphalor/was/visual/jfx/controller/OptionsController.java index a0f5e58..09b34d6 100644 --- a/src/main/java/de/siphalor/was/visual/jfx/controller/OptionsController.java +++ b/src/main/java/de/siphalor/was/visual/jfx/controller/OptionsController.java @@ -14,6 +14,7 @@ public class OptionsController { private Runnable exitRunnable; public ChoiceBox languageChoice; + public ToggleButton soundsEnabledToggle; public ToggleButton allowQuestResolvingToggle; public ToggleButton autoQuestRefillToggle; @@ -35,6 +36,7 @@ public class OptionsController { } } + soundsEnabledToggle.setSelected(options.getSoundEnabled()); allowQuestResolvingToggle.setSelected(options.getAllowQuestResolving()); autoQuestRefillToggle.setSelected(options.getAutoRefillQuests()); } @@ -45,6 +47,7 @@ public class OptionsController { String oldLang = I18n.getInstance().getLang().getCode(); I18n.getInstance().setLang(languageChoice.getValue().getCode(), WhatAStorage.getInstance().getContentManager()); + options.setSoundEnabled(soundsEnabledToggle.isSelected()); options.setAllowQuestResolving(allowQuestResolvingToggle.isSelected()); options.setAutoRefillQuests(autoQuestRefillToggle.isSelected()); diff --git a/src/main/java/de/siphalor/was/visual/jfx/util/JFXStorageSlot.java b/src/main/java/de/siphalor/was/visual/jfx/util/JFXStorageSlot.java index 6d19fd0..44aded5 100644 --- a/src/main/java/de/siphalor/was/visual/jfx/util/JFXStorageSlot.java +++ b/src/main/java/de/siphalor/was/visual/jfx/util/JFXStorageSlot.java @@ -139,11 +139,13 @@ public class JFXStorageSlot { if (origin instanceof DraggedProduct.Quest) { WhatAStorage.getInstance().userStoreProduct(((DraggedProduct.Quest) origin).index, x, y); dragEvent.setDropCompleted(true); + JFXUtil.playAudio("place"); return; } else if (origin instanceof DraggedProduct.Slot) { DraggedProduct.Slot slot = (DraggedProduct.Slot) origin; WhatAStorage.getInstance().userMoveProduct(slot.x, slot.y, x, y); dragEvent.setDropCompleted(true); + JFXUtil.playAudio("place"); return; } } diff --git a/src/main/java/de/siphalor/was/visual/jfx/util/JFXUtil.java b/src/main/java/de/siphalor/was/visual/jfx/util/JFXUtil.java index d49fa96..f6143d8 100644 --- a/src/main/java/de/siphalor/was/visual/jfx/util/JFXUtil.java +++ b/src/main/java/de/siphalor/was/visual/jfx/util/JFXUtil.java @@ -1,5 +1,6 @@ package de.siphalor.was.visual.jfx.util; +import de.siphalor.was.WhatAStorage; import de.siphalor.was.assets.AssetsManager; import de.siphalor.was.content.lang.I18n; import javafx.fxml.FXMLLoader; @@ -11,9 +12,12 @@ import javafx.scene.image.PixelReader; import javafx.scene.image.PixelWriter; import javafx.scene.image.WritableImage; +import javax.sound.sampled.*; import java.io.IOException; public class JFXUtil { + private static Image image; + public static Image scaleTo(Image image, int width) { double scale = image.getWidth() / (double) width; int height = (int) (image.getHeight() / scale); @@ -55,4 +59,26 @@ public class JFXUtil { scene.getStylesheets().add("assets/jfx/main.css"); return scene; } + + public static void playAudio(String sound) { + if (WhatAStorage.getInstance().getOptions().getSoundEnabled()) { + try { + AudioInputStream inputStream = AudioSystem.getAudioInputStream(AssetsManager.getStream("sound/" + sound + ".wav").orElseThrow()); + AudioFormat format = inputStream.getFormat(); + DataLine.Info info = new DataLine.Info(Clip.class, format); + Clip clip = (Clip) AudioSystem.getLine(info); + clip.open(inputStream); + clip.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public static Image getIcon() { + if (image == null) { + image = new Image(AssetsManager.getStream("textures/icon.png").orElseThrow()); + } + return image; + } } diff --git a/src/main/resources/assets/jfx/main.css b/src/main/resources/assets/jfx/main.css index ccd8f7d..6e3fe32 100644 --- a/src/main/resources/assets/jfx/main.css +++ b/src/main/resources/assets/jfx/main.css @@ -54,11 +54,11 @@ Label.red { Label.green { -fx-text-fill: #457229; } -.options-menu > Label { +.menu > Label { -fx-font-size: 16; } -.options-menu .heading { - -fx-padding: 10 0 0 0; +.menu > .heading { + -fx-padding: 8 0 0 0; -fx-font-size: 20; -fx-font-weight: bold; } diff --git a/src/main/resources/assets/jfx/options.fxml b/src/main/resources/assets/jfx/options.fxml index bcdb07d..f78e9e6 100644 --- a/src/main/resources/assets/jfx/options.fxml +++ b/src/main/resources/assets/jfx/options.fxml @@ -21,27 +21,38 @@ - + - - - - - + + + + + + + + + + diff --git a/src/main/resources/assets/sound/destroy.wav b/src/main/resources/assets/sound/destroy.wav new file mode 100644 index 0000000..7abd38b Binary files /dev/null and b/src/main/resources/assets/sound/destroy.wav differ diff --git a/src/main/resources/assets/sound/earn-money.wav b/src/main/resources/assets/sound/earn-money.wav new file mode 100644 index 0000000..b60175b Binary files /dev/null and b/src/main/resources/assets/sound/earn-money.wav differ diff --git a/src/main/resources/assets/sound/lose-money.wav b/src/main/resources/assets/sound/lose-money.wav new file mode 100644 index 0000000..3d9eb52 Binary files /dev/null and b/src/main/resources/assets/sound/lose-money.wav differ diff --git a/src/main/resources/assets/sound/place.wav b/src/main/resources/assets/sound/place.wav new file mode 100644 index 0000000..f4b2b13 Binary files /dev/null and b/src/main/resources/assets/sound/place.wav differ diff --git a/src/main/resources/assets/textures/icon.png b/src/main/resources/assets/textures/icon.png new file mode 100644 index 0000000..5c9b4ce Binary files /dev/null and b/src/main/resources/assets/textures/icon.png differ diff --git a/src/main/resources/content/lang/de_de.properties b/src/main/resources/content/lang/de_de.properties index 5ac52f2..a49d985 100644 --- a/src/main/resources/content/lang/de_de.properties +++ b/src/main/resources/content/lang/de_de.properties @@ -5,9 +5,14 @@ menu.options = Optionen menu.options.available = Verf\u00fcgbare Optionen: menu.options.back = Anwenden und zur\u00fcck menu.options.general = Allgemein +menu.options.general.sounds = Geräusche menu.options.gameplay = Spielmechanik menu.options.gameplay.quest-resolving = Erlauben Auftr\u00e4ge gegeneinander aufzul\u00f6sen menu.options.gameplay.auto-quest-refill = Automatisch neue Auftr\u00e4ge akzeptieren +menu.options.imprint = Impressum +menu.options.imprint.developer = Entwickelt von Johannes Freitag. +menu.options.imprint.assets = Die Grafiken wurden von mir selbst erstellt. Die Audio-Dateien stammen von freesound.org und sind lizensiert als CC0. +menu.options.imprint.javafx = Die Benutzeroberfläche wurde mit JavaFX und dem Gluon Scene Builder erstellt. general.invalid-input = Ung\u00fcltige Eingabe diff --git a/src/main/resources/content/lang/en_us.properties b/src/main/resources/content/lang/en_us.properties index 1f52a88..0f66f60 100644 --- a/src/main/resources/content/lang/en_us.properties +++ b/src/main/resources/content/lang/en_us.properties @@ -8,9 +8,14 @@ menu.options = Options menu.options.available = Available options: menu.options.back = Apply & Leave menu.options.general = General +menu.options.general.sounds = Sounds menu.options.gameplay = Gameplay menu.options.gameplay.quest-resolving = Allow quest resolving menu.options.gameplay.auto-quest-refill = Automatically refill quests +menu.options.imprint = Imprint +menu.options.imprint.developer = Developed by Johannes Freitag. +menu.options.imprint.assets = Images are made by myself. Sounds are licensed as CC0 and taken from freesound.org. +menu.options.imprint.javafx = User Interface created with JavaFX and the Gluon Scene Builder. general.invalid-input = Invalid input