diff --git a/src/main/java/com/alttd/fishingevent/config/Messages.java b/src/main/java/com/alttd/fishingevent/config/Messages.java
index d4b5679..1b70b8c 100644
--- a/src/main/java/com/alttd/fishingevent/config/Messages.java
+++ b/src/main/java/com/alttd/fishingevent/config/Messages.java
@@ -50,6 +50,7 @@ public class Messages extends AbstractConfig {
public static String NO_FISHING_ROD = "You need to have a fishing rod to use this NPC";
public static String UPGRADE_GUI_NAME = "Upgrade GUI";
public static String PRIZES_GUI_NAME = "Prizes GUI";
+ public static String SELL_GUI_NAME = "Sell GUI";;
public static String NOT_INITIALIZED = "There was an error initializing this GUI, please contact staff";
@SuppressWarnings("unused")
@@ -57,6 +58,7 @@ public class Messages extends AbstractConfig {
NO_FISHING_ROD = config.getString(prefix, "no-fishing-rod", NO_FISHING_ROD);
UPGRADE_GUI_NAME = config.getString(prefix, "upgrade-gui-name", UPGRADE_GUI_NAME);
PRIZES_GUI_NAME = config.getString(prefix, "prizes-gui-name", PRIZES_GUI_NAME);
+ SELL_GUI_NAME = config.getString(prefix, "sell-gui-name", SELL_GUI_NAME);
NOT_INITIALIZED = config.getString(prefix, "not-initialized", NOT_INITIALIZED);
}
}
@@ -98,10 +100,12 @@ public class Messages extends AbstractConfig {
public static class OTHER_ERRORS {
private static final String prefix = "other-errors.";
public static String UNABLE_TO_CREATE_FISH = "Unable to create fish, please contact a staff member";
+ public static String UNABLE_TO_SELL_ITEMS = "Unable to sell items, please contact a staff member";
@SuppressWarnings("unused")
private static void load() {
UNABLE_TO_CREATE_FISH = config.getString(prefix, "unable-to-create-fish", UNABLE_TO_CREATE_FISH);
+ UNABLE_TO_SELL_ITEMS = config.getString(prefix, "unable-to-sell-items", UNABLE_TO_SELL_ITEMS);
}
}
}
diff --git a/src/main/java/com/alttd/fishingevent/gui/GUI.java b/src/main/java/com/alttd/fishingevent/gui/GUI.java
index c5b7ca3..9c5c0c5 100644
--- a/src/main/java/com/alttd/fishingevent/gui/GUI.java
+++ b/src/main/java/com/alttd/fishingevent/gui/GUI.java
@@ -11,7 +11,7 @@ import java.util.HashMap;
import java.util.UUID;
public abstract class GUI {
- HashMap GUIByUUID = new HashMap<>();
+ static HashMap GUIByUUID = new HashMap<>();
protected final Inventory inventory;
protected final HashMap guiActions;
@@ -44,4 +44,8 @@ public abstract class GUI {
GUIByUUID.put(player.getUniqueId(), this);
return true;
}
+
+ protected abstract void closed();
+
+ protected abstract boolean canMoveItems();
}
diff --git a/src/main/java/com/alttd/fishingevent/gui/GUIListener.java b/src/main/java/com/alttd/fishingevent/gui/GUIListener.java
new file mode 100644
index 0000000..8f199e4
--- /dev/null
+++ b/src/main/java/com/alttd/fishingevent/gui/GUIListener.java
@@ -0,0 +1,65 @@
+package com.alttd.fishingevent.gui;
+
+import org.bukkit.Material;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.inventory.InventoryCloseEvent;
+import org.bukkit.event.inventory.InventoryType;
+import org.bukkit.event.inventory.TradeSelectEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.MerchantInventory;
+
+public class GUIListener implements Listener {
+
+ /**
+ * Handles clicking inside a gui
+ * @param event gui click event
+ */
+ @EventHandler
+ public void onClick(InventoryClickEvent event){
+ if (!(event.getWhoClicked() instanceof Player player)) return;
+
+ GUI gui = GUI.GUIByUUID.get(player.getUniqueId());
+ if (gui == null)
+ return;
+ if (gui.getInventory() != null) {
+ if (!gui.getInventory().equals(event.getInventory()))
+ return;
+ }
+ else
+ return;
+
+ if (gui.canMoveItems())
+ return;
+
+ event.setCancelled(true);
+
+ Inventory clickedInventory = event.getClickedInventory();
+ if (clickedInventory == null || clickedInventory.getType().equals(InventoryType.PLAYER)) return;
+
+ GUIAction action = gui.getGuiAction(event.getSlot());
+
+ if (action != null) action.click(player);
+ }
+
+ @EventHandler
+ public void onClose(InventoryCloseEvent event) {
+ HumanEntity player = event.getPlayer();
+ GUI gui = GUI.GUIByUUID.get(player.getUniqueId());
+
+ gui.closed();
+
+ GUI.GUIByUUID.remove(event.getPlayer().getUniqueId());
+ }
+
+ @EventHandler
+ public void onQuit(PlayerQuitEvent event){
+ GUI.GUIByUUID.remove(event.getPlayer().getUniqueId());
+ }
+
+}
diff --git a/src/main/java/com/alttd/fishingevent/gui/windows/PrizesWindow.java b/src/main/java/com/alttd/fishingevent/gui/windows/PrizesWindow.java
index a0c8fe5..877031c 100644
--- a/src/main/java/com/alttd/fishingevent/gui/windows/PrizesWindow.java
+++ b/src/main/java/com/alttd/fishingevent/gui/windows/PrizesWindow.java
@@ -33,4 +33,14 @@ public class PrizesWindow extends GUI {
public boolean canOpen() {
return true;
}
+
+ @Override
+ protected void closed() {
+
+ }
+
+ @Override
+ protected boolean canMoveItems() {
+ return false;
+ }
}
diff --git a/src/main/java/com/alttd/fishingevent/gui/windows/SellWindow.java b/src/main/java/com/alttd/fishingevent/gui/windows/SellWindow.java
new file mode 100644
index 0000000..a1f6bab
--- /dev/null
+++ b/src/main/java/com/alttd/fishingevent/gui/windows/SellWindow.java
@@ -0,0 +1,96 @@
+package com.alttd.fishingevent.gui.windows;
+
+import com.alttd.fishingevent.FishingEvent;
+import com.alttd.fishingevent.config.Messages;
+import com.alttd.fishingevent.gui.GUI;
+import com.alttd.fishingevent.points.PointsManagement;
+import com.alttd.fishingevent.util.Logger;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import org.bukkit.NamespacedKey;
+import org.bukkit.entity.Player;
+import org.bukkit.event.inventory.InventoryType;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.persistence.PersistentDataType;
+
+import java.util.*;
+
+public class SellWindow extends GUI {
+
+ private final Logger logger;
+ private final FishingEvent fishingEvent;
+ private final Player player;
+
+ public SellWindow(FishingEvent fishingEvent, Player player, Logger logger) {
+ super(InventoryType.CHEST, MiniMessage.miniMessage().deserialize(Messages.GUI.SELL_GUI_NAME));
+ this.fishingEvent = fishingEvent;
+ this.logger = logger;
+ this.player = player;
+ }
+
+
+ @Override
+ public boolean canOpen() {
+ return true;
+ }
+
+ @Override
+ protected void closed() {
+ Optional optionalNamespacedKey = getNamespacedKey();
+ if (optionalNamespacedKey.isEmpty()) {
+ player.getInventory().addItem(Arrays.stream(getInventory().getContents())
+ .filter(Objects::nonNull)
+ .toArray(ItemStack[]::new))
+ .values()
+ .forEach(item -> player.getWorld().dropItem(player.getLocation(), item));
+ player.sendMiniMessage(Messages.OTHER_ERRORS.UNABLE_TO_SELL_ITEMS, null);
+ return;
+ }
+
+ PointsManagement pointsManagement = PointsManagement.getInstance();
+ NamespacedKey namespacedKey = optionalNamespacedKey.get();
+ List itemsToMoveBack = new ArrayList<>();
+
+ for (ItemStack content : getInventory().getContents()) {
+ if (content == null) {
+ continue;
+ }
+ int points = getPoints(content, namespacedKey);
+ if (points == -1) {
+ itemsToMoveBack.add(content);
+ } else {
+ pointsManagement.addPoints(player.getUniqueId(), points);
+ }
+ }
+ player.getInventory().addItem(itemsToMoveBack.toArray(ItemStack[]::new)).values()
+ .forEach(item -> player.getWorld().dropItem(player.getLocation(), item));
+ }
+
+ /**
+ * @param itemStack ItemStack to check
+ * @return -1 if it has no points, otherwise returns points
+ */
+ public int getPoints(ItemStack itemStack, NamespacedKey namespacedKey) {
+ ItemMeta itemMeta = itemStack.getItemMeta();
+ Integer integer = itemMeta.getPersistentDataContainer().get(namespacedKey, PersistentDataType.INTEGER);
+ return integer == null ? -1 : integer;
+ }
+
+ private Optional getNamespacedKey() {
+ try {
+ NamespacedKey namespacedKey = NamespacedKey.fromString("points", fishingEvent);
+ if (namespacedKey != null)
+ return Optional.of(namespacedKey);
+ } catch (Exception e) {
+ logger.warning("Error while creating namespaced key for points");
+ return Optional.empty();
+ }
+ logger.warning("Error while creating namespaced key for points");
+ return Optional.empty();
+ }
+
+ @Override
+ protected boolean canMoveItems() {
+ return true;
+ }
+}
diff --git a/src/main/java/com/alttd/fishingevent/gui/windows/UpgradeWindow.java b/src/main/java/com/alttd/fishingevent/gui/windows/UpgradeWindow.java
index 3e5bdcf..e28fafa 100644
--- a/src/main/java/com/alttd/fishingevent/gui/windows/UpgradeWindow.java
+++ b/src/main/java/com/alttd/fishingevent/gui/windows/UpgradeWindow.java
@@ -167,4 +167,14 @@ public class UpgradeWindow extends GUI {
public boolean canOpen() {
return canOpen;
}
+
+ @Override
+ protected void closed() {
+
+ }
+
+ @Override
+ protected boolean canMoveItems() {
+ return false;
+ }
}
diff --git a/src/main/java/com/alttd/fishingevent/npc/types/SellNPC.java b/src/main/java/com/alttd/fishingevent/npc/types/SellNPC.java
index 1490b53..ccda976 100644
--- a/src/main/java/com/alttd/fishingevent/npc/types/SellNPC.java
+++ b/src/main/java/com/alttd/fishingevent/npc/types/SellNPC.java
@@ -1,4 +1,86 @@
package com.alttd.fishingevent.npc.types;
-public class SellNPC {
+import com.alttd.fishingevent.FishingEvent;
+import com.alttd.fishingevent.config.Messages;
+import com.alttd.fishingevent.gui.windows.SellWindow;
+import com.alttd.fishingevent.gui.windows.UpgradeWindow;
+import com.alttd.fishingevent.npc.LibNPC;
+import com.alttd.fishingevent.npc.NPC;
+import com.alttd.fishingevent.objects.EnchantmentTrack;
+import com.alttd.fishingevent.util.Logger;
+import com.alttd.fishingevent.util.NPCCreateData;
+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+import org.bukkit.scheduler.BukkitRunnable;
+
+import java.util.List;
+
+public class SellNPC extends LibNPC implements NPC {
+
+ private final NPCCreateData npcCreateData;
+ private final Logger logger;
+ private boolean isSpawned = false;
+ private FishingEvent fishingEvent = null;
+
+ public SellNPC(Logger logger, NPCCreateData npcCreateData) {
+ this.npcCreateData = npcCreateData;
+ this.logger = logger;
+ }
+
+ @Override
+ public String getName() {
+ return npcCreateData.name();
+ }
+
+ @Override
+ public void spawnNPC(FishingEvent fishingEvent, Location location) {
+ defaultSpawnNPC(fishingEvent, location, npcCreateData, logger, this);
+ this.fishingEvent = fishingEvent;
+ isSpawned = true;
+ }
+
+ @Override
+ public void leftClick(Player player) {
+ player.sendMiniMessage(Messages.NPC.UPGRADE_NPC_LEFT_CLICK_MESSAGE, Placeholder.component("player", player.name()));
+ }
+
+ @Override
+ public void rightClick(Player player) {
+ if (fishingEvent == null) {
+ player.sendMiniMessage(Messages.GUI.NOT_INITIALIZED, null);
+ return;
+ }
+ SellWindow sellWindow = new SellWindow(fishingEvent, player, logger);
+ if (!sellWindow.canOpen()) {
+ player.sendMiniMessage(Messages.GUI.NO_FISHING_ROD, null);
+ return;
+ }
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ sellWindow.open(player);
+ }
+ }.runTaskAsynchronously(fishingEvent);
+ }
+
+ @Override
+ public boolean showToPlayer(Player player) {
+ return super.showToPlayer(player);
+ }
+
+ @Override
+ public boolean hideFromPlayer(Player player) {
+ return super.hideFromPlayer(player);
+ }
+
+ @Override
+ public boolean isSpawned(FishingEvent fishingEvent) {
+ return isSpawned;
+ }
+
+ @Override
+ public void updateSkin(Player player) {
+ super.updateSkin(player);
+ }
}