Files
GameModes-SpeedHG/src/main/kotlin/club/mcscrims/speedhg/perk/Perk.kt
TDSTOS 1c6b229ad8 Add Anchor, Puppet, Tesla kits and perks
Introduce three new kits (Anchor, Puppet, Tesla) and multiple perks, plus related plumbing and behavior changes. Key changes:

- Added kit implementations: AnchorKit (summon iron-golem anchor, knockback resistance/radius effects), PuppetKit (life-drain / fear abilities), TeslaKit (lightning active + passive knockback/fire aura).
- Register new kits and register new perks in SpeedHG startup.
- Added new perks: AdrenalinePerk (post-damage speed proc with cooldown), EnderbluePerk (ender-pearl fall damage handling), Ghost, Pyromaniac, Scavenger (and updated OraclePerk/PerkEventDispatcher usage).
- Extended Perk API (Perk.kt) with onEnderPearlDamage and onPostDamage hooks to support specialized damage handling and post-damage checks.
- PerkManager.isGhost added for checking Ghost perk selection and used to exclude ghost players from targeting/compass logic.
- GameManager.updateCompass now excludes ghost-perk players when computing compass targets.
- Updated PerkEventDispatcher and OraclePerk to integrate new hooks and behaviors.
- Minor language additions in en_US.yml to support new kits/perks.

These changes add new gameplay mechanics and ensure correct event dispatching for pearl/fall/post-damage cases and ghost invisibility to game tracking.
2026-04-08 02:59:32 +02:00

85 lines
3.5 KiB
Kotlin

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.<id>.*` 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<String>
/** 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) {}
}