From 1acb5681fca54111d032d494ad4bc25762b9a8a6 Mon Sep 17 00:00:00 2001 From: TDSTOS Date: Thu, 11 Dec 2025 19:47:45 +0100 Subject: [PATCH] Add kit inventory --- .../mcscrims/speedhg/command/KitsCommand.kt | 6 +- .../speedhg/kit/KitInventoryHolder.kt | 9 +- .../speedhg/kit/KitInventoryListener.kt | 60 ++++--- .../speedhg/kit/KitInventoryManager.kt | 170 ++++++++++-------- .../speedhg/listener/GameStateListener.kt | 130 ++++++++++++++ 5 files changed, 271 insertions(+), 104 deletions(-) diff --git a/src/main/kotlin/club/mcscrims/speedhg/command/KitsCommand.kt b/src/main/kotlin/club/mcscrims/speedhg/command/KitsCommand.kt index 447fe69..efc4387 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/command/KitsCommand.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/command/KitsCommand.kt @@ -18,12 +18,14 @@ class KitsCommand( label: String, args: Array ): Boolean { - if (sender !is Player) { + if ( sender !is Player ) + { sender.sendMessage("§cOnly players can use this command.") return true } - kitInventoryManager.openKitInventory(sender, 1) + 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 index 8f6d67f..4091b59 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/kit/KitInventoryHolder.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/kit/KitInventoryHolder.kt @@ -3,13 +3,18 @@ package club.mcscrims.speedhg.kit import org.bukkit.inventory.Inventory import org.bukkit.inventory.InventoryHolder -class KitInventoryHolder(val page: Int) : InventoryHolder { +class KitInventoryHolder( + val page: Int +) : InventoryHolder { private lateinit var inventory: Inventory override fun getInventory(): Inventory = inventory - fun setInventory(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 index 6436500..9cac587 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/kit/KitInventoryListener.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/kit/KitInventoryListener.kt @@ -1,6 +1,7 @@ package club.mcscrims.speedhg.kit import club.mcscrims.speedhg.SpeedHG +import club.mcscrims.speedhg.SpeedHG.Companion.content import org.bukkit.Material import org.bukkit.Sound import org.bukkit.entity.Player @@ -16,46 +17,49 @@ class KitInventoryListener( ) : Listener { @EventHandler - fun onInventoryClick(event: InventoryClickEvent) { + fun onInventoryClick( + event: InventoryClickEvent + ) { val holder = event.inventory.holder - if (holder !is KitInventoryHolder) { + 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) { + if ( clickedItem.type == Material.AIR ) return - } - when (event.rawSlot) { + when( event.rawSlot ) + { 45 -> { - if (holder.page > 1) { - player.playSound(player.location, Sound.UI_BUTTON_CLICK, 1f, 1f) - kitInventoryManager.openKitInventory(player, holder.page - 1) + 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.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) + 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 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, @@ -64,20 +68,22 @@ class KitInventoryListener( 37, 38, 39, 40, 41, 42, 43 ) - val slotIndex = kitSlots.indexOf(event.rawSlot) - if (slotIndex != -1 && slotIndex < kitsOnPage.size) { + 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) + 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) + kitInventoryManager.openKitInventory( player, holder.page ) } else { - player.playSound(player.location, Sound.ENTITY_VILLAGER_NO, 1f, 1f) + player.playSound( player.location, Sound.ENTITY_VILLAGER_NO, 1f, 1f ) } } } @@ -85,11 +91,13 @@ class KitInventoryListener( } @EventHandler - fun onInventoryDrag(event: InventoryDragEvent) { + fun onInventoryDrag( + event: InventoryDragEvent + ) { val holder = event.inventory.holder - if (holder is KitInventoryHolder) { + 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 index 4befd11..c1036e1 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/kit/KitInventoryManager.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/kit/KitInventoryManager.kt @@ -1,7 +1,7 @@ package club.mcscrims.speedhg.kit import club.mcscrims.speedhg.SpeedHG -import club.mcscrims.speedhg.SpeedHG.Companion.content +import kotlinx.coroutines.runBlocking import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor import net.kyori.adventure.text.format.TextDecoration @@ -11,7 +11,6 @@ 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, @@ -21,36 +20,39 @@ class KitInventoryManager( private val kitsPerPage = 28 private val rows = 6 - fun openKitInventory(player: Player, page: Int = 1) { + 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 totalPages = ( allKits.size + kitsPerPage - 1 ) / kitsPerPage + val validPage = page.coerceIn( 1, totalPages.coerceAtLeast( 1 )) - val holder = KitInventoryHolder(validPage) + val holder = KitInventoryHolder( validPage ) val title = Component.text("Kits - Page $validPage/$totalPages") - .color(NamedTextColor.DARK_PURPLE) - .decoration(TextDecoration.BOLD, true) + .color( NamedTextColor.DARK_PURPLE ) + .decoration( TextDecoration.BOLD, true ) - val inventory = Bukkit.createInventory(holder, rows * 9, title) - holder.setInventory(inventory) + val inventory = Bukkit.createInventory( holder, rows * 9, title ) + holder.setInventory( inventory ) - fillBorder(inventory) - fillKits(inventory, allKits, validPage, player) - fillNavigationItems(inventory, validPage, totalPages) + fillBorder( inventory ) + fillKits( inventory, allKits, validPage, player ) + fillNavigationItems( inventory, validPage, totalPages ) - player.openInventory(inventory) + player.openInventory( inventory ) } - private fun fillBorder(inventory: org.bukkit.inventory.Inventory) { + private fun fillBorder( + inventory: org.bukkit.inventory.Inventory + ) { val borderItem = createBorderItem() - for (i in 0..8) { - inventory.setItem(i, borderItem) - } + for ( i in 0..8 ) + inventory.setItem( i, borderItem ) - for (i in 45..53) { - inventory.setItem(i, borderItem) - } + for ( i in 45..53 ) + inventory.setItem( i, borderItem ) } private fun fillKits( @@ -59,11 +61,11 @@ class KitInventoryManager( page: Int, player: Player ) { - val startIndex = (page - 1) * kitsPerPage - val endIndex = (startIndex + kitsPerPage).coerceAtMost(allKits.size) - val kitsOnPage = allKits.subList(startIndex, endIndex) + val startIndex = ( page - 1 ) * kitsPerPage + val endIndex = ( startIndex + kitsPerPage ).coerceAtMost( allKits.size ) + val kitsOnPage = allKits.subList( startIndex, endIndex ) - val selectedKit = kitManager.getSelectedKit(player) + val selectedKit = kitManager.getSelectedKit( player ) val kitSlots = listOf( 10, 11, 12, 13, 14, 15, 16, @@ -73,10 +75,11 @@ class KitInventoryManager( ) kitsOnPage.forEachIndexed { index, kit -> - if (index < kitSlots.size) { + if ( index < kitSlots.size ) + { val isSelected = selectedKit?.id == kit.id - val kitItem = createKitItem(kit, isSelected, player) - inventory.setItem(kitSlots[index], kitItem) + val kitItem = createKitItem( kit, isSelected, player ) + inventory.setItem(kitSlots[ index ], kitItem ) } } } @@ -86,116 +89,135 @@ class KitInventoryManager( page: Int, totalPages: Int ) { - if (page > 1) { - inventory.setItem(45, createPreviousPageItem()) - } + if ( page > 1 ) + inventory.setItem( 45, createPreviousPageItem() ) - inventory.setItem(49, createCloseItem()) + inventory.setItem( 49, createCloseItem() ) - if (page < totalPages) { - inventory.setItem(53, createNextPageItem()) - } + if ( page < totalPages ) + inventory.setItem( 53, createNextPageItem() ) } - private fun createBorderItem(): ItemStack { - val item = ItemStack(Material.GRAY_STAINED_GLASS_PANE) + private fun createBorderItem(): ItemStack + { + val item = ItemStack( Material.GRAY_STAINED_GLASS_PANE ) val meta = item.itemMeta - meta.displayName(Component.text(" ")) + meta.displayName(Component.text( " " )) item.itemMeta = meta return item } - private fun createKitItem(kit: AbstractKit, isSelected: Boolean, player: Player): ItemStack { - val item = ItemStack(kit.icon) + 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)) + meta.displayName(kit.displayName.decoration( TextDecoration.ITALIC, false )) val lore = mutableListOf() - if (isSelected) { + if ( isSelected ) { lore.add( Component.text("✔ Currently Selected") - .color(NamedTextColor.GREEN) - .decoration(TextDecoration.ITALIC, false) + .color( NamedTextColor.GREEN ) + .decoration( TextDecoration.ITALIC, false ) ) } else { lore.add( Component.text("Click to select") - .color(NamedTextColor.YELLOW) - .decoration(TextDecoration.ITALIC, false) + .color( NamedTextColor.YELLOW ) + .decoration( TextDecoration.ITALIC, false ) ) } - lore.add(Component.empty()) + lore.add( Component.empty() ) kit.description.forEach { line -> lore.add( - Component.text(line) - .color(NamedTextColor.GRAY) - .decoration(TextDecoration.ITALIC, false) + 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) + 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.empty() ) lore.add( Component.text("⚠ Locked") - .color(NamedTextColor.RED) - .decoration(TextDecoration.ITALIC, false) - .decoration(TextDecoration.BOLD, true) + .color( NamedTextColor.RED ) + .decoration( TextDecoration.ITALIC, false ) + .decoration( TextDecoration.BOLD, true ) ) } - meta.lore(lore) - meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES) + meta.lore( lore ) + meta.addItemFlags( ItemFlag.HIDE_ATTRIBUTES ) item.itemMeta = meta return item } - private fun createPreviousPageItem(): ItemStack { - val item = ItemStack(Material.ARROW) + 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) + .color( NamedTextColor.YELLOW ) + .decoration( TextDecoration.ITALIC, false ) ) item.itemMeta = meta return item } - private fun createNextPageItem(): ItemStack { - val item = ItemStack(Material.ARROW) + 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) + .color( NamedTextColor.YELLOW ) + .decoration( TextDecoration.ITALIC, false ) ) item.itemMeta = meta return item } - private fun createCloseItem(): ItemStack { - val item = ItemStack(Material.BARRIER) + 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) + .color( NamedTextColor.RED ) + .decoration( TextDecoration.ITALIC, false ) ) item.itemMeta = meta return item } - private fun canUseKit(player: Player, kit: AbstractKit): Boolean { - return true + private fun canUseKit( + player: Player, + kit: AbstractKit + ): Boolean + { + val unlockedKits = mutableListOf() + + runBlocking { + val kitPlayer = plugin.playerRepository.findByUuid( player.uniqueId ) + if ( kitPlayer != null ) unlockedKits.addAll( kitPlayer.unlockedKits ) + } + + return unlockedKits.contains( kit.id ) } + } diff --git a/src/main/kotlin/club/mcscrims/speedhg/listener/GameStateListener.kt b/src/main/kotlin/club/mcscrims/speedhg/listener/GameStateListener.kt index 5b4fb2d..62e24a6 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/listener/GameStateListener.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/listener/GameStateListener.kt @@ -4,12 +4,16 @@ import club.mcscrims.speedhg.SpeedHG import club.mcscrims.speedhg.game.GameManager import club.mcscrims.speedhg.game.GameStateTypes import club.mcscrims.speedhg.util.DirectionUtil +import club.mcscrims.spigot.chat.getDisplayName import kotlinx.coroutines.runBlocking import org.bukkit.Bukkit import org.bukkit.Material import org.bukkit.Sound import org.bukkit.attribute.Attribute +import org.bukkit.entity.Entity import org.bukkit.entity.Player +import org.bukkit.entity.Projectile +import org.bukkit.entity.Tameable import org.bukkit.event.Event import org.bukkit.event.EventHandler import org.bukkit.event.Listener @@ -22,6 +26,7 @@ import org.bukkit.event.enchantment.EnchantItemEvent import org.bukkit.event.entity.EntityDamageByEntityEvent import org.bukkit.event.entity.EntityDamageEvent import org.bukkit.event.entity.FoodLevelChangeEvent +import org.bukkit.event.entity.PlayerDeathEvent import org.bukkit.event.inventory.ClickType import org.bukkit.event.inventory.CraftItemEvent import org.bukkit.event.inventory.InventoryClickEvent @@ -542,4 +547,129 @@ class GameStateListener( event.isCancelled = true } + enum class DeathType { + PLAYER, + ENTITY, + WORLD + } + + private val playerDeathMessages: Int = plugin.messageConfig.data.deathMessages["player"]!!.size + private val entityDeathMessages: Int = plugin.messageConfig.data.deathMessages["entity"]!!.size + private val worldDeathMessages: Int = plugin.messageConfig.data.deathMessages["world"]!!.size + + @EventHandler + fun onDeath( + event: PlayerDeathEvent + ) { + val player = event.entity + suppressEvent( event ) + + val lastDamageCause = player.lastDamageCause + var killer: Entity? = null + var deathType = DeathType.WORLD + + if ( lastDamageCause is EntityDamageByEntityEvent ) + { + val damager = lastDamageCause.damager + + if ( damager !is Player ) + { + if ( damager is Projectile ) + { + if ( damager.shooter is Player ) + { + deathType = DeathType.PLAYER + killer = damager.shooter as Player + } + else + { + deathType = DeathType.ENTITY + killer = damager.shooter as Entity + } + } + else if ( damager is Tameable && damager.isTamed && damager.owner is Player ) + { + deathType = DeathType.PLAYER + killer = damager.owner as Player + } + else + { + deathType = DeathType.ENTITY + killer = damager + } + } + else + { + deathType = DeathType.PLAYER + killer = damager + } + } + + if ( killer != null && killer is Player ) + { + killer.exp += 0.5f + runBlocking { plugin.statsRepository.addKills( killer.uniqueId, 1 ) } + } + + when( deathType ) + { + DeathType.PLAYER -> + { + val random = this.random.nextInt( 0, playerDeathMessages ) + + val message = plugin.chatFormatter.formatList( "death.player", + "{player}" to player.getDisplayName, "{killer}" to (killer as Player).getDisplayName + )[ random ] + + for ( p in Bukkit.getOnlinePlayers() ) + plugin.chatManager.sendInteractiveMessage( p, message ) + } + + DeathType.ENTITY -> + { + val random = this.random.nextInt( 0, entityDeathMessages ) + + val message = plugin.chatFormatter.formatList( "death.entity", + "{player}" to player.getDisplayName, "{entity}" to killer!!.type.name + )[ random ] + + for ( p in Bukkit.getOnlinePlayers() ) + plugin.chatManager.sendInteractiveMessage( p, message ) + } + + DeathType.WORLD -> + { + val random = this.random.nextInt( 0, worldDeathMessages ) + + val message = plugin.chatFormatter.formatList( "death.world", + "{player}" to player.getDisplayName + )[ random ] + + for ( p in Bukkit.getOnlinePlayers() ) + plugin.chatManager.sendInteractiveMessage( p, message ) + } + } + } + + private fun suppressEvent( + event: PlayerDeathEvent + ) { + val player = event.entity + + event.deathMessage( null ) + + event.setShouldDropExperience( false ) + + event.setShouldPlayDeathSound( false ) + player.world.strikeLightningEffect( player.location ) + + runBlocking { + plugin.statsRepository.addDeaths( player.uniqueId, 1 ) + plugin.playerRepository.updateAliveStatus( player.uniqueId, false ) + } + + if ( player.isOnline ) + player.kick(plugin.chatFormatter.format( "death.kick" )) + } + } \ No newline at end of file