package club.mcscrims.speedhg.kit import club.mcscrims.speedhg.kit.ability.ActiveAbility import club.mcscrims.speedhg.kit.ability.PassiveAbility import net.kyori.adventure.text.Component import org.bukkit.Material import org.bukkit.entity.Player import org.bukkit.inventory.ItemStack import java.util.* import java.util.concurrent.ConcurrentHashMap /** * Base class for every kit in SpeedHG. * * ## How to create a new kit * 1. Extend this class. * 2. Implement all abstract members. * 3. For each [Playstyle], create a private inner class extending [ActiveAbility] * and another extending [PassiveAbility]. * 4. Return the correct instance from [getActiveAbility] / [getPassiveAbility] * using a `when(playstyle)` expression. * 5. Register the kit via `plugin.kitManager.registerKit(YourKit())` in [SpeedHG.onEnable]. * * See [TemplateKit] for a fully annotated example. */ abstract class Kit { /** Unique snake_case identifier (e.g. `"warrior"`, `"archer"`). */ abstract val id: String /** Coloured display name shown in the kit selection GUI. */ abstract val displayName: Component /** Short lore lines shown on the item in the kit GUI. */ abstract val lore: List /** Icon used in the kit selection GUI. */ abstract val icon: Material // ------------------------------------------------------------------------- // Playstyle-specific abilities — implement with a `when` expression // ------------------------------------------------------------------------- /** * Return the [ActiveAbility] for the given [playstyle]. * * ```kotlin * override fun getActiveAbility(playstyle: Playstyle) = when (playstyle) { * Playstyle.AGGRESSIVE -> AggressiveActive() * Playstyle.DEFENSIVE -> DefensiveActive() * } * ``` * * **Performance note:** This is called frequently by [KitEventDispatcher]. * Prefer returning a cached singleton (`private val aggressiveActive = AggressiveActive()`) * over allocating a new instance on each call. */ abstract fun getActiveAbility( playstyle: Playstyle ): ActiveAbility /** Return the [PassiveAbility] for the given [playstyle]. Same caching advice applies. */ abstract fun getPassiveAbility( playstyle: Playstyle ): PassiveAbility // ------------------------------------------------------------------------- // Item distribution // ------------------------------------------------------------------------- abstract val cachedItems: ConcurrentHashMap> /** * Give the player their kit-specific items at game start (after teleportation). * The standard HG items (soup, compass, etc.) are already given by [GameManager]. * Only add kit-exclusive items here. */ abstract fun giveItems( player: Player, playstyle: Playstyle ) // ------------------------------------------------------------------------- // Lifecycle hooks (optional) // ------------------------------------------------------------------------- /** * Called once per round when the kit is applied to [player]. * Use for permanent potion effects, scoreboard objectives, repeating tasks, etc. * The matching [PassiveAbility.onActivate] is called immediately after this. */ open fun onAssign( player: Player, playstyle: Playstyle ) {} /** * Called when the kit is removed (game over / round reset). * The matching [PassiveAbility.onDeactivate] is called immediately before this. */ open fun onRemove( player: Player ) {} }