A huge amount of work on GUI and Gameplay

This commit is contained in:
2020-07-07 22:51:15 +02:00
parent 2249ddbc68
commit dbd645e6d6
24 changed files with 936 additions and 219 deletions

View File

@@ -9,6 +9,8 @@ game.trash = M\u00fclltonne
game.trash.hover = Zerst\u00f6ren game.trash.hover = Zerst\u00f6ren
game.storage = Lager game.storage = Lager
game.balance.history = Buchungen game.balance.history = Buchungen
game.balance.history.no-data = Noch keine Buchungen
game.balance.history.index =
game.balance.history.change = Wert in \u20ac game.balance.history.change = Wert in \u20ac
game.balance.history.type = Beschreibung game.balance.history.type = Beschreibung
game.balance.history.type.abandon = Auftrag abgelehnt game.balance.history.type.abandon = Auftrag abgelehnt

View File

@@ -4,13 +4,18 @@ import de.siphalor.was.content.ContentManager;
import de.siphalor.was.content.lang.I18n; import de.siphalor.was.content.lang.I18n;
import de.siphalor.was.content.pack.FileContentPack; import de.siphalor.was.content.pack.FileContentPack;
import de.siphalor.was.content.pack.JarContentPack; import de.siphalor.was.content.pack.JarContentPack;
import de.siphalor.was.content.product.Product;
import de.siphalor.was.content.product.ProductManager; import de.siphalor.was.content.product.ProductManager;
import de.siphalor.was.content.quest.Quest; import de.siphalor.was.content.quest.Quest;
import de.siphalor.was.content.quest.QuestGenerator; import de.siphalor.was.content.quest.QuestGenerator;
import de.siphalor.was.content.quest.QuestManager; import de.siphalor.was.content.quest.QuestManager;
import de.siphalor.was.game.Balance; import de.siphalor.was.game.Balance;
import de.siphalor.was.game.Storage;
import de.siphalor.was.visual.JFXVisual; import de.siphalor.was.visual.JFXVisual;
import de.siphalor.was.visual.Visual; import de.siphalor.was.visual.Visual;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.nio.file.Path; import java.nio.file.Path;
@@ -19,6 +24,7 @@ import java.util.List;
public class WhatAStorage { public class WhatAStorage {
private static final int MAX_QUESTS = 3; private static final int MAX_QUESTS = 3;
private static final int GRID_SIZE = 3;
public static final String TITLE = "What a Storage"; public static final String TITLE = "What a Storage";
private static final WhatAStorage INSTANCE = new WhatAStorage(); private static final WhatAStorage INSTANCE = new WhatAStorage();
@@ -39,6 +45,7 @@ public class WhatAStorage {
private Balance balance; private Balance balance;
private QuestGenerator questGenerator; private QuestGenerator questGenerator;
private final List<Quest> quests = new ArrayList<>(MAX_QUESTS); private final List<Quest> quests = new ArrayList<>(MAX_QUESTS);
private Storage storage;
private WhatAStorage() { private WhatAStorage() {
contentManager = new ContentManager(); contentManager = new ContentManager();
@@ -94,6 +101,7 @@ public class WhatAStorage {
public void loadGame() { public void loadGame() {
questGenerator = questManager.get("normal"); questGenerator = questManager.get("normal");
quests.clear(); quests.clear();
storage = new Storage(GRID_SIZE, GRID_SIZE, GRID_SIZE);
balance = new Balance(); balance = new Balance();
} }
@@ -138,6 +146,75 @@ public class WhatAStorage {
Quest quest = quests.remove(index); Quest quest = quests.remove(index);
addTransaction(Balance.Transaction.ABANDON, -quest.getReward()); addTransaction(Balance.Transaction.ABANDON, -quest.getReward());
visual.onQuestAbandoned(index); visual.onQuestRemoved(index);
}
public boolean canStoreProduct(@Nullable Product product, int x, int y) {
return product != null && storage.get(x, y).fits(product) && product.testY(y);
}
public boolean canStoreProduct(int questIndex, int x, int y) {
return canStoreProduct(quests.get(questIndex).getProduct(), x, y);
}
public boolean canMoveProduct(int x1, int y1, int x2, int y2) {
return canStoreProduct(storage.get(x1, y1).front(), x2, y2);
}
public void storeProduct(int questIndex, int x, int y) {
Quest quest = quests.get(questIndex);
if (quest != null && quest.getType() == Quest.Type.IN) {
Product product = quest.getProduct();
int z = storage.get(x, y).add(product);
if (z >= 0 && product.testY(y)) {
quests.remove(questIndex);
addTransaction(Balance.Transaction.STORE, quest.getReward());
visual.onQuestRemoved(questIndex);
visual.onProductSet(x, y, z, quest.getProduct());
}
}
}
public boolean canSellProduct(int questIndex, int x, int y) {
Quest quest = quests.get(questIndex);
if (quest != null && quest.getType() == Quest.Type.OUT) {
return quest.getProduct().equals(storage.get(x, y).front());
}
return false;
}
public boolean sellProduct(int questIndex, int x, int y) {
if (canSellProduct(questIndex, x, y)) {
int z = storage.get(x, y).pop();
addTransaction(Balance.Transaction.SELL, quests.get(questIndex).getReward());
quests.remove(questIndex);
visual.onQuestRemoved(questIndex);
visual.onProductCleared(x, y, z);
return true;
}
return false;
}
public void moveProduct(int x1, int y1, int x2, int y2) {
Product product = storage.get(x1, y1).front();
if (product != null && product.testY(y2)) {
int z2 = storage.get(x2, y2).add(product);
if (z2 >= 0) {
int z1 = storage.get(x1, y1).pop();
addTransaction(Balance.Transaction.MOVE, -100);
visual.onProductCleared(x1, y1, z1);
visual.onProductSet(x2, y2, z2, product);
}
}
}
public void destroyProduct(int x, int y) {
int z = storage.get(x, y).pop();
if (z >= 0) {
addTransaction(Balance.Transaction.DESTROY, -500);
visual.onProductCleared(x, y, z);
}
} }
} }

View File

@@ -13,10 +13,6 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
public class AssetsManager { public class AssetsManager {
private static final Map<String, Image> imageCache = new HashMap<>();
@NotNull
public static final Image MISSINGNO = getImage("textures/missingno.png");
@NotNull @NotNull
public static Optional<InputStream> getStream(@NotNull String path) { public static Optional<InputStream> getStream(@NotNull String path) {
@@ -28,20 +24,4 @@ public class AssetsManager {
return Optional.ofNullable(Thread.currentThread().getContextClassLoader().getResource(path)); return Optional.ofNullable(Thread.currentThread().getContextClassLoader().getResource(path));
} }
@NotNull
public static Image getImage(@NotNull String path) {
Image image = imageCache.get(path);
if (image == null) {
image = getStream(path).map(inputStream -> {
try {
return (Image) ImageIO.read(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}).orElse(MISSINGNO);
imageCache.put(path, image);
}
return image;
}
} }

View File

@@ -1,8 +1,9 @@
package de.siphalor.was.content.product; package de.siphalor.was.content.product;
import de.siphalor.was.content.lang.I18n;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ResourceBundle;
public interface Product { public interface Product {
@NotNull @NotNull
String getPropertySpecifier(); String getPropertySpecifier();
@@ -14,15 +15,20 @@ public interface Product {
@NotNull @NotNull
ProductType<?> getType(); ProductType<?> getType();
public boolean equals(Product product);
@NotNull
default String getTranslationKey() { default String getTranslationKey() {
return "products." + getType().getId(); return "products." + getType().getId();
} }
default String getName(I18n i18n) { @NotNull
default String getName(@NotNull ResourceBundle i18n) {
return i18n.getString(getTranslationKey()); return i18n.getString(getTranslationKey());
} }
default String getDescription(I18n i18n) { @NotNull
default String getDescription(@NotNull ResourceBundle i18n) {
String[] props = getType().getProperties(); String[] props = getType().getProperties();
String[] values = getProperties(); String[] values = getProperties();
@@ -39,4 +45,14 @@ public interface Product {
return res.toString(); return res.toString();
} }
@NotNull
default String getTextureLocation() {
return "textures/products/" + getType().getId() + "/" + getPropertySpecifier();
}
@NotNull
static String getPlaceholderTextureLocation() {
return "textures/products/package.png";
}
} }

View File

@@ -55,6 +55,11 @@ public class DynamicProduct implements Product {
return type; return type;
} }
@Override
public boolean equals(Product product) {
return super.equals(product);
}
public void setYPredicate(@NotNull IntPredicate yPredicate) { public void setYPredicate(@NotNull IntPredicate yPredicate) {
this.yPredicate = yPredicate; this.yPredicate = yPredicate;
} }

View File

@@ -21,12 +21,12 @@ public class Storage {
return slots[x][y]; return slots[x][y];
} }
public boolean move(int x1, int y1, int x2, int y2) { public int move(int x1, int y1, int x2, int y2) {
StorageSlot slot1 = get(x1, y1); StorageSlot slot1 = get(x1, y1);
Product product = slot1.front(); Product product = slot1.front();
if (product != null) { if (product != null) {
return get(x2, y2).add(product); return get(x2, y2).add(product);
} }
return false; return -1;
} }
} }

View File

@@ -29,16 +29,15 @@ public class StorageSlot {
return null; return null;
} }
@Nullable public int pop() {
public Product pop() {
for (int i = products.length - 1; i >= 0; i--) { for (int i = products.length - 1; i >= 0; i--) {
Product product = products[i]; Product product = products[i];
if (product != null) { if (product != null) {
products[i] = null; products[i] = null;
return product; return i;
} }
} }
return null; return -1;
} }
public boolean fits(@NotNull Product product) { public boolean fits(@NotNull Product product) {
@@ -51,7 +50,7 @@ public class StorageSlot {
return product.getDepth() <= depth - blocked; return product.getDepth() <= depth - blocked;
} }
public boolean add(@NotNull Product product) { public int add(@NotNull Product product) {
int blocked = 0; int blocked = 0;
int i; int i;
for (i = 0; i < products.length; i++) { for (i = 0; i < products.length; i++) {
@@ -61,13 +60,13 @@ public class StorageSlot {
} }
blocked += p.getDepth(); blocked += p.getDepth();
if (blocked >= depth) { if (blocked >= depth) {
return false; return -1;
} }
} }
if (i < products.length && product.getDepth() <= depth - blocked) { if (i < products.length && product.getDepth() <= depth - blocked) {
products[i] = product; products[i] = product;
return true; return i;
} }
return false; return -1;
} }
} }

View File

@@ -0,0 +1,26 @@
package de.siphalor.was.util;
import org.jetbrains.annotations.NotNull;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* <b>Taken from here: https://stackoverflow.com/questions/924990/how-to-cache-inputstream-for-multiple-use#1303314</b>
*/
public class PersistentInputStream extends BufferedInputStream {
public PersistentInputStream(@NotNull InputStream in) {
super(in);
super.mark(Integer.MAX_VALUE);
}
@Override
public void close() throws IOException {
super.reset();
}
public void realClose() throws IOException {
super.close();
}
}

View File

@@ -1,17 +1,27 @@
package de.siphalor.was.visual; package de.siphalor.was.visual;
import de.siphalor.was.WhatAStorage; import de.siphalor.was.WhatAStorage;
import de.siphalor.was.assets.AssetsManager;
import de.siphalor.was.content.product.Product;
import de.siphalor.was.content.quest.Quest; import de.siphalor.was.content.quest.Quest;
import de.siphalor.was.game.Balance; import de.siphalor.was.game.Balance;
import de.siphalor.was.visual.canvas.layout.FixedAspectLayout; import de.siphalor.was.visual.canvas.layout.FixedAspectLayout;
import de.siphalor.was.visual.canvas.layout.FulfillingLayout; import de.siphalor.was.visual.canvas.layout.FulfillingLayout;
import org.jetbrains.annotations.NotNull;
import javax.imageio.ImageIO;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import java.awt.image.BufferStrategy; import java.awt.image.BufferStrategy;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class CanvasVisual implements Visual { public class CanvasVisual implements Visual {
@NotNull
public static final Image MISSINGNO = getImage("textures/missingno.png");
private static final double ASPECT_RATIO = 16.0 / 9.0; private static final double ASPECT_RATIO = 16.0 / 9.0;
private static final Map<String, Image> imageCache = new HashMap<>();
private WhatAStorage main; private WhatAStorage main;
private final Frame frame = new Frame(WhatAStorage.TITLE); private final Frame frame = new Frame(WhatAStorage.TITLE);
@@ -21,6 +31,23 @@ public class CanvasVisual implements Visual {
private boolean fullScreen = false; private boolean fullScreen = false;
@NotNull
public static Image getImage(@NotNull String path) {
Image image = imageCache.get(path);
if (image == null) {
image = AssetsManager.getStream(path).map(inputStream -> {
try {
return (Image) ImageIO.read(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}).orElse(MISSINGNO);
imageCache.put(path, image);
}
return image;
}
@Override @Override
public void setup(WhatAStorage whatAStorage) { public void setup(WhatAStorage whatAStorage) {
main = whatAStorage; main = whatAStorage;
@@ -138,7 +165,17 @@ public class CanvasVisual implements Visual {
} }
@Override @Override
public void onQuestAbandoned(int index) { public void onQuestRemoved(int index) {
}
@Override
public void onProductSet(int x, int y, int z, Product product) {
}
@Override
public void onProductCleared(int x, int y, int z) {
} }
} }

View File

@@ -2,14 +2,17 @@ package de.siphalor.was.visual;
import de.siphalor.was.WhatAStorage; import de.siphalor.was.WhatAStorage;
import de.siphalor.was.assets.AssetsManager; import de.siphalor.was.assets.AssetsManager;
import de.siphalor.was.content.ContentManager;
import de.siphalor.was.content.lang.I18n; import de.siphalor.was.content.lang.I18n;
import de.siphalor.was.content.product.Product; import de.siphalor.was.content.product.Product;
import de.siphalor.was.content.quest.Quest; import de.siphalor.was.content.quest.Quest;
import de.siphalor.was.content.resource.Resource;
import de.siphalor.was.game.Balance; import de.siphalor.was.game.Balance;
import de.siphalor.was.util.Pair; import de.siphalor.was.util.PersistentInputStream;
import de.siphalor.was.visual.jfx.BalanceEntry; import de.siphalor.was.visual.jfx.BalanceEntry;
import de.siphalor.was.visual.jfx.MainController; import de.siphalor.was.visual.jfx.MainController;
import de.siphalor.was.visual.jfx.QuestController; import de.siphalor.was.visual.jfx.QuestController;
import de.siphalor.was.visual.jfx.StorageSlotController;
import javafx.application.Application; import javafx.application.Application;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
@@ -20,10 +23,14 @@ import javafx.scene.chart.XYChart;
import javafx.scene.control.TableColumn; import javafx.scene.control.TableColumn;
import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.stage.Stage; import javafx.stage.Stage;
import org.jetbrains.annotations.NotNull;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
public class JFXVisual extends Application implements Visual { public class JFXVisual extends Application implements Visual {
private static Stage primaryStage; private static Stage primaryStage;
@@ -33,6 +40,20 @@ public class JFXVisual extends Application implements Visual {
private static MainController controller; private static MainController controller;
@NotNull
public static Image getProductImage(@NotNull Product product, @NotNull ContentManager contentManager) {
return loadImage(product.getTextureLocation(), contentManager).orElseGet(() -> loadImage(Product.getPlaceholderTextureLocation(), contentManager).orElseThrow());
}
@NotNull
public static Optional<Image> loadImage(@NotNull String location, @NotNull ContentManager contentManager) {
Optional<Resource> optResource = contentManager.getResource(location);
return optResource.map(resource -> {
InputStream inputStream = resource.getInputStream();
if (inputStream == null) return null;
return new Image(inputStream);
});
}
@Override @Override
public void setup(WhatAStorage whatAStorage) { public void setup(WhatAStorage whatAStorage) {
} }
@@ -52,7 +73,7 @@ public class JFXVisual extends Application implements Visual {
I18n i18n = I18n.getInstance(); I18n i18n = I18n.getInstance();
controller.budgetLabel.setText(i18n.format("game.budget", budget)); controller.budgetLabel.setText(i18n.format("game.budget", budget));
if (budget < 0) { if (budget < 0 && !controller.budgetLabel.getStyleClass().contains("red")) {
controller.budgetLabel.getStyleClass().add("red"); controller.budgetLabel.getStyleClass().add("red");
} else { } else {
controller.budgetLabel.getStyleClass().remove("red"); controller.budgetLabel.getStyleClass().remove("red");
@@ -79,7 +100,7 @@ public class JFXVisual extends Application implements Visual {
} }
@Override @Override
public void onQuestAbandoned(int index) { public void onQuestRemoved(int index) {
controller.questBox.getChildren().remove(index); controller.questBox.getChildren().remove(index);
controller.nextQuestButton.setDisable(false); controller.nextQuestButton.setDisable(false);
@@ -95,7 +116,7 @@ public class JFXVisual extends Application implements Visual {
controller = new MainController(WhatAStorage.getInstance()); controller = new MainController(WhatAStorage.getInstance());
loader.setController(controller); loader.setController(controller);
Pane pane = loader.load(AssetsManager.getStream("jfx/main.fxml").get()); Pane pane = loader.load(AssetsManager.getStream("jfx/test.fxml").get());
mainScene = new Scene(pane); mainScene = new Scene(pane);
mainScene.getStylesheets().add("assets/jfx/main.css"); mainScene.getStylesheets().add("assets/jfx/main.css");
@@ -114,6 +135,8 @@ public class JFXVisual extends Application implements Visual {
public void loadMainScene() { public void loadMainScene() {
primaryStage.setScene(mainScene); primaryStage.setScene(mainScene);
prepareStorageGrid();
AssetsManager.getStream("textures/bin_closed.png").ifPresent(inputStream -> { AssetsManager.getStream("textures/bin_closed.png").ifPresent(inputStream -> {
controller.trash.setImage(new Image(inputStream)); controller.trash.setImage(new Image(inputStream));
}); });
@@ -122,11 +145,11 @@ public class JFXVisual extends Application implements Visual {
onBalanceChanged(0, Balance.Transaction.NOOP, 0, 0, 0); onBalanceChanged(0, Balance.Transaction.NOOP, 0, 0, 0);
} }
public void addQuest(Quest quest) { private void addQuest(Quest quest) {
AssetsManager.getStream("jfx/quest_widget.fxml").ifPresentOrElse(is -> { AssetsManager.getStream("jfx/quest_widget.fxml").ifPresentOrElse(is -> {
try { try {
FXMLLoader loader = new FXMLLoader(); FXMLLoader loader = new FXMLLoader();
QuestController questController = new QuestController(WhatAStorage.getInstance()); QuestController questController = new QuestController(quest.getType());
loader.setController(questController); loader.setController(questController);
Parent parent = loader.load(is); Parent parent = loader.load(is);
@@ -135,12 +158,17 @@ public class JFXVisual extends Application implements Visual {
Product product = quest.getProduct(); Product product = quest.getProduct();
I18n i18n = I18n.getInstance(); I18n i18n = I18n.getInstance();
questController.title.setText(product.getName(i18n)); questController.title.setText(product.getName(i18n));
questController.description.setText(product.getDescription(i18n)); questController.description.setText(product.getDescription(i18n));
questController.reward.setText(i18n.format("game.quest.reward", quest.getReward())); questController.reward.setText(i18n.format("game.quest.reward", quest.getReward()));
questController.image.setImage(getProductImage(product, WhatAStorage.getInstance().getContentManager()));
if (quest.getType() == Quest.Type.OUT) {
parent.getStyleClass().add("quest-out");
}
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -148,4 +176,89 @@ public class JFXVisual extends Application implements Visual {
System.out.println("INTERNAL ERROR: Failed to load quest widget"); System.out.println("INTERNAL ERROR: Failed to load quest widget");
}); });
} }
private void prepareStorageGrid() {
GridPane storageGrid = controller.storageGrid;
storageGrid.getChildren().clear();
PersistentInputStream inputStream = new PersistentInputStream(AssetsManager.getStream("jfx/storage_slot.fxml").orElseThrow());
for (int y = 0; y < 3; y++) {
for (int x = 0; x < 3; x++) {
FXMLLoader loader = new FXMLLoader();
StorageSlotController storageSlotController = new StorageSlotController(x, y);
loader.setController(storageSlotController);
loader.setResources(I18n.getInstance());
try {
Parent parent = loader.load(inputStream);
inputStream.reset();
storageGrid.add(parent, x, y);
controller.storageSlotControllers[y][x] = storageSlotController;
// TODO
//storageSlotController.slot0.setImage(loadImage("textures/products/package.png", WhatAStorage.getInstance().getContentManager()).orElseThrow());
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
inputStream.realClose();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onProductSet(int x, int y, int z, Product product) {
ContentManager contentManager = WhatAStorage.getInstance().getContentManager();
I18n i18n = I18n.getInstance();
StorageSlotController slot = controller.storageSlotControllers[y][x];
switch (z) {
default:
case 0:
slot.slot0.setImage(getProductImage(product, contentManager));
slot.slot0Description.setText(product.getDescription(i18n));
slot.slot0Title.setText(product.getName(i18n));
break;
case 1:
slot.slot1.setImage(getProductImage(product, contentManager));
slot.slot1Description.setText(product.getDescription(i18n));
slot.slot1Title.setText(product.getName(i18n));
break;
case 2:
slot.slot2.setImage(getProductImage(product, contentManager));
slot.slot2Description.setText(product.getDescription(i18n));
slot.slot2Title.setText(product.getName(i18n));
break;
}
}
@Override
public void onProductCleared(int x, int y, int z) {
StorageSlotController slot = controller.storageSlotControllers[y][x];
String empty = I18n.getInstance().getString("game.storage.empty");
switch (z) {
default:
case 0:
slot.slot0.setImage(null);
slot.slot0Description.setText(null);
slot.slot0Title.setText(empty);
break;
case 1:
slot.slot1.setImage(null);
slot.slot1Description.setText(null);
slot.slot1Title.setText(empty);
break;
case 2:
slot.slot2.setImage(null);
slot.slot2Description.setText(null);
slot.slot2Title.setText(empty);
break;
}
}
} }

View File

@@ -1,6 +1,7 @@
package de.siphalor.was.visual; package de.siphalor.was.visual;
import de.siphalor.was.WhatAStorage; import de.siphalor.was.WhatAStorage;
import de.siphalor.was.content.product.Product;
import de.siphalor.was.content.quest.Quest; import de.siphalor.was.content.quest.Quest;
import de.siphalor.was.game.Balance; import de.siphalor.was.game.Balance;
@@ -12,5 +13,9 @@ public interface Visual {
void onBalanceChanged(int budget, Balance.Transaction transaction, int change, int totalIncome, int totalLoss); void onBalanceChanged(int budget, Balance.Transaction transaction, int change, int totalIncome, int totalLoss);
void onQuestAdded(Quest newQuest, boolean canCreateMore); void onQuestAdded(Quest newQuest, boolean canCreateMore);
void onQuestAbandoned(int index); void onQuestRemoved(int index);
void onProductSet(int x, int y, int z, Product product);
void onProductCleared(int x, int y, int z);
} }

View File

@@ -0,0 +1,27 @@
package de.siphalor.was.visual.jfx;
import javafx.scene.input.DataFormat;
import java.io.Serializable;
interface DraggedProduct extends Serializable {
DataFormat FORMAT = new DataFormat("application/java-was-jfx-product-move");
class Quest implements DraggedProduct {
public final int index;
public Quest(int index) {
this.index = index;
}
}
class Slot implements DraggedProduct {
public final int x;
public final int y;
public Slot(int x, int y) {
this.x = x;
this.y = y;
}
}
}

View File

@@ -0,0 +1,25 @@
package de.siphalor.was.visual.jfx;
import javafx.scene.image.Image;
import javafx.scene.image.PixelReader;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
public class JFXUtil {
public static Image scaleTo(Image image, int width) {
double scale = image.getWidth() / (double) width;
int height = (int) (image.getHeight() / scale);
WritableImage res = new WritableImage(width, height);
PixelReader reader = image.getPixelReader();
PixelWriter writer = res.getPixelWriter();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
writer.setColor(x, y, reader.getColor((int) (x * scale), (int) (y * scale)));
}
}
return res;
}
}

View File

@@ -1,7 +1,6 @@
package de.siphalor.was.visual.jfx; package de.siphalor.was.visual.jfx;
import de.siphalor.was.WhatAStorage; import de.siphalor.was.WhatAStorage;
import de.siphalor.was.util.Pair;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.chart.LineChart; import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis; import javafx.scene.chart.NumberAxis;
@@ -10,8 +9,12 @@ import javafx.scene.control.Button;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.TableView; import javafx.scene.control.TableView;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.input.DragEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
@SuppressWarnings("unused")
public class MainController { public class MainController {
private final WhatAStorage was; private final WhatAStorage was;
@@ -27,6 +30,9 @@ public class MainController {
public VBox questBox; public VBox questBox;
public Button nextQuestButton; public Button nextQuestButton;
public GridPane storageGrid;
public StorageSlotController[][] storageSlotControllers = new StorageSlotController[3][3];
public MainController(WhatAStorage was) { public MainController(WhatAStorage was) {
this.was = was; this.was = was;
} }
@@ -40,4 +46,36 @@ public class MainController {
private void nextQuest() { private void nextQuest() {
was.requestQuest(); was.requestQuest();
} }
@FXML
private void onTrashDragOver(DragEvent dragEvent) {
if (dragEvent.getDragboard().hasContent(DraggedProduct.FORMAT)) {
dragEvent.acceptTransferModes(TransferMode.MOVE);
}
dragEvent.consume();
}
@FXML
private void onTrashDragDropped(DragEvent dragEvent) {
if (dragEvent.getDragboard().hasContent(DraggedProduct.FORMAT)) {
DraggedProduct origin = (DraggedProduct) dragEvent.getDragboard().getContent(DraggedProduct.FORMAT);
if (origin instanceof DraggedProduct.Quest) {
DraggedProduct.Quest questOrigin = (DraggedProduct.Quest) origin;
was.abandonQuest(questOrigin.index);
dragEvent.setDropCompleted(true);
dragEvent.consume();
return;
} else if (origin instanceof DraggedProduct.Slot) {
was.destroyProduct(((DraggedProduct.Slot) origin).x, ((DraggedProduct.Slot) origin).y);
dragEvent.setDropCompleted(true);
dragEvent.consume();
return;
}
}
dragEvent.setDropCompleted(false);
}
} }

View File

@@ -1,13 +1,16 @@
package de.siphalor.was.visual.jfx; package de.siphalor.was.visual.jfx;
import de.siphalor.was.WhatAStorage; import de.siphalor.was.WhatAStorage;
import de.siphalor.was.content.quest.Quest;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.input.*;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
@SuppressWarnings("unused")
public class QuestController { public class QuestController {
private final WhatAStorage was; private final Quest.Type type;
@FXML @FXML
private GridPane questContainer; private GridPane questContainer;
@@ -18,13 +21,62 @@ public class QuestController {
public ImageView image; public ImageView image;
public QuestController(WhatAStorage was) { public QuestController(Quest.Type type) {
this.was = was; this.type = type;
} }
@FXML @FXML
private void abandon() { private void abandon() {
int index = questContainer.getParent().getChildrenUnmodifiable().indexOf(questContainer); WhatAStorage.getInstance().abandonQuest(getIndex());
was.abandonQuest(index); }
@FXML
private void onDragDetected(MouseEvent event) {
if (type == Quest.Type.IN) {
Dragboard dragboard = questContainer.startDragAndDrop(TransferMode.MOVE);
dragboard.setDragView(JFXUtil.scaleTo(image.getImage(), 100));
ClipboardContent content = new ClipboardContent();
content.put(DraggedProduct.FORMAT, new DraggedProduct.Quest(getIndex()));
dragboard.setContent(content);
}
event.consume();
}
@FXML
private void onDragOver(DragEvent dragEvent) {
Dragboard dragboard = dragEvent.getDragboard();
if (dragboard.hasContent(DraggedProduct.FORMAT)) {
DraggedProduct product = (DraggedProduct) dragboard.getContent(DraggedProduct.FORMAT);
if (product instanceof DraggedProduct.Slot) {
DraggedProduct.Slot slot = (DraggedProduct.Slot) product;
if (WhatAStorage.getInstance().canSellProduct(getIndex(), slot.x, slot.y)) {
dragEvent.acceptTransferModes(TransferMode.MOVE);
dragEvent.consume();
}
}
}
}
@FXML
private void onDragDropped(DragEvent dragEvent) {
Dragboard dragboard = dragEvent.getDragboard();
if (dragboard.hasContent(DraggedProduct.FORMAT)) {
DraggedProduct product = (DraggedProduct) dragboard.getContent(DraggedProduct.FORMAT);
if (product instanceof DraggedProduct.Slot) {
DraggedProduct.Slot slot = (DraggedProduct.Slot) product;
if (WhatAStorage.getInstance().sellProduct(getIndex(), slot.x, slot.y)) {
dragEvent.setDropCompleted(true);
dragEvent.consume();
return;
}
}
}
dragEvent.setDropCompleted(false);
}
private int getIndex() {
return questContainer.getParent().getChildrenUnmodifiable().indexOf(questContainer);
} }
} }

View File

@@ -0,0 +1,94 @@
package de.siphalor.was.visual.jfx;
import de.siphalor.was.WhatAStorage;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.*;
@SuppressWarnings("unused")
public class StorageSlotController {
private final int x;
private final int y;
@FXML
private Parent slot;
public ImageView slot0;
public Label slot0Title;
public Label slot0Description;
public ImageView slot1;
public Label slot1Title;
public Label slot1Description;
public ImageView slot2;
public Label slot2Title;
public Label slot2Description;
public StorageSlotController(int x, int y) {
this.x = x;
this.y = y;
}
@FXML
private void onDragDetected(MouseEvent event) {
int index;
Image image;
if (slot2.getImage() != null) {
image = JFXUtil.scaleTo(slot2.getImage(), 100);
} else if (slot1.getImage() != null) {
image = JFXUtil.scaleTo(slot1.getImage(), 100);
} else if (slot0.getImage() != null){
image = JFXUtil.scaleTo(slot0.getImage(), 100);
} else {
event.consume();
return;
}
Dragboard dragboard = slot.startDragAndDrop(TransferMode.MOVE);
dragboard.setDragView(image);
ClipboardContent content = new ClipboardContent();
content.put(DraggedProduct.FORMAT, new DraggedProduct.Slot(x, y));
dragboard.setContent(content);
event.consume();
}
@FXML
private void onDragOver(DragEvent dragEvent) {
if (dragEvent.getGestureSource() != slot && dragEvent.getDragboard().hasContent(DraggedProduct.FORMAT)) {
DraggedProduct origin = (DraggedProduct) dragEvent.getDragboard().getContent(DraggedProduct.FORMAT);
if (origin instanceof DraggedProduct.Quest) {
if (WhatAStorage.getInstance().canStoreProduct(((DraggedProduct.Quest) origin).index, x, y)) {
dragEvent.acceptTransferModes(TransferMode.MOVE);
}
} else if (origin instanceof DraggedProduct.Slot){
if (WhatAStorage.getInstance().canMoveProduct(((DraggedProduct.Slot) origin).x, ((DraggedProduct.Slot) origin).y, x, y)) {
dragEvent.acceptTransferModes(TransferMode.MOVE);
}
}
}
dragEvent.consume();
}
@FXML
private void onDragDropped(DragEvent dragEvent) {
if (dragEvent.getGestureSource() != slot && dragEvent.getDragboard().hasContent(DraggedProduct.FORMAT)) {
DraggedProduct origin = (DraggedProduct) dragEvent.getDragboard().getContent(DraggedProduct.FORMAT);
if (origin instanceof DraggedProduct.Quest) {
WhatAStorage.getInstance().storeProduct(((DraggedProduct.Quest) origin).index, x, y);
dragEvent.setDropCompleted(true);
return;
} else if (origin instanceof DraggedProduct.Slot) {
DraggedProduct.Slot slot = (DraggedProduct.Slot) origin;
WhatAStorage.getInstance().moveProduct(slot.x, slot.y, x, y);
dragEvent.setDropCompleted(true);
return;
}
}
dragEvent.setDropCompleted(false);
}
}

View File

@@ -0,0 +1,168 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.chart.LineChart?>
<?import javafx.scene.chart.NumberAxis?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.ToolBar?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<VBox maxHeight="1.7976931348623157E308" prefWidth="800.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<AnchorPane>
<children>
<ToolBar maxWidth="1.7976931348623157E308" prefHeight="40.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<items>
<Label fx:id="budgetLabel" text="%game.budget">
<font>
<Font size="19.0" />
</font>
<padding>
<Insets left="5.0" />
</padding>
</Label>
</items>
</ToolBar>
<Button alignment="CENTER" mnemonicParsing="false" onMouseClicked="#scheduleStop" styleClass="red" text="%game.quit" textFill="WHITE" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="7.0" />
</children>
</AnchorPane>
<SplitPane dividerPositions="0.3659147869674185" maxHeight="1.7976931348623157E308" VBox.vgrow="ALWAYS">
<items>
<GridPane minWidth="250.0" styleClass="side-pane">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints fillHeight="false" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints fillHeight="false" vgrow="NEVER" />
<RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES" />
<RowConstraints fillHeight="false" maxHeight="-Infinity" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<ScrollPane id="quest-pane" fitToWidth="true" hbarPolicy="NEVER" prefHeight="200.0" prefWidth="200.0" GridPane.rowIndex="2">
<content>
<VBox fx:id="questBox" />
</content>
</ScrollPane>
<VBox alignment="CENTER" onDragDropped="#onTrashDragDropped" onDragOver="#onTrashDragOver" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="TOP">
<GridPane.margin>
<Insets />
</GridPane.margin>
<children>
<ImageView fx:id="trash" fitHeight="80.0" pickOnBounds="true" preserveRatio="true" />
<Label text="%game.trash">
<font>
<Font name="System Bold" size="19.0" />
</font>
</Label>
</children>
<padding>
<Insets top="10.0" />
</padding>
</VBox>
<Label maxWidth="1.7976931348623157E308" minWidth="450.0" styleClass="quest-bar" text="%game.quests" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1">
<font>
<Font size="23.0" />
</font>
<padding>
<Insets left="10.0" top="-1.0" />
</padding>
</Label>
<Button fx:id="nextQuestButton" mnemonicParsing="false" onAction="#nextQuest" styleClass="green" text="%game.quests.next" textFill="WHITE" GridPane.halignment="RIGHT" GridPane.rowIndex="1" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets right="5.0" />
</GridPane.margin>
</Button>
</children>
</GridPane>
<TabPane minWidth="450.0" tabClosingPolicy="UNAVAILABLE" tabMaxHeight="Infinity" tabMaxWidth="Infinity">
<tabs>
<Tab text="%game.storage">
<content>
<GridPane id="storage-grid" fx:id="storageGrid" alignment="CENTER_LEFT" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="33.333" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</GridPane>
</content>
</Tab>
<Tab text="%game.balance.history">
<content>
<TableView fx:id="balanceHistoryTable" prefHeight="200.0" prefWidth="200.0">
<columns>
<TableColumn prefWidth="50.666626400416135" styleClass="align-right" text="%game.balance.history.index" />
<TableColumn maxWidth="500.0" prefWidth="100.0" styleClass="align-right" text="%game.balance.history.change" />
<TableColumn maxWidth="1.7976931348623157E308" prefWidth="300.0" text="%game.balance.history.type" />
</columns>
<placeholder>
<Label text="%game.balance.history.no-data" />
</placeholder>
</TableView>
</content>
</Tab>
<Tab text="%game.balance.chart">
<content>
<VBox>
<children>
<HBox fillHeight="false" maxWidth="1.7976931348623157E308" styleClass="tab-info-bar">
<children>
<Label fx:id="totalIncomeLabel" styleClass="green" text="Label">
<font>
<Font size="14.0" />
</font>
<HBox.margin>
<Insets right="20.0" />
</HBox.margin>
</Label>
<Label fx:id="totalLossLabel" styleClass="red" text="Label">
<font>
<Font size="14.0" />
</font>
</Label>
</children>
<padding>
<Insets bottom="5.0" left="20.0" right="20.0" top="5.0" />
</padding>
</HBox>
<LineChart fx:id="budgetChart" verticalGridLinesVisible="false">
<xAxis>
<NumberAxis minorTickVisible="false" side="BOTTOM" tickLabelsVisible="false" tickMarkVisible="false" />
</xAxis>
<yAxis>
<NumberAxis side="LEFT" />
</yAxis>
</LineChart>
</children>
</VBox>
</content>
</Tab>
</tabs>
</TabPane>
</items>
</SplitPane>
</children>
</VBox>

View File

@@ -27,16 +27,21 @@ Label.green {
} }
.side-pane { .side-pane {
-fx-border-width: 0 1;
-fx-border-color: #aaaaaa;
-fx-background-color: linear-gradient(to bottom, #dddddd, #aaaaaa); -fx-background-color: linear-gradient(to bottom, #dddddd, #aaaaaa);
} }
.quest-bar {
-fx-border-width: 0 0 1 0;
-fx-border-color: #aaaaaa;
}
.quest-container { .quest-container {
-fx-border-width: 1 0 0 0; -fx-border-width: 0 0 1 0;
-fx-border-color: #aaaaaa; -fx-border-color: #aaaaaa;
-fx-background-color: #eeeeee; -fx-background-color: #eeeeee;
} }
.quest-container.quest-out ImageView {
-fx-blend-mode: hard-light;
}
.quest-reward { .quest-reward {
-fx-text-fill: #457229; -fx-text-fill: #457229;
} }
@@ -49,7 +54,31 @@ Label.green {
.table-column { .table-column {
-fx-padding: 0 5; -fx-padding: 0 5;
} }
.split-pane:horizontal > .split-pane-divider {
-fx-padding: 0 1 0 1;
-fx-background-color: #aaaaaa;
}
.tab-pane:top > .tab-header-area {
-fx-min-height: 34;
-fx-pref-height: 34;
}
.tab-pane:top > .tab-header-area > .headers-region > .tab {
-fx-padding: 4;
-fx-end-margin: 5;
}
.tab-pane:top > .tab-header-area > .headers-region > .tab .focus-indicator {
-fx-focus-color: transparent;
-fx-faint-focus-color: transparent;
}
#main { #main {
-fx-background-color: #dddddd; -fx-background-color: #dddddd;
} }
#storage-grid > * {
-fx-border-color: #dddddd;
-fx-border-width: 1;
}
.storage-slot-item-title {
-fx-end-margin: 10;
}

View File

@@ -1,163 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.chart.LineChart?>
<?import javafx.scene.chart.NumberAxis?>
<?import javafx.scene.control.Accordion?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.ToolBar?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="450.0" prefWidth="850.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="250.0" percentWidth="30.0" prefWidth="250.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="10.0" percentWidth="70.0" prefWidth="380.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints fillHeight="false" vgrow="NEVER" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<GridPane styleClass="side-pane" GridPane.rowIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints fillHeight="false" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints fillHeight="false" vgrow="NEVER" />
<RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES" />
<RowConstraints fillHeight="false" maxHeight="-Infinity" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<ScrollPane id="quest-pane" fitToWidth="true" hbarPolicy="NEVER" prefHeight="200.0" prefWidth="200.0" GridPane.rowIndex="2">
<content>
<VBox fx:id="questBox" />
</content>
</ScrollPane>
<Label text="%game.trash" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="BOTTOM">
<font>
<Font name="System Bold" size="19.0" />
</font>
</Label>
<ImageView fx:id="trash" fitHeight="80.0" pickOnBounds="true" preserveRatio="true" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="TOP">
<GridPane.margin>
<Insets bottom="35.0" top="10.0" />
</GridPane.margin>
</ImageView>
<Label text="%game.quests" GridPane.rowIndex="1">
<font>
<Font size="23.0" />
</font>
<padding>
<Insets left="10.0" />
</padding>
</Label>
<Button fx:id="nextQuestButton" mnemonicParsing="false" onAction="#nextQuest" styleClass="green" text="%game.quests.next" textFill="WHITE" GridPane.halignment="RIGHT" GridPane.rowIndex="1" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets right="5.0" />
</GridPane.margin>
</Button>
<Accordion GridPane.rowIndex="1" />
</children>
</GridPane>
<TabPane tabClosingPolicy="UNAVAILABLE" GridPane.columnIndex="1" GridPane.rowIndex="1">
<GridPane.margin>
<Insets />
</GridPane.margin>
<tabs>
<Tab text="%game.storage">
<content>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
</GridPane>
</content>
</Tab>
<Tab text="%game.balance.history">
<content>
<TableView fx:id="balanceHistoryTable" prefHeight="200.0" prefWidth="200.0">
<columns>
<TableColumn prefWidth="50.666626400416135" styleClass="align-right" text="%game.balance.history.index" />
<TableColumn maxWidth="500.0" prefWidth="149.77776718139648" styleClass="align-right" text="%game.balance.history.change" />
<TableColumn maxWidth="1.7976931348623157E308" prefWidth="400.0" text="%game.balance.history.type" />
</columns>
</TableView>
</content>
</Tab>
<Tab text="%game.balance.chart">
<content>
<VBox>
<children>
<HBox fillHeight="false" maxWidth="1.7976931348623157E308" styleClass="tab-info-bar">
<children>
<Label fx:id="totalIncomeLabel" styleClass="green" text="Label">
<font>
<Font size="14.0" />
</font>
<HBox.margin>
<Insets right="20.0" />
</HBox.margin>
</Label>
<Label fx:id="totalLossLabel" styleClass="red" text="Label">
<font>
<Font size="14.0" />
</font>
</Label>
</children>
<padding>
<Insets bottom="5.0" left="20.0" right="20.0" top="5.0" />
</padding>
</HBox>
<LineChart fx:id="budgetChart" verticalGridLinesVisible="false">
<xAxis>
<NumberAxis minorTickVisible="false" side="BOTTOM" tickLabelsVisible="false" tickMarkVisible="false" />
</xAxis>
<yAxis>
<NumberAxis side="LEFT" />
</yAxis>
</LineChart>
</children>
</VBox>
</content>
</Tab>
</tabs>
</TabPane>
<ToolBar prefHeight="40.0" prefWidth="200.0" GridPane.columnSpan="2147483647">
<items>
<Label fx:id="budgetLabel" text="%game.budget">
<font>
<Font size="19.0" />
</font>
<padding>
<Insets left="5.0" />
</padding>
</Label>
</items>
</ToolBar>
<Button mnemonicParsing="false" onMouseClicked="#scheduleStop" styleClass="red" text="%game.quit" textFill="WHITE" GridPane.columnSpan="2147483647" GridPane.halignment="RIGHT" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets right="10.0" />
</GridPane.margin>
</Button>
</children>
</GridPane>

View File

@@ -10,7 +10,7 @@
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<GridPane fx:id="questContainer" maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="250.0" prefHeight="80.0" styleClass="quest-container" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1"> <GridPane fx:id="questContainer" maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="250.0" onDragDetected="#onDragDetected" onDragDropped="#onDragDropped" onDragOver="#onDragOver" prefHeight="80.0" styleClass="quest-container" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="80.0" /> <ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="80.0" />
<ColumnConstraints hgrow="SOMETIMES" /> <ColumnConstraints hgrow="SOMETIMES" />
@@ -20,9 +20,9 @@
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints> </rowConstraints>
<children> <children>
<ImageView fx:id="image" fitHeight="80.0" fitWidth="100.0" pickOnBounds="true" preserveRatio="true" GridPane.halignment="CENTER" GridPane.valignment="CENTER"> <ImageView fx:id="image" fitHeight="60.0" fitWidth="60.0" pickOnBounds="true" preserveRatio="true" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets /> <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</GridPane.margin> </GridPane.margin>
</ImageView> </ImageView>
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#abandon" prefHeight="0.0" prefWidth="0.0" styleClass="red" text="X" textFill="WHITE" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.valignment="CENTER"> <Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#abandon" prefHeight="0.0" prefWidth="0.0" styleClass="red" text="X" textFill="WHITE" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.valignment="CENTER">

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<VBox fx:id="slot" fillWidth="false" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" onDragDetected="#onDragDetected" onDragDropped="#onDragDropped" onDragOver="#onDragOver" GridPane.valignment="CENTER" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<GridPane alignment="CENTER_LEFT" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="30.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="30.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="30.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="30.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="0.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<ImageView fx:id="slot0" fitHeight="60.0" fitWidth="60.0" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="2" GridPane.columnSpan="2" GridPane.rowSpan="2" />
<ImageView fx:id="slot1" fitHeight="60.0" fitWidth="60.0" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="1" GridPane.rowSpan="2" />
<ImageView fx:id="slot2" fitHeight="60.0" fitWidth="60.0" pickOnBounds="true" preserveRatio="true" GridPane.columnSpan="2" GridPane.rowIndex="2" GridPane.rowSpan="2" />
<HBox alignment="CENTER_LEFT" prefHeight="100.0" GridPane.columnIndex="4" GridPane.rowIndex="1">
<children>
<Label fx:id="slot0Title" styleClass="storage-slot-item-title" text="%game.storage.empty">
<font>
<Font name="System Bold" size="12.0" />
</font>
</Label>
<Label fx:id="slot0Description" />
</children>
</HBox>
<HBox alignment="CENTER_LEFT" prefHeight="100.0" GridPane.columnIndex="3" GridPane.columnSpan="2147483647" GridPane.rowIndex="2">
<children>
<Label fx:id="slot1Title" styleClass="storage-slot-item-title" text="%game.storage.empty">
<font>
<Font name="System Bold" size="12.0" />
</font>
</Label>
<Label fx:id="slot1Description" />
</children>
</HBox>
<HBox alignment="CENTER_LEFT" prefHeight="100.0" GridPane.columnIndex="2" GridPane.columnSpan="2147483647" GridPane.rowIndex="3">
<children>
<Label fx:id="slot2Title" styleClass="storage-slot-item-title" text="%game.storage.empty">
<font>
<Font name="System Bold" size="12.0" />
</font>
</Label>
<Label fx:id="slot2Description" />
</children>
</HBox>
</children>
</GridPane>
</children>
</VBox>

View File

@@ -8,7 +8,9 @@ game.quest.reward = %d$
game.trash = Recycle Bin game.trash = Recycle Bin
game.trash.hover = Destroy\n%d$ game.trash.hover = Destroy\n%d$
game.storage = Storage game.storage = Storage
game.storage.empty = Empty
game.balance.history = Transactions game.balance.history = Transactions
game.balance.history.no-data = No transactions yet
game.balance.history.index = game.balance.history.index =
game.balance.history.change = Change in $ game.balance.history.change = Change in $
game.balance.history.type = Description game.balance.history.type = Description

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="package.svg"
id="svg8"
version="1.1"
viewBox="0 0 132.29166 132.29167"
height="500"
width="500">
<defs
id="defs2" />
<sodipodi:namedview
inkscape:guide-bbox="true"
inkscape:lockguides="false"
showguides="true"
inkscape:window-maximized="1"
inkscape:window-y="-7"
inkscape:window-x="-7"
inkscape:window-height="1010"
inkscape:window-width="1920"
units="px"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="mm"
inkscape:cy="217.09446"
inkscape:cx="307.26355"
inkscape:zoom="0.7"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base">
<sodipodi:guide
inkscape:color="rgb(0,0,255)"
inkscape:locked="false"
inkscape:label=""
id="guide1410"
orientation="0,1"
position="105.83333,105.83333" />
<sodipodi:guide
inkscape:color="rgb(0,0,255)"
inkscape:locked="false"
inkscape:label=""
id="guide1412"
orientation="-1,0"
position="105.83333,105.83333" />
<sodipodi:guide
inkscape:color="rgb(0,0,255)"
inkscape:locked="false"
inkscape:label=""
id="guide1414"
orientation="-1,0"
position="26.458333,105.83333" />
<sodipodi:guide
inkscape:color="rgb(0,0,255)"
inkscape:locked="false"
inkscape:label=""
id="guide1416"
orientation="0,1"
position="105.83333,26.458333" />
<sodipodi:guide
id="guide1418"
orientation="0,500"
position="0,132.29166" />
<sodipodi:guide
id="guide1420"
orientation="500,0"
position="132.29166,132.29166" />
<sodipodi:guide
id="guide1422"
orientation="0,-500"
position="132.29166,0" />
<sodipodi:guide
id="guide1424"
orientation="-500,0"
position="0,0" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<rect
ry="1.9382317e-06"
y="26.458336"
x="0"
height="105.83333"
width="105.83333"
id="rect1426"
style="fill:#d6b285;stroke-width:0.264583;fill-opacity:1;stroke:#000000;stroke-opacity:1" />
<path
id="path1428"
d="M 0,26.458336 26.458333,4.9999997e-6 H 132.29166 L 105.83333,26.458336 H 0"
style="fill:#e4ccaf;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" />
<path
id="path1430"
d="m 105.83333,132.29166 26.45833,-26.45833 V 4.9999997e-6 L 105.83333,26.458336 Z"
style="fill:#ba915e;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB