Add chat listener and fix ability height/fall logic
Add a ChatListener and register it to render chat with rank prefixes/colors. Enforce a maximum knockback altitude (MAX_KNOCKBACK_HEIGHT_Y) and block height-restricted ability use in Blitzcrank and BlackPanther; surface a localized height_restriction message. Add per-kit noFallDamage tracking for BlackPanther and Trident and cancel fall damage for flagged players in the KitEventDispatcher. Improve hitsRequired resolution: CustomGameSettings will treat a hardcoded 0 as an explicit cooldown-only value (never overridden) and the ActiveAbility getter now only accepts positive override values. Misc fixes: allow throwable items (potions/pearls) to bypass active-item handling, tighten ninja last-hit tracking, fix kit item drop detection in GameStateListener, tweak tablist prefix/suffix handling, and bump TheWorld ability cooldown from 20000ms to 25000ms. Also update language entries and minor formatting/cleanup.
This commit is contained in:
@@ -21,6 +21,7 @@ import club.mcscrims.speedhg.gui.listener.MenuListener
|
|||||||
import club.mcscrims.speedhg.kit.KitManager
|
import club.mcscrims.speedhg.kit.KitManager
|
||||||
import club.mcscrims.speedhg.kit.impl.*
|
import club.mcscrims.speedhg.kit.impl.*
|
||||||
import club.mcscrims.speedhg.kit.listener.KitEventDispatcher
|
import club.mcscrims.speedhg.kit.listener.KitEventDispatcher
|
||||||
|
import club.mcscrims.speedhg.listener.ChatListener
|
||||||
import club.mcscrims.speedhg.listener.ConnectListener
|
import club.mcscrims.speedhg.listener.ConnectListener
|
||||||
import club.mcscrims.speedhg.listener.GameStateListener
|
import club.mcscrims.speedhg.listener.GameStateListener
|
||||||
import club.mcscrims.speedhg.listener.SoupListener
|
import club.mcscrims.speedhg.listener.SoupListener
|
||||||
@@ -288,6 +289,7 @@ class SpeedHG : JavaPlugin() {
|
|||||||
pm.registerEvents(PerkEventDispatcher( this, perkManager ), this )
|
pm.registerEvents(PerkEventDispatcher( this, perkManager ), this )
|
||||||
pm.registerEvents( TeamListener(), this )
|
pm.registerEvents( TeamListener(), this )
|
||||||
pm.registerEvents( lobbyItemManager, this )
|
pm.registerEvents( lobbyItemManager, this )
|
||||||
|
pm.registerEvents(ChatListener( this, VolcanoServerRankProvider() ), this )
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerRecipes()
|
private fun registerRecipes()
|
||||||
|
|||||||
@@ -37,9 +37,22 @@ data class CustomGameSettings(
|
|||||||
/**
|
/**
|
||||||
* Gibt den hitsRequired-Wert für ein Kit zurück.
|
* Gibt den hitsRequired-Wert für ein Kit zurück.
|
||||||
* Priorität: kit-spezifisch > global > hardcoded Default
|
* Priorität: kit-spezifisch > global > hardcoded Default
|
||||||
|
*
|
||||||
|
* Wenn hardcodedDefault == 0, ist das Kit explizit als cooldown-only markiert
|
||||||
|
* und der globale Wert wird niemals angewendet.
|
||||||
*/
|
*/
|
||||||
fun hitsRequired(kitId: String, hardcodedDefault: Int): Int =
|
fun hitsRequired(
|
||||||
kits[kitId]?.hitsRequired ?: globalHitsRequired.takeIf { it >= 0 } ?: hardcodedDefault
|
kitId: String,
|
||||||
|
hardcodedDefault: Int
|
||||||
|
): Int
|
||||||
|
{
|
||||||
|
// A hardcoded 0 means the kit is explicitly cooldown-based — never override it.
|
||||||
|
if ( hardcodedDefault == 0 ) return 0
|
||||||
|
|
||||||
|
return kits[ kitId ]?.hitsRequired?.takeIf { it >= 0 }
|
||||||
|
?: globalHitsRequired.takeIf { it >= 0 }
|
||||||
|
?: hardcodedDefault
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
@@ -88,7 +101,7 @@ data class CustomGameSettings(
|
|||||||
@SerialName("pounce_timeout_ticks") val pounceTimeoutTicks: Long = 30L,
|
@SerialName("pounce_timeout_ticks") val pounceTimeoutTicks: Long = 30L,
|
||||||
|
|
||||||
// TheWorld
|
// TheWorld
|
||||||
@SerialName("tw_ability_cooldown_ms") val abilityCooldownMs: Long = 20_000L,
|
@SerialName("tw_ability_cooldown_ms") val abilityCooldownMs: Long = 25_000L,
|
||||||
@SerialName("tw_shockwave_radius") val shockwaveRadius: Double = 6.0,
|
@SerialName("tw_shockwave_radius") val shockwaveRadius: Double = 6.0,
|
||||||
@SerialName("tw_teleport_range") val teleportRange: Double = 10.0,
|
@SerialName("tw_teleport_range") val teleportRange: Double = 10.0,
|
||||||
@SerialName("tw_max_teleport_charges") val maxTeleportCharges: Int = 3,
|
@SerialName("tw_max_teleport_charges") val maxTeleportCharges: Int = 3,
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ abstract class ActiveAbility(
|
|||||||
private var _hitsRequired: Int = -1
|
private var _hitsRequired: Int = -1
|
||||||
|
|
||||||
val hitsRequired: Int
|
val hitsRequired: Int
|
||||||
get() = _hitsRequired.takeIf { it >= 0 } ?: hardcodedHitsRequired
|
get() = _hitsRequired.takeIf { it > 0 } ?: hardcodedHitsRequired
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Einmalig beim applyKit() aufgerufen – danach ist der Wert gecacht.
|
* Einmalig beim applyKit() aufgerufen – danach ist der Wert gecacht.
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import club.mcscrims.speedhg.kit.Playstyle
|
|||||||
import club.mcscrims.speedhg.kit.ability.AbilityResult
|
import club.mcscrims.speedhg.kit.ability.AbilityResult
|
||||||
import club.mcscrims.speedhg.kit.ability.ActiveAbility
|
import club.mcscrims.speedhg.kit.ability.ActiveAbility
|
||||||
import club.mcscrims.speedhg.kit.ability.PassiveAbility
|
import club.mcscrims.speedhg.kit.ability.PassiveAbility
|
||||||
|
import club.mcscrims.speedhg.kit.listener.KitEventDispatcher.Companion.MAX_KNOCKBACK_HEIGHT_Y
|
||||||
import club.mcscrims.speedhg.util.ItemBuilder
|
import club.mcscrims.speedhg.util.ItemBuilder
|
||||||
import club.mcscrims.speedhg.util.WorldEditUtils
|
import club.mcscrims.speedhg.util.WorldEditUtils
|
||||||
import club.mcscrims.speedhg.util.trans
|
import club.mcscrims.speedhg.util.trans
|
||||||
@@ -61,6 +62,9 @@ class BlackPantherKit : Kit()
|
|||||||
/** Players currently in Fist Mode: UUID → expiry timestamp (ms). */
|
/** Players currently in Fist Mode: UUID → expiry timestamp (ms). */
|
||||||
internal val fistModeExpiry: MutableMap<UUID, Long> = ConcurrentHashMap()
|
internal val fistModeExpiry: MutableMap<UUID, Long> = ConcurrentHashMap()
|
||||||
|
|
||||||
|
/** Players currently in a pounce — fall damage is suppressed on landing. */
|
||||||
|
internal val noFallDamagePlayers: MutableSet<UUID> = ConcurrentHashMap.newKeySet()
|
||||||
|
|
||||||
companion object
|
companion object
|
||||||
{
|
{
|
||||||
private fun override() = SpeedHG.instance.customGameManager.settings.kits.kits["blackpanther"]
|
private fun override() = SpeedHG.instance.customGameManager.settings.kits.kits["blackpanther"]
|
||||||
@@ -106,8 +110,11 @@ class BlackPantherKit : Kit()
|
|||||||
player.inventory.addItem(item)
|
player.inventory.addItem(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRemove(player: Player) {
|
override fun onRemove(
|
||||||
|
player: Player
|
||||||
|
) {
|
||||||
fistModeExpiry.remove( player.uniqueId )
|
fistModeExpiry.remove( player.uniqueId )
|
||||||
|
noFallDamagePlayers.remove( player.uniqueId )
|
||||||
cachedItems.remove( player.uniqueId )?.forEach { player.inventory.remove( it ) }
|
cachedItems.remove( player.uniqueId )?.forEach { player.inventory.remove( it ) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +135,15 @@ class BlackPantherKit : Kit()
|
|||||||
get() = plugin.languageManager.getDefaultRawMessage("kits.blackpanther.items.push.description")
|
get() = plugin.languageManager.getDefaultRawMessage("kits.blackpanther.items.push.description")
|
||||||
override val triggerMaterial = Material.BLACK_DYE
|
override val triggerMaterial = Material.BLACK_DYE
|
||||||
|
|
||||||
override fun execute(player: Player): AbilityResult {
|
override fun execute(
|
||||||
|
player: Player
|
||||||
|
): AbilityResult
|
||||||
|
{
|
||||||
|
if ( player.location.y > MAX_KNOCKBACK_HEIGHT_Y )
|
||||||
|
return AbilityResult.ConditionNotMet(
|
||||||
|
plugin.languageManager.getRawMessage( player, "kits.height_restriction" )
|
||||||
|
)
|
||||||
|
|
||||||
val enemies = player.world
|
val enemies = player.world
|
||||||
.getNearbyEntities(player.location, PUSH_RADIUS, PUSH_RADIUS, PUSH_RADIUS)
|
.getNearbyEntities(player.location, PUSH_RADIUS, PUSH_RADIUS, PUSH_RADIUS)
|
||||||
.filterIsInstance<Player>()
|
.filterIsInstance<Player>()
|
||||||
@@ -236,8 +251,10 @@ class BlackPantherKit : Kit()
|
|||||||
override val description: String
|
override val description: String
|
||||||
get() = plugin.languageManager.getDefaultRawMessage("kits.blackpanther.passive.defensive.description")
|
get() = plugin.languageManager.getDefaultRawMessage("kits.blackpanther.passive.defensive.description")
|
||||||
|
|
||||||
override fun onMove(player: Player, event: PlayerMoveEvent)
|
override fun onMove(
|
||||||
{
|
player: Player,
|
||||||
|
event: PlayerMoveEvent
|
||||||
|
) {
|
||||||
if ( event.to.y >= event.from.y ) return
|
if ( event.to.y >= event.from.y ) return
|
||||||
if ( player.fallDistance < POUNCE_MIN_FALL ) return
|
if ( player.fallDistance < POUNCE_MIN_FALL ) return
|
||||||
|
|
||||||
@@ -258,7 +275,6 @@ class BlackPantherKit : Kit()
|
|||||||
impactLoc.world.playSound(impactLoc, Sound.ENTITY_GENERIC_EXPLODE, 1f, 0.7f)
|
impactLoc.world.playSound(impactLoc, Sound.ENTITY_GENERIC_EXPLODE, 1f, 0.7f)
|
||||||
impactLoc.world.playSound(impactLoc, Sound.ENTITY_IRON_GOLEM_HURT, 1f, 0.5f)
|
impactLoc.world.playSound(impactLoc, Sound.ENTITY_IRON_GOLEM_HURT, 1f, 0.5f)
|
||||||
|
|
||||||
// Async WorldEdit Krater (Vorsicht: Blöcke setzen muss synchron passieren, also normaler Scheduler)
|
|
||||||
Bukkit.getScheduler().runTaskLater(plugin, Runnable {
|
Bukkit.getScheduler().runTaskLater(plugin, Runnable {
|
||||||
WorldEditUtils.createCylinder(
|
WorldEditUtils.createCylinder(
|
||||||
impactLoc.world, impactLoc.clone().subtract(0.0, 1.0, 0.0),
|
impactLoc.world, impactLoc.clone().subtract(0.0, 1.0, 0.0),
|
||||||
@@ -269,7 +285,8 @@ class BlackPantherKit : Kit()
|
|||||||
player.sendActionBar(player.trans("kits.blackpanther.messages.wakanda_impact",
|
player.sendActionBar(player.trans("kits.blackpanther.messages.wakanda_impact",
|
||||||
mapOf("count" to splashTargets.size.toString())))
|
mapOf("count" to splashTargets.size.toString())))
|
||||||
|
|
||||||
// Setze die Fall-Distanz auf 0 zurück, damit der Spieler selbst keinen Vanilla-Fallschaden bekommt
|
// Suppress fall damage for this landing
|
||||||
|
noFallDamagePlayers.add( player.uniqueId )
|
||||||
player.fallDistance = 0f
|
player.fallDistance = 0f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import club.mcscrims.speedhg.kit.Playstyle
|
|||||||
import club.mcscrims.speedhg.kit.ability.AbilityResult
|
import club.mcscrims.speedhg.kit.ability.AbilityResult
|
||||||
import club.mcscrims.speedhg.kit.ability.ActiveAbility
|
import club.mcscrims.speedhg.kit.ability.ActiveAbility
|
||||||
import club.mcscrims.speedhg.kit.ability.PassiveAbility
|
import club.mcscrims.speedhg.kit.ability.PassiveAbility
|
||||||
|
import club.mcscrims.speedhg.kit.listener.KitEventDispatcher
|
||||||
|
import club.mcscrims.speedhg.kit.listener.KitEventDispatcher.Companion.MAX_KNOCKBACK_HEIGHT_Y
|
||||||
import club.mcscrims.speedhg.util.ItemBuilder
|
import club.mcscrims.speedhg.util.ItemBuilder
|
||||||
import club.mcscrims.speedhg.util.trans
|
import club.mcscrims.speedhg.util.trans
|
||||||
import net.kyori.adventure.text.Component
|
import net.kyori.adventure.text.Component
|
||||||
@@ -146,6 +148,12 @@ class BlitzcrankKit : Kit() {
|
|||||||
private fun fireUlt(
|
private fun fireUlt(
|
||||||
caster: Player
|
caster: Player
|
||||||
) {
|
) {
|
||||||
|
if ( caster.location.y > MAX_KNOCKBACK_HEIGHT_Y )
|
||||||
|
{
|
||||||
|
caster.sendActionBar(caster.trans( "kits.height_restriction" ))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
val lastUlt = ultCooldowns[ caster.uniqueId ] ?: 0L
|
val lastUlt = ultCooldowns[ caster.uniqueId ] ?: 0L
|
||||||
|
|
||||||
@@ -220,6 +228,11 @@ class BlitzcrankKit : Kit() {
|
|||||||
|
|
||||||
override fun execute(player: Player): AbilityResult
|
override fun execute(player: Player): AbilityResult
|
||||||
{
|
{
|
||||||
|
if ( player.location.y > MAX_KNOCKBACK_HEIGHT_Y )
|
||||||
|
return AbilityResult.ConditionNotMet(
|
||||||
|
plugin.languageManager.getRawMessage( player, "kits.height_restriction" )
|
||||||
|
)
|
||||||
|
|
||||||
val eyeLoc = player.eyeLocation
|
val eyeLoc = player.eyeLocation
|
||||||
val dir = eyeLoc.direction.normalize()
|
val dir = eyeLoc.direction.normalize()
|
||||||
|
|
||||||
@@ -289,7 +302,15 @@ class BlitzcrankKit : Kit() {
|
|||||||
override val hardcodedHitsRequired = 15
|
override val hardcodedHitsRequired = 15
|
||||||
override val triggerMaterial = Material.PISTON
|
override val triggerMaterial = Material.PISTON
|
||||||
|
|
||||||
override fun execute(player: Player): AbilityResult {
|
override fun execute(
|
||||||
|
player: Player
|
||||||
|
): AbilityResult
|
||||||
|
{
|
||||||
|
if ( player.location.y > MAX_KNOCKBACK_HEIGHT_Y )
|
||||||
|
return AbilityResult.ConditionNotMet(
|
||||||
|
plugin.languageManager.getRawMessage( player, "kits.height_restriction" )
|
||||||
|
)
|
||||||
|
|
||||||
val targets = player.world
|
val targets = player.world
|
||||||
.getNearbyEntities(player.location, STUN_RADIUS, STUN_RADIUS, STUN_RADIUS)
|
.getNearbyEntities(player.location, STUN_RADIUS, STUN_RADIUS, STUN_RADIUS)
|
||||||
.filterIsInstance<Player>()
|
.filterIsInstance<Player>()
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ class TridentKit : Kit() {
|
|||||||
private val diveMonitors: MutableMap<UUID, BukkitTask> = ConcurrentHashMap()
|
private val diveMonitors: MutableMap<UUID, BukkitTask> = ConcurrentHashMap()
|
||||||
private val lastSequenceTime: MutableMap<UUID, Long> = ConcurrentHashMap()
|
private val lastSequenceTime: MutableMap<UUID, Long> = ConcurrentHashMap()
|
||||||
|
|
||||||
|
/** Players who have recently launched a dive and should not receive fall damage. */
|
||||||
|
internal val noFallDamagePlayers: MutableSet<UUID> = ConcurrentHashMap.newKeySet()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val MAX_DIVE_CHARGES = 3
|
const val MAX_DIVE_CHARGES = 3
|
||||||
const val SEQUENCE_COOLDOWN_MS = 25_000L // Cooldown zwischen vollst. Sequenzen
|
const val SEQUENCE_COOLDOWN_MS = 25_000L // Cooldown zwischen vollst. Sequenzen
|
||||||
@@ -129,6 +132,7 @@ class TridentKit : Kit() {
|
|||||||
diveCharges.remove( player.uniqueId )
|
diveCharges.remove( player.uniqueId )
|
||||||
diveMonitors.remove( player.uniqueId )?.cancel()
|
diveMonitors.remove( player.uniqueId )?.cancel()
|
||||||
lastSequenceTime.remove( player.uniqueId )
|
lastSequenceTime.remove( player.uniqueId )
|
||||||
|
noFallDamagePlayers.remove( player.uniqueId )
|
||||||
cachedItems.remove( player.uniqueId )?.forEach { player.inventory.remove( it ) }
|
cachedItems.remove( player.uniqueId )?.forEach { player.inventory.remove( it ) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,6 +252,7 @@ class TridentKit : Kit() {
|
|||||||
else diveCharges[ player.uniqueId ] = charges - 1
|
else diveCharges[ player.uniqueId ] = charges - 1
|
||||||
|
|
||||||
player.velocity = player.velocity.clone().setY( 1.38 )
|
player.velocity = player.velocity.clone().setY( 1.38 )
|
||||||
|
noFallDamagePlayers.add( player.uniqueId )
|
||||||
|
|
||||||
val remaining = diveCharges.getOrDefault( player.uniqueId, 0 )
|
val remaining = diveCharges.getOrDefault( player.uniqueId, 0 )
|
||||||
player.sendActionBar(player.trans( "kits.trident.messages.dive_launched", "charges" to remaining.toString() ))
|
player.sendActionBar(player.trans( "kits.trident.messages.dive_launched", "charges" to remaining.toString() ))
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import club.mcscrims.speedhg.kit.charge.ChargeState
|
|||||||
import club.mcscrims.speedhg.kit.impl.AnchorKit
|
import club.mcscrims.speedhg.kit.impl.AnchorKit
|
||||||
import club.mcscrims.speedhg.kit.impl.BlackPantherKit
|
import club.mcscrims.speedhg.kit.impl.BlackPantherKit
|
||||||
import club.mcscrims.speedhg.kit.impl.IceMageKit
|
import club.mcscrims.speedhg.kit.impl.IceMageKit
|
||||||
|
import club.mcscrims.speedhg.kit.impl.NinjaKit
|
||||||
|
import club.mcscrims.speedhg.kit.impl.TridentKit
|
||||||
import club.mcscrims.speedhg.kit.impl.VenomKit
|
import club.mcscrims.speedhg.kit.impl.VenomKit
|
||||||
import club.mcscrims.speedhg.util.trans
|
import club.mcscrims.speedhg.util.trans
|
||||||
import net.kyori.adventure.text.Component
|
import net.kyori.adventure.text.Component
|
||||||
@@ -26,6 +28,7 @@ import org.bukkit.event.EventPriority
|
|||||||
import org.bukkit.event.Listener
|
import org.bukkit.event.Listener
|
||||||
import org.bukkit.event.block.BlockBreakEvent
|
import org.bukkit.event.block.BlockBreakEvent
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||||
|
import org.bukkit.event.entity.EntityDamageEvent
|
||||||
import org.bukkit.event.entity.EntityDeathEvent
|
import org.bukkit.event.entity.EntityDeathEvent
|
||||||
import org.bukkit.event.entity.EntityExplodeEvent
|
import org.bukkit.event.entity.EntityExplodeEvent
|
||||||
import org.bukkit.event.entity.PlayerDeathEvent
|
import org.bukkit.event.entity.PlayerDeathEvent
|
||||||
@@ -67,6 +70,11 @@ class KitEventDispatcher(
|
|||||||
private val kitManager: KitManager,
|
private val kitManager: KitManager,
|
||||||
) : Listener {
|
) : Listener {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/** Above this Y-level, knockback abilities are disabled to prevent skybasing. */
|
||||||
|
const val MAX_KNOCKBACK_HEIGHT_Y = 100.0
|
||||||
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Hit tracking + charge system + passive combat hook
|
// Hit tracking + charge system + passive combat hook
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
@@ -102,11 +110,19 @@ class KitEventDispatcher(
|
|||||||
sendChargeUpdateActionBar( attacker, currentHits, chargeData.hitsRequired )
|
sendChargeUpdateActionBar( attacker, currentHits, chargeData.hitsRequired )
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── 2. Attacker passive hook ─────────────────────────────────────────
|
// ── 2. Ninja last-hit tracking ───────────────────────────────────────
|
||||||
|
if ( attackerKit is NinjaKit &&
|
||||||
|
attackerPlaystyle == Playstyle.AGGRESSIVE )
|
||||||
|
{
|
||||||
|
attackerKit.lastHitEnemy[ attacker.uniqueId ] =
|
||||||
|
Pair( victim.uniqueId, System.currentTimeMillis() )
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── 3. Attacker passive hook ─────────────────────────────────────────
|
||||||
attackerKit.getPassiveAbility( attackerPlaystyle )
|
attackerKit.getPassiveAbility( attackerPlaystyle )
|
||||||
.onHitEnemy( attacker, victim, event )
|
.onHitEnemy( attacker, victim, event )
|
||||||
|
|
||||||
// ── 3. Victim passive hook ────────────────────────────────────────────
|
// ── 4. Victim passive hook ────────────────────────────────────────────
|
||||||
kitManager.getSelectedKit( victim )
|
kitManager.getSelectedKit( victim )
|
||||||
?.getPassiveAbility(kitManager.getSelectedPlaystyle( victim ))
|
?.getPassiveAbility(kitManager.getSelectedPlaystyle( victim ))
|
||||||
?.onHitByEnemy( victim, attacker, event )
|
?.onHitByEnemy( victim, attacker, event )
|
||||||
@@ -129,7 +145,6 @@ class KitEventDispatcher(
|
|||||||
) {
|
) {
|
||||||
val player = event.player
|
val player = event.player
|
||||||
|
|
||||||
// Only main-hand right-clicks — ignore left-click and off-hand duplicates
|
|
||||||
if ( event.hand != EquipmentSlot.HAND ) return
|
if ( event.hand != EquipmentSlot.HAND ) return
|
||||||
if ( !event.action.isRightClick ) return
|
if ( !event.action.isRightClick ) return
|
||||||
if ( !isIngame() ) return
|
if ( !isIngame() ) return
|
||||||
@@ -144,6 +159,11 @@ class KitEventDispatcher(
|
|||||||
val itemInHand = player.inventory.itemInMainHand
|
val itemInHand = player.inventory.itemInMainHand
|
||||||
val active = kit.getActiveAbility( playstyle )
|
val active = kit.getActiveAbility( playstyle )
|
||||||
|
|
||||||
|
// Allow throwable items (potions, ender pearls, etc.) to pass through
|
||||||
|
if ( itemInHand.type == Material.SPLASH_POTION ||
|
||||||
|
itemInHand.type == Material.LINGERING_POTION ||
|
||||||
|
itemInHand.type == Material.ENDER_PEARL ) return
|
||||||
|
|
||||||
if ( itemInHand.type != active.triggerMaterial ) return
|
if ( itemInHand.type != active.triggerMaterial ) return
|
||||||
|
|
||||||
event.isCancelled = true // prevent vanilla block interaction on ability item
|
event.isCancelled = true // prevent vanilla block interaction on ability item
|
||||||
@@ -392,10 +412,39 @@ class KitEventDispatcher(
|
|||||||
event.droppedExp = 0
|
event.droppedExp = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = false)
|
||||||
|
fun onLeapFallDamage(
|
||||||
|
event: EntityDamageEvent
|
||||||
|
) {
|
||||||
|
if ( event.cause != EntityDamageEvent.DamageCause.FALL ) return
|
||||||
|
if ( !isIngame() ) return
|
||||||
|
|
||||||
|
val player = event.entity as? Player ?: return
|
||||||
|
|
||||||
|
when(val kit = kitManager.getSelectedKit( player ))
|
||||||
|
{
|
||||||
|
is TridentKit ->
|
||||||
|
{
|
||||||
|
if ( kit.noFallDamagePlayers.remove( player.uniqueId ) )
|
||||||
|
event.isCancelled = true
|
||||||
|
}
|
||||||
|
is BlackPantherKit ->
|
||||||
|
{
|
||||||
|
if ( kit.noFallDamagePlayers.remove( player.uniqueId ) )
|
||||||
|
event.isCancelled = true
|
||||||
|
}
|
||||||
|
else -> return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Helpers
|
// Helpers
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
|
private fun isAboveKnockbackHeight(
|
||||||
|
player: Player
|
||||||
|
): Boolean = player.location.y > MAX_KNOCKBACK_HEIGHT_Y
|
||||||
|
|
||||||
private fun changeGladiatorBlock(
|
private fun changeGladiatorBlock(
|
||||||
event: Cancellable,
|
event: Cancellable,
|
||||||
block: Block
|
block: Block
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package club.mcscrims.speedhg.listener
|
||||||
|
|
||||||
|
import club.mcscrims.speedhg.SpeedHG
|
||||||
|
import club.mcscrims.speedhg.scoreboard.ServerRankProvider
|
||||||
|
import io.papermc.paper.event.player.AsyncChatEvent
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage
|
||||||
|
import org.bukkit.event.EventHandler
|
||||||
|
import org.bukkit.event.Listener
|
||||||
|
|
||||||
|
class ChatListener(
|
||||||
|
private val plugin: SpeedHG,
|
||||||
|
private val rankProvider: ServerRankProvider
|
||||||
|
) : Listener {
|
||||||
|
|
||||||
|
private val mm = MiniMessage.miniMessage()
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onAsyncChat(
|
||||||
|
event: AsyncChatEvent
|
||||||
|
) {
|
||||||
|
val player = event.player
|
||||||
|
|
||||||
|
val prefix = rankProvider.getRankPrefix( player )
|
||||||
|
val nameColor = rankProvider.getRankColor( player )
|
||||||
|
|
||||||
|
event.renderer { source, _, message, _ ->
|
||||||
|
val coloredName = mm.deserialize(
|
||||||
|
"${nameColor}${source.name}<reset>"
|
||||||
|
)
|
||||||
|
|
||||||
|
Component.empty()
|
||||||
|
.append( prefix )
|
||||||
|
.append( Component.space() )
|
||||||
|
.append( coloredName )
|
||||||
|
.append(mm.deserialize( "<dark_gray>: <gray>" ))
|
||||||
|
.append(message.colorIfAbsent( NamedTextColor.GRAY ))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,7 +5,6 @@ import club.mcscrims.speedhg.game.GameState
|
|||||||
import club.mcscrims.speedhg.util.sendMsg
|
import club.mcscrims.speedhg.util.sendMsg
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import org.bukkit.Sound
|
import org.bukkit.Sound
|
||||||
import org.bukkit.attribute.Attribute
|
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.event.Event
|
import org.bukkit.event.Event
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.event.EventHandler
|
||||||
@@ -164,10 +163,12 @@ class GameStateListener : Listener {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val kitItems = plugin.kitManager.getSelectedKit( player )?.cachedItems?.get( player.uniqueId ) ?: return
|
val kitItems = plugin.kitManager.getSelectedKit( player )
|
||||||
|
?.cachedItems?.get( player.uniqueId ) ?: return
|
||||||
val item = event.itemDrop.itemStack
|
val item = event.itemDrop.itemStack
|
||||||
|
|
||||||
if (kitItems.contains( item ))
|
val isKitItem = kitItems.any { kitItem -> kitItem.isSimilar( item ) }
|
||||||
|
if ( isKitItem )
|
||||||
{
|
{
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
player.playSound( player.location, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
player.playSound( player.location, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||||
|
|||||||
@@ -234,10 +234,9 @@ class TablistManager(
|
|||||||
team.prefix(rankProvider.getRankPrefix( player ))
|
team.prefix(rankProvider.getRankPrefix( player ))
|
||||||
|
|
||||||
// ── playerListName: farbiger Spielername ───────────────────────────
|
// ── playerListName: farbiger Spielername ───────────────────────────
|
||||||
// Ersetzt den Standard-Anzeigenamen in der Namens-Spalte.
|
// WICHTIG: KEIN <reset> hier. Das <reset> machen wir am Anfang des Suffixes!
|
||||||
// Endergebnis: [PREFIX] [NAME] [SUFFIX]
|
|
||||||
val nameColor = rankProvider.getRankColor( player )
|
val nameColor = rankProvider.getRankColor( player )
|
||||||
player.playerListName(mm.deserialize( "${nameColor}${player.name}<reset>" ))
|
player.playerListName(mm.deserialize( "${nameColor}${player.name}" ))
|
||||||
|
|
||||||
// ── Suffix: SpeedHG-Rang (z. B. "[Gold II]") ──────────────────────
|
// ── Suffix: SpeedHG-Rang (z. B. "[Gold II]") ──────────────────────
|
||||||
team.suffix(buildSpeedHGRankSuffix( player ))
|
team.suffix(buildSpeedHGRankSuffix( player ))
|
||||||
@@ -259,7 +258,9 @@ class TablistManager(
|
|||||||
val games = ( stats?.wins ?: 0 ) + ( stats?.losses ?: 0 )
|
val games = ( stats?.wins ?: 0 ) + ( stats?.losses ?: 0 )
|
||||||
val rankTag = Rank.getFormattedRankTag( score, games )
|
val rankTag = Rank.getFormattedRankTag( score, games )
|
||||||
|
|
||||||
mm.deserialize( " <dark_gray>[<reset>${rankTag}<dark_gray>]</dark_gray>" )
|
// Führendes <reset> stellt sicher, dass die Spielerfarbe nicht in den Suffix blutet
|
||||||
|
// und erzwingt einen Cut, den Bukkit/Paper als neues Suffix-Objekt erkennt.
|
||||||
|
mm.deserialize( "<reset> <dark_gray>[<reset>${rankTag}<dark_gray>]</dark_gray>" )
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Entfernt das Scoreboard-Team des Spielers vollständig. */
|
/** Entfernt das Scoreboard-Team des Spielers vollständig. */
|
||||||
|
|||||||
@@ -307,6 +307,7 @@ perks:
|
|||||||
kits:
|
kits:
|
||||||
needed_hits: '<gold>⚡ Ability: <white><current>/<required> Hits</white></gold>'
|
needed_hits: '<gold>⚡ Ability: <white><current>/<required> Hits</white></gold>'
|
||||||
ability_charged: '<green><bold>⚡ ABILITY READY!</bold></green>'
|
ability_charged: '<green><bold>⚡ ABILITY READY!</bold></green>'
|
||||||
|
height_restriction: '<red>⚠ This ability cannot be used at high altitudes!'
|
||||||
|
|
||||||
backup:
|
backup:
|
||||||
name: '<gradient:gold:#ff841f><bold>Backup</bold></gradient>'
|
name: '<gradient:gold:#ff841f><bold>Backup</bold></gradient>'
|
||||||
@@ -624,8 +625,8 @@ kits:
|
|||||||
name: '<gradient:gold:yellow><bold>Spielo</bold></gradient>'
|
name: '<gradient:gold:yellow><bold>Spielo</bold></gradient>'
|
||||||
lore:
|
lore:
|
||||||
- ' '
|
- ' '
|
||||||
- '<gray>AGGRESSIVE: Gambling at the push of a button</gray>'
|
- 'AGGRESSIVE: Gambling at the push of a button'
|
||||||
- '<gray>DEFENSIVE: Slot machine - no instant death</gray>'
|
- 'DEFENSIVE: Slot machine - no instant death'
|
||||||
items:
|
items:
|
||||||
automat:
|
automat:
|
||||||
name: '<gold><bold>Slot Machine</bold></gold>'
|
name: '<gold><bold>Slot Machine</bold></gold>'
|
||||||
|
|||||||
Reference in New Issue
Block a user