package club.mcscrims.speedhg.perk import net.kyori.adventure.text.Component import org.bukkit.Material import org.bukkit.entity.Player import org.bukkit.event.entity.EntityDamageByEntityEvent import org.bukkit.event.entity.EntityDamageEvent /** * Basisklasse für alle passiven Perks in SpeedHG. * * Perks sind passive Boni, die Spieler neben ihrem Kit ausrüsten. * Ein Spieler darf maximal [PerkManager.MAX_PERKS] Perks gleichzeitig aktiv haben. * * ## Neuen Perk erstellen * 1. Diese Klasse erweitern. * 2. Alle abstrakten Member implementieren. * 3. Nur die Hooks überschreiben, die tatsächlich gebraucht werden — alle Defaults sind No-Ops. * 4. Via `plugin.perkManager.registerPerk(DeinPerk())` in [SpeedHG.onEnable] registrieren. */ abstract class Perk { /** Eindeutiger snake_case Bezeichner. Muss dem Sprachschlüssel-Prefix `perks..*` entsprechen. */ abstract val id: String /** Angezeigter Name im GUI, aus der Sprachdatei geladen. */ abstract val displayName: Component /** Kurze Lore-Zeilen als MiniMessage-Strings aus der Sprachdatei. */ abstract val lore: List /** Icon-Material im Perk-Selector-GUI. */ abstract val icon: Material // ── Lifecycle ───────────────────────────────────────────────────────────── /** Einmalig aufgerufen wenn das Spiel startet und dieser Perk für [player] aktiv ist. */ open fun onActivate(player: Player) {} /** Aufgerufen wenn die Runde endet oder der Perk entfernt wird. Tasks hier abbrechen. */ open fun onDeactivate(player: Player) {} // ── Combat Hooks (dispatched by PerkEventDispatcher) ────────────────────── /** [attacker] (dieser Spieler) hat gerade [victim] per Nahkampf getroffen. */ open fun onHitEnemy(attacker: Player, victim: Player, event: EntityDamageByEntityEvent) {} /** Dieser Spieler hat gerade einen Nahkampfhit von [attacker] erhalten. */ open fun onHitByEnemy(victim: Player, attacker: Player, event: EntityDamageByEntityEvent) {} /** Dieser Spieler hat einen anderen Spieler getötet. */ open fun onKillEnemy(killer: Player, victim: Player) {} /** * Aufgerufen bei Umgebungsschaden (Fall, Feuer, etc.) — KEIN Nahkampf. * Wird vom Dispatcher mit HIGH-Priority verarbeitet, damit Featherweight canceln kann. */ open fun onEnvironmentalDamage(player: Player, event: EntityDamageEvent) {} /** * Aufgerufen wenn dieser Spieler via Enderperle teleportiert wurde und * direkt danach Fallschaden erhalten würde (Cause: FALL, nach ENDER_PEARL-Teleport). * * Der [PerkEventDispatcher] unterscheidet diesen Fall vom normalen Fallschaden * über ein internes Tracking-Set und ruft diesen Hook **statt** [onEnvironmentalDamage] auf. * * → Überschreiben um den Schaden zu canceln ([event.isCancelled = true]). */ open fun onEnderPearlDamage(player: Player, event: EntityDamageEvent) {} /** * Aufgerufen **nach** vollständiger Schadensberechnung (MONITOR-Priority), * wenn `event.finalDamage` den endgültigen Abzug nach Rüstung/Modifiern enthält. * `player.health` ist hier noch der Vor-Schaden-Wert. * * Geeignet für Prüfungen der Form: `player.health - event.finalDamage < X` * * Gilt für **jeden** Schadenstyp (Nahkampf UND Umgebung). * Wird nicht aufgerufen wenn das Event bereits gecancelt ist. * * → Primär für [AdrenalinePerk]. */ open fun onPostDamage(player: Player, event: EntityDamageEvent) {} }