diff --git a/src/main/kotlin/club/mcscrims/speedhg/SpeedHG.kt b/src/main/kotlin/club/mcscrims/speedhg/SpeedHG.kt index 8899f2b..d8806e8 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/SpeedHG.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/SpeedHG.kt @@ -14,6 +14,9 @@ import club.mcscrims.speedhg.config.MessageConfig import club.mcscrims.speedhg.config.PluginConfig import club.mcscrims.speedhg.database.StatsRepository import club.mcscrims.speedhg.game.GameManager +import club.mcscrims.speedhg.command.KitsCommand +import club.mcscrims.speedhg.kit.KitInventoryListener +import club.mcscrims.speedhg.kit.KitInventoryManager import club.mcscrims.speedhg.kit.KitListener import club.mcscrims.speedhg.kit.KitManager import club.mcscrims.speedhg.listener.GameStateListener @@ -66,6 +69,7 @@ class SpeedHG : JavaPlugin() { internal lateinit var abilityContext: AbilityContext internal lateinit var kitManager: KitManager + internal lateinit var kitInventoryManager: KitInventoryManager internal lateinit var worldEditUtils: WorldEditUtils @@ -111,8 +115,11 @@ class SpeedHG : JavaPlugin() { kitManager = KitManager( this ) kitManager.initialize() + kitInventoryManager = KitInventoryManager( this, kitManager ) + setupLuckPerms() registerListener() + registerCommands() RecraftUtils.registerRecipes() RecraftInspector( this ).startRunnable() @@ -129,10 +136,16 @@ class SpeedHG : JavaPlugin() { { server.pluginManager.registerEvents(GameStateListener( this, gameManager ), this ) server.pluginManager.registerEvents(KitListener( this, kitManager ), this ) + server.pluginManager.registerEvents(KitInventoryListener( this, kitManager, kitInventoryManager ), this ) server.pluginManager.registerEvents(AbilityHitListener( this, abilityContext ), this ) LunarClientListener( this ) } + private fun registerCommands() + { + getCommand("kits")?.setExecutor(KitsCommand( this, kitInventoryManager )) + } + /* * LUCKPERMS >> */ diff --git a/src/main/kotlin/club/mcscrims/speedhg/command/KitsCommand.kt b/src/main/kotlin/club/mcscrims/speedhg/command/KitsCommand.kt new file mode 100644 index 0000000..447fe69 --- /dev/null +++ b/src/main/kotlin/club/mcscrims/speedhg/command/KitsCommand.kt @@ -0,0 +1,29 @@ +package club.mcscrims.speedhg.command + +import club.mcscrims.speedhg.SpeedHG +import club.mcscrims.speedhg.kit.KitInventoryManager +import org.bukkit.command.Command +import org.bukkit.command.CommandExecutor +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player + +class KitsCommand( + private val plugin: SpeedHG, + private val kitInventoryManager: KitInventoryManager +) : CommandExecutor { + + override fun onCommand( + sender: CommandSender, + command: Command, + label: String, + args: Array + ): Boolean { + if (sender !is Player) { + sender.sendMessage("§cOnly players can use this command.") + return true + } + + kitInventoryManager.openKitInventory(sender, 1) + return true + } +} diff --git a/src/main/kotlin/club/mcscrims/speedhg/kit/KitInventoryHolder.kt b/src/main/kotlin/club/mcscrims/speedhg/kit/KitInventoryHolder.kt new file mode 100644 index 0000000..8f6d67f --- /dev/null +++ b/src/main/kotlin/club/mcscrims/speedhg/kit/KitInventoryHolder.kt @@ -0,0 +1,15 @@ +package club.mcscrims.speedhg.kit + +import org.bukkit.inventory.Inventory +import org.bukkit.inventory.InventoryHolder + +class KitInventoryHolder(val page: Int) : InventoryHolder { + + private lateinit var inventory: Inventory + + override fun getInventory(): Inventory = inventory + + fun setInventory(inventory: Inventory) { + this.inventory = inventory + } +} diff --git a/src/main/kotlin/club/mcscrims/speedhg/kit/KitInventoryListener.kt b/src/main/kotlin/club/mcscrims/speedhg/kit/KitInventoryListener.kt new file mode 100644 index 0000000..6436500 --- /dev/null +++ b/src/main/kotlin/club/mcscrims/speedhg/kit/KitInventoryListener.kt @@ -0,0 +1,95 @@ +package club.mcscrims.speedhg.kit + +import club.mcscrims.speedhg.SpeedHG +import org.bukkit.Material +import org.bukkit.Sound +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.InventoryDragEvent + +class KitInventoryListener( + private val plugin: SpeedHG, + private val kitManager: KitManager, + private val kitInventoryManager: KitInventoryManager +) : Listener { + + @EventHandler + fun onInventoryClick(event: InventoryClickEvent) { + val holder = event.inventory.holder + + if (holder !is KitInventoryHolder) { + return + } + + event.isCancelled = true + + val player = event.whoClicked as? Player ?: return + val clickedItem = event.currentItem ?: return + + if (clickedItem.type == Material.AIR) { + return + } + + when (event.rawSlot) { + 45 -> { + if (holder.page > 1) { + player.playSound(player.location, Sound.UI_BUTTON_CLICK, 1f, 1f) + kitInventoryManager.openKitInventory(player, holder.page - 1) + } + } + 49 -> { + player.playSound(player.location, Sound.UI_BUTTON_CLICK, 1f, 0.8f) + player.closeInventory() + } + 53 -> { + val totalKits = kitManager.getAllKits().size + val totalPages = (totalKits + 27) / 28 + if (holder.page < totalPages) { + player.playSound(player.location, Sound.UI_BUTTON_CLICK, 1f, 1f) + kitInventoryManager.openKitInventory(player, holder.page + 1) + } + } + in 10..43 -> { + val allKits = kitManager.getAllKits().toList() + val startIndex = (holder.page - 1) * 28 + val endIndex = (startIndex + 28).coerceAtMost(allKits.size) + val kitsOnPage = allKits.subList(startIndex, endIndex) + + val kitSlots = listOf( + 10, 11, 12, 13, 14, 15, 16, + 19, 20, 21, 22, 23, 24, 25, + 28, 29, 30, 31, 32, 33, 34, + 37, 38, 39, 40, 41, 42, 43 + ) + + val slotIndex = kitSlots.indexOf(event.rawSlot) + if (slotIndex != -1 && slotIndex < kitsOnPage.size) { + val selectedKit = kitsOnPage[slotIndex] + + if (kitManager.selectKit(player, selectedKit.id)) { + player.playSound(player.location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1f, 1.2f) + plugin.chatManager.sendMessage( + player, + "kits.selected", + "{kit}" to selectedKit.displayName.content() + ) + kitInventoryManager.openKitInventory(player, holder.page) + } else { + player.playSound(player.location, Sound.ENTITY_VILLAGER_NO, 1f, 1f) + } + } + } + } + } + + @EventHandler + fun onInventoryDrag(event: InventoryDragEvent) { + val holder = event.inventory.holder + + if (holder is KitInventoryHolder) { + event.isCancelled = true + } + } +} diff --git a/src/main/kotlin/club/mcscrims/speedhg/kit/KitInventoryManager.kt b/src/main/kotlin/club/mcscrims/speedhg/kit/KitInventoryManager.kt new file mode 100644 index 0000000..4befd11 --- /dev/null +++ b/src/main/kotlin/club/mcscrims/speedhg/kit/KitInventoryManager.kt @@ -0,0 +1,201 @@ +package club.mcscrims.speedhg.kit + +import club.mcscrims.speedhg.SpeedHG +import club.mcscrims.speedhg.SpeedHG.Companion.content +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.format.NamedTextColor +import net.kyori.adventure.text.format.TextDecoration +import org.bukkit.Bukkit +import org.bukkit.Material +import org.bukkit.enchantments.Enchantment +import org.bukkit.entity.Player +import org.bukkit.inventory.ItemFlag +import org.bukkit.inventory.ItemStack +import org.bukkit.inventory.meta.ItemMeta + +class KitInventoryManager( + private val plugin: SpeedHG, + private val kitManager: KitManager +) { + + private val kitsPerPage = 28 + private val rows = 6 + + fun openKitInventory(player: Player, page: Int = 1) { + val allKits = kitManager.getAllKits().toList() + val totalPages = (allKits.size + kitsPerPage - 1) / kitsPerPage + val validPage = page.coerceIn(1, totalPages.coerceAtLeast(1)) + + val holder = KitInventoryHolder(validPage) + val title = Component.text("Kits - Page $validPage/$totalPages") + .color(NamedTextColor.DARK_PURPLE) + .decoration(TextDecoration.BOLD, true) + + val inventory = Bukkit.createInventory(holder, rows * 9, title) + holder.setInventory(inventory) + + fillBorder(inventory) + fillKits(inventory, allKits, validPage, player) + fillNavigationItems(inventory, validPage, totalPages) + + player.openInventory(inventory) + } + + private fun fillBorder(inventory: org.bukkit.inventory.Inventory) { + val borderItem = createBorderItem() + + for (i in 0..8) { + inventory.setItem(i, borderItem) + } + + for (i in 45..53) { + inventory.setItem(i, borderItem) + } + } + + private fun fillKits( + inventory: org.bukkit.inventory.Inventory, + allKits: List, + page: Int, + player: Player + ) { + val startIndex = (page - 1) * kitsPerPage + val endIndex = (startIndex + kitsPerPage).coerceAtMost(allKits.size) + val kitsOnPage = allKits.subList(startIndex, endIndex) + + val selectedKit = kitManager.getSelectedKit(player) + + val kitSlots = listOf( + 10, 11, 12, 13, 14, 15, 16, + 19, 20, 21, 22, 23, 24, 25, + 28, 29, 30, 31, 32, 33, 34, + 37, 38, 39, 40, 41, 42, 43 + ) + + kitsOnPage.forEachIndexed { index, kit -> + if (index < kitSlots.size) { + val isSelected = selectedKit?.id == kit.id + val kitItem = createKitItem(kit, isSelected, player) + inventory.setItem(kitSlots[index], kitItem) + } + } + } + + private fun fillNavigationItems( + inventory: org.bukkit.inventory.Inventory, + page: Int, + totalPages: Int + ) { + if (page > 1) { + inventory.setItem(45, createPreviousPageItem()) + } + + inventory.setItem(49, createCloseItem()) + + if (page < totalPages) { + inventory.setItem(53, createNextPageItem()) + } + } + + private fun createBorderItem(): ItemStack { + val item = ItemStack(Material.GRAY_STAINED_GLASS_PANE) + val meta = item.itemMeta + meta.displayName(Component.text(" ")) + item.itemMeta = meta + return item + } + + private fun createKitItem(kit: AbstractKit, isSelected: Boolean, player: Player): ItemStack { + val item = ItemStack(kit.icon) + val meta = item.itemMeta + + meta.displayName(kit.displayName.decoration(TextDecoration.ITALIC, false)) + + val lore = mutableListOf() + + if (isSelected) { + lore.add( + Component.text("✔ Currently Selected") + .color(NamedTextColor.GREEN) + .decoration(TextDecoration.ITALIC, false) + ) + } else { + lore.add( + Component.text("Click to select") + .color(NamedTextColor.YELLOW) + .decoration(TextDecoration.ITALIC, false) + ) + } + + lore.add(Component.empty()) + + kit.description.forEach { line -> + lore.add( + Component.text(line) + .color(NamedTextColor.GRAY) + .decoration(TextDecoration.ITALIC, false) + ) + } + + if (canUseKit(player, kit)) { + if (isSelected) { + meta.addEnchant(Enchantment.UNBREAKING, 1, true) + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS) + } + } else { + lore.add(Component.empty()) + lore.add( + Component.text("⚠ Locked") + .color(NamedTextColor.RED) + .decoration(TextDecoration.ITALIC, false) + .decoration(TextDecoration.BOLD, true) + ) + } + + meta.lore(lore) + meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES) + item.itemMeta = meta + + return item + } + + private fun createPreviousPageItem(): ItemStack { + val item = ItemStack(Material.ARROW) + val meta = item.itemMeta + meta.displayName( + Component.text("← Previous Page") + .color(NamedTextColor.YELLOW) + .decoration(TextDecoration.ITALIC, false) + ) + item.itemMeta = meta + return item + } + + private fun createNextPageItem(): ItemStack { + val item = ItemStack(Material.ARROW) + val meta = item.itemMeta + meta.displayName( + Component.text("Next Page →") + .color(NamedTextColor.YELLOW) + .decoration(TextDecoration.ITALIC, false) + ) + item.itemMeta = meta + return item + } + + private fun createCloseItem(): ItemStack { + val item = ItemStack(Material.BARRIER) + val meta = item.itemMeta + meta.displayName( + Component.text("Close") + .color(NamedTextColor.RED) + .decoration(TextDecoration.ITALIC, false) + ) + item.itemMeta = meta + return item + } + + private fun canUseKit(player: Player, kit: AbstractKit): Boolean { + return true + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index ec57b38..1d75161 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -2,3 +2,8 @@ name: GameModes-SpeedHG version: '1.0.0' main: club.mcscrims.speedhg.SpeedHG api-version: '1.21' + +commands: + kits: + description: Open the kit selection menu + usage: /kits