diff --git a/src/main/kotlin/club/mcscrims/speedhg/SpeedHG.kt b/src/main/kotlin/club/mcscrims/speedhg/SpeedHG.kt index bd3bd7d..77d094b 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/SpeedHG.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/SpeedHG.kt @@ -5,6 +5,7 @@ import club.mcscrims.core.config.ConfigFormat import club.mcscrims.core.config.ConfigLoader import club.mcscrims.core.database.DatabaseConfig import club.mcscrims.core.database.mongodb.MongoManager +import club.mcscrims.speedhg.config.KitConfig import club.mcscrims.speedhg.config.MessageConfig import club.mcscrims.speedhg.config.PluginConfig import club.mcscrims.speedhg.database.StatsRepository @@ -31,6 +32,7 @@ class SpeedHG : JavaPlugin() { private lateinit var configLoader: ConfigLoader internal lateinit var pluginConfig: ConfigData internal lateinit var messageConfig: ConfigData + internal lateinit var kitConfig: ConfigData internal lateinit var databaseConfig: ConfigData internal lateinit var chatManager: ChatManager @@ -171,6 +173,12 @@ class SpeedHG : JavaPlugin() { autoReload = false ) + kitConfig = configLoader.loadConfig( + fileName = "kits.yml", + format = ConfigFormat.YAML, + autoReload = false + ) + databaseConfig = configLoader.loadConfig( fileName = "database.json", format = ConfigFormat.JSON, @@ -184,6 +192,7 @@ class SpeedHG : JavaPlugin() { { pluginConfig.reload() messageConfig.reload() + kitConfig.reload() databaseConfig.reload() } catch ( ex: Exception ) { diff --git a/src/main/kotlin/club/mcscrims/speedhg/ability/AbilityContext.kt b/src/main/kotlin/club/mcscrims/speedhg/ability/AbilityContext.kt index 1d9b7f2..12d333e 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/ability/AbilityContext.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/ability/AbilityContext.kt @@ -3,8 +3,8 @@ package club.mcscrims.speedhg.ability import org.bukkit.entity.Player class AbilityContext( - private val cooldownManager: CooldownManager, - private val hitCounterManager: HitCounterManager + val cooldownManager: CooldownManager, + val hitCounterManager: HitCounterManager ) { fun canUseAbility( diff --git a/src/main/kotlin/club/mcscrims/speedhg/config/KitConfig.kt b/src/main/kotlin/club/mcscrims/speedhg/config/KitConfig.kt index c37cdc7..54849da 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/config/KitConfig.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/config/KitConfig.kt @@ -50,6 +50,23 @@ data class KitConfig( rattlesnake + tesla + voodoo } + fun getConfigForKit(id: String): Map + { + return when (id.lowercase()) { + "anchor" -> anchor + "armorer" -> armorer + "blackpanther" -> blackPanther + "gladiator" -> gladiator + "goblin" -> goblin + "icemage" -> iceMage + "poseidon" -> poseidon + "rattlesnake" -> rattlesnake + "tesla" -> tesla + "voodoo" -> voodoo + else -> emptyMap() + } + } + } private fun getAnchorConfigurations() = mapOf( diff --git a/src/main/kotlin/club/mcscrims/speedhg/kit/AbstractKit.kt b/src/main/kotlin/club/mcscrims/speedhg/kit/AbstractKit.kt new file mode 100644 index 0000000..2766e66 --- /dev/null +++ b/src/main/kotlin/club/mcscrims/speedhg/kit/AbstractKit.kt @@ -0,0 +1,70 @@ +package club.mcscrims.speedhg.kit + +import club.mcscrims.speedhg.SpeedHG +import club.mcscrims.speedhg.ability.AbilityContext +import club.mcscrims.speedhg.ability.AbilityResult +import org.bukkit.Material +import org.bukkit.entity.Player +import org.bukkit.event.entity.EntityDamageByEntityEvent +import org.bukkit.event.player.PlayerInteractEvent + +abstract class AbstractKit( + val id: String, + val displayName: String, + val description: List, + val icon: Material, + protected val plugin: SpeedHG, + protected val abilityContext: AbilityContext +) { + + lateinit var config: Map + + open fun onSelect(player: Player) { + } + + open fun onStart(player: Player) { + } + + open fun onHit(attacker: Player, victim: Player, event: EntityDamageByEntityEvent) { + } + + open fun onInteract(player: Player, event: PlayerInteractEvent) { + } + + open fun cleanup(player: Player) { + abilityContext.clearPlayerData(player) + } + + protected fun hasCooldown(player: Player, key: String): Boolean { + return abilityContext.getRemainingCooldown(player, key) > 0 + } + + protected fun startCooldown(player: Player, key: String, seconds: Int) { + abilityContext.cooldownManager.startCooldown(player, key, seconds) + } + + protected fun getRemainingCooldown(player: Player, key: String): Double { + return abilityContext.getRemainingCooldown(player, key) + } + + protected fun incrementHits(player: Player, key: String): Int { + return abilityContext.incrementHit(player, key) + } + + protected fun getHits(player: Player, key: String): Int { + return abilityContext.getHits(player, key) + } + + protected fun resetHits(player: Player, key: String) { + abilityContext.hitCounterManager.resetHits(player, key) + } + + protected fun abilityResult( + player: Player, + abilityKey: String, + requiredHits: Int? = null, + cooldownSeconds: Int? = null + ): AbilityResult { + return abilityContext.canUseAbility(player, abilityKey, requiredHits, cooldownSeconds) + } +} diff --git a/src/main/kotlin/club/mcscrims/speedhg/kit/KitListener.kt b/src/main/kotlin/club/mcscrims/speedhg/kit/KitListener.kt new file mode 100644 index 0000000..e6b244d --- /dev/null +++ b/src/main/kotlin/club/mcscrims/speedhg/kit/KitListener.kt @@ -0,0 +1,29 @@ +package club.mcscrims.speedhg.kit + +import org.bukkit.entity.Player +import org.bukkit.event.EventHandler +import org.bukkit.event.Listener +import org.bukkit.event.entity.EntityDamageByEntityEvent +import org.bukkit.event.player.PlayerInteractEvent + +class KitListener(private val kitManager: KitManager) : Listener { + + @EventHandler + fun onEntityDamage(event: EntityDamageByEntityEvent) { + val attacker = event.damager as? Player ?: return + val victim = event.entity as? Player ?: return + + if (kitManager.getSelectedKit(attacker) != null) { + kitManager.triggerHit(attacker, victim, event) + } + } + + @EventHandler + fun onPlayerInteract(event: PlayerInteractEvent) { + val player = event.player + + if (kitManager.getSelectedKit(player) != null) { + kitManager.triggerInteract(player, event) + } + } +} diff --git a/src/main/kotlin/club/mcscrims/speedhg/kit/KitManager.kt b/src/main/kotlin/club/mcscrims/speedhg/kit/KitManager.kt new file mode 100644 index 0000000..12b714d --- /dev/null +++ b/src/main/kotlin/club/mcscrims/speedhg/kit/KitManager.kt @@ -0,0 +1,99 @@ +package club.mcscrims.speedhg.kit + +import club.mcscrims.speedhg.SpeedHG +import org.bukkit.entity.Player +import org.bukkit.event.entity.EntityDamageByEntityEvent +import org.bukkit.event.player.PlayerInteractEvent +import java.util.UUID +import java.util.concurrent.ConcurrentHashMap + +class KitManager(private val plugin: SpeedHG) { + + private val kits = ConcurrentHashMap() + private val selectedKits = ConcurrentHashMap() + + fun registerKit(kit: AbstractKit) { + kit.config = plugin.kitConfig.data.getConfigForKit(kit.id) + kits[kit.id.lowercase()] = kit + plugin.logger.info("Registered kit: ${kit.displayName} (${kit.id})") + } + + fun getKit(id: String): AbstractKit? { + return kits[id.lowercase()] + } + + fun getAllKits(): Collection { + return kits.values + } + + fun selectKit(player: Player, kitId: String): Boolean { + val kit = getKit(kitId) ?: return false + + val previousKit = selectedKits[player.uniqueId] + previousKit?.cleanup(player) + + selectedKits[player.uniqueId] = kit + + try { + kit.onSelect(player) + } catch (e: Exception) { + plugin.logger.severe("Error during onSelect for kit ${kit.id} and player ${player.name}: ${e.message}") + e.printStackTrace() + } + + return true + } + + fun getSelectedKit(player: Player): AbstractKit? { + return selectedKits[player.uniqueId] + } + + fun startKitForPlayer(player: Player) { + val kit = selectedKits[player.uniqueId] ?: return + + try { + kit.onStart(player) + } catch (e: Exception) { + plugin.logger.severe("Error during onStart for kit ${kit.id} and player ${player.name}: ${e.message}") + e.printStackTrace() + } + } + + fun triggerHit(attacker: Player, victim: Player, event: EntityDamageByEntityEvent) { + val kit = selectedKits[attacker.uniqueId] ?: return + + try { + kit.onHit(attacker, victim, event) + } catch (e: Exception) { + plugin.logger.severe("Error during onHit for kit ${kit.id} and player ${attacker.name}: ${e.message}") + e.printStackTrace() + } + } + + fun triggerInteract(player: Player, event: PlayerInteractEvent) { + val kit = selectedKits[player.uniqueId] ?: return + + try { + kit.onInteract(player, event) + } catch (e: Exception) { + plugin.logger.severe("Error during onInteract for kit ${kit.id} and player ${player.name}: ${e.message}") + e.printStackTrace() + } + } + + fun clearPlayerSelection(player: Player) { + val kit = selectedKits.remove(player.uniqueId) + kit?.cleanup(player) + } + + fun clearAll() { + selectedKits.values.forEach { kit -> + plugin.server.onlinePlayers.forEach { player -> + if (selectedKits[player.uniqueId] == kit) { + kit.cleanup(player) + } + } + } + selectedKits.clear() + } +} diff --git a/src/main/kotlin/club/mcscrims/speedhg/kit/impl/AnchorKit.kt b/src/main/kotlin/club/mcscrims/speedhg/kit/impl/AnchorKit.kt new file mode 100644 index 0000000..b6d1ab5 --- /dev/null +++ b/src/main/kotlin/club/mcscrims/speedhg/kit/impl/AnchorKit.kt @@ -0,0 +1,85 @@ +package club.mcscrims.speedhg.kit.impl + +import club.mcscrims.speedhg.SpeedHG +import club.mcscrims.speedhg.ability.AbilityContext +import club.mcscrims.speedhg.kit.AbstractKit +import org.bukkit.Material +import org.bukkit.entity.Player +import org.bukkit.event.entity.EntityDamageByEntityEvent +import org.bukkit.event.player.PlayerInteractEvent +import org.bukkit.inventory.ItemStack +import org.bukkit.potion.PotionEffect +import org.bukkit.potion.PotionEffectType + +class AnchorKit( + plugin: SpeedHG, + abilityContext: AbilityContext +) : AbstractKit( + id = "anchor", + displayName = "Anchor", + description = listOf( + "§7Heavy and strong.", + "§7Deal extra damage after 3 hits.", + "§7Gain resistance when standing still." + ), + icon = Material.ANVIL, + plugin = plugin, + abilityContext = abilityContext +) { + + private val abilityKey = "anchor_ability" + private val hitCounterKey = "anchor_hits" + + override fun onSelect(player: Player) { + player.sendMessage("§aYou selected §6Anchor§a!") + } + + override fun onStart(player: Player) { + player.inventory.addItem(ItemStack(Material.STONE_SWORD)) + player.inventory.helmet = ItemStack(Material.IRON_HELMET) + player.inventory.chestplate = ItemStack(Material.IRON_CHESTPLATE) + player.inventory.leggings = ItemStack(Material.IRON_LEGGINGS) + player.inventory.boots = ItemStack(Material.IRON_BOOTS) + } + + override fun onHit(attacker: Player, victim: Player, event: EntityDamageByEntityEvent) { + val currentHits = incrementHits(attacker, hitCounterKey) + + val result = abilityResult( + player = attacker, + abilityKey = abilityKey, + requiredHits = 3, + cooldownSeconds = 10 + ) + + if (result.success) { + val extraDamage = config["offensive extra damage"] ?: 1.0 + event.damage += extraDamage + + attacker.sendMessage("§6⚓ Anchor Ability! §eDealt ${extraDamage} extra damage!") + victim.sendMessage("§c${attacker.name} used Anchor ability!") + } else if (result.missingHits > 0) { + attacker.sendMessage("§e⚓ Hits: $currentHits/3") + } else if (result.remainingCooldown > 0) { + attacker.sendMessage("§c⚓ Cooldown: ${String.format("%.1f", result.remainingCooldown)}s") + } + } + + override fun onInteract(player: Player, event: PlayerInteractEvent) { + if (event.action.isRightClick && event.item?.type == Material.ANVIL) { + if (!hasCooldown(player, "anchor_resistance")) { + player.addPotionEffect(PotionEffect(PotionEffectType.RESISTANCE, 100, 0)) + player.sendMessage("§6⚓ Resistance activated!") + startCooldown(player, "anchor_resistance", 15) + } else { + val remaining = getRemainingCooldown(player, "anchor_resistance") + player.sendMessage("§c⚓ Resistance on cooldown: ${String.format("%.1f", remaining)}s") + } + } + } + + override fun cleanup(player: Player) { + super.cleanup(player) + player.sendMessage("§7Anchor kit cleaned up.") + } +} diff --git a/src/main/resources/kits.yml b/src/main/resources/kits.yml new file mode 100644 index 0000000..94bc72c --- /dev/null +++ b/src/main/resources/kits.yml @@ -0,0 +1,60 @@ +anchor: + offensive extra damage: 1.0 + +armorer: + kills until new armor: 2.0 + +blackpanther: + enderpearl hit damage: 3.0 + extra damage on top: 0.5 + default hit radius: 3.0 + explosion multiplier: 3.0 + +gladiator: + cage radius: 23.0 + cage height: 10.0 + wither effect after x seconds: 180.0 + +goblin: + bunker radius: 10.0 + bunker time until disappear: 15.0 + knockback and pullin radius: 7.0 + kit steal time: 60.0 + soup steal chance: 20.0 + +icemage: + chance for slowness: 2.0 + +poseidon: + default hit radius: 3.0 + lightning hit damage: 4.0 + +rattlesnake: + maximum jump distance: 10.0 + speed duration: 10.0 + poison duration: 8.0 + maximum negative effect duration: 16.0 + default jump radius: 10.0 + +tesla: + disable push at height: 50.0 + default thunder radius: 5.0 + push strength: 1.0 + fire tick duration: 5.0 + time until thunder disables: 7.0 + thunder damage: 1.5 + +voodoo: + default curse radius: 3.0 + maximum effect duration: 15.0 + clicked players minimum health: 10.0 + voodoo hold duration: 5.0 + chance for wither effect: 5.0 + +perks: + knockback: + knockback strength: 1.5 + pullin: + pullin strength: 0.5 + radiusincrease: + new radius: 5.0