BlackPanther pounce on move; TheWorld & soup fixes

BlackPantherKit: Replace the old onHitEnemy logic with onMove(PlayerMoveEvent) to detect a landing pounce (checks downward movement, minimum fall, and solid ground). Applies AoE damage to nearby alive players, plays VFX/sounds, spawns a crater asynchronously, and resets the player's fallDistance; also fixes action bar target count and cleans up impact location usage.

TheWorldKit: Add explicit return types for ability getters and minor cleanup in giveItems when building and caching the ability item.

SoupListener: Harden interaction handling by checking event.item and hand, denying vanilla item/block use, using the live maxHealth attribute value, capping health/food/saturation with coerceAtMost, and only replacing the consumed stew with a bowl in the correct hand when actually consumed. Also set EventHandler ignoreCancelled to false to ensure proper handling.
This commit is contained in:
TDSTOS
2026-04-04 20:23:53 +02:00
parent 1f9a43fb89
commit 6141cde0b5
3 changed files with 46 additions and 31 deletions

View File

@@ -15,6 +15,7 @@ import org.bukkit.*
import org.bukkit.entity.Player
import org.bukkit.entity.Snowball
import org.bukkit.event.entity.EntityDamageByEntityEvent
import org.bukkit.event.player.PlayerMoveEvent
import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataType
import java.util.*
@@ -240,39 +241,41 @@ class BlackPantherKit : Kit()
override val description: String
get() = plugin.languageManager.getDefaultRawMessage("kits.blackpanther.passive.defensive.description")
override fun onHitEnemy(attacker: Player, victim: Player, event: EntityDamageByEntityEvent) {
if (attacker.fallDistance < POUNCE_MIN_FALL) return
override fun onMove(player: Player, event: PlayerMoveEvent)
{
if ( event.to.y >= event.from.y ) return
if ( player.fallDistance < POUNCE_MIN_FALL ) return
// ── Instant damage to all enemies in splash radius ─────────────────
val splashTargets = victim.world
.getNearbyEntities(victim.location, POUNCE_RADIUS, POUNCE_RADIUS, POUNCE_RADIUS)
val blockBelow = event.to.clone().subtract( 0.0, 0.1, 0.0 ).block
if ( !blockBelow.type.isSolid ) return
val impactLoc = event.to.clone()
val splashTargets = impactLoc.world
.getNearbyEntities( impactLoc, POUNCE_RADIUS, POUNCE_RADIUS, POUNCE_RADIUS )
.filterIsInstance<Player>()
.filter { it != attacker && plugin.gameManager.alivePlayers.contains(it.uniqueId) }
.onEach { t -> t.damage(POUNCE_DAMAGE, attacker) }
.filter { it != player && plugin.gameManager.alivePlayers.contains( it.uniqueId ) }
// Direct victim also receives meteor damage
event.damage = POUNCE_DAMAGE
splashTargets.forEach { it.damage( POUNCE_DAMAGE, player ) }
// ── Explosion VFX + sound ──────────────────────────────────────────
val impactLoc = attacker.location.clone()
impactLoc.world.spawnParticle(Particle.EXPLOSION, impactLoc, 3, 0.5, 0.5, 0.5, 0.0)
impactLoc.world.spawnParticle(Particle.LARGE_SMOKE, impactLoc, 20, 1.0, 0.5, 1.0, 0.05)
impactLoc.world.playSound(impactLoc, Sound.ENTITY_GENERIC_EXPLODE, 1f, 0.7f)
impactLoc.world.playSound(impactLoc, Sound.ENTITY_IRON_GOLEM_HURT, 1f, 0.5f)
// ── Crater (radius 3, hollow = false so the depression looks natural) ─
Bukkit.getScheduler().runTaskLater(plugin, { ->
// Async WorldEdit Krater (Vorsicht: Blöcke setzen muss synchron passieren, also normaler Scheduler)
Bukkit.getScheduler().runTaskLater(plugin, Runnable {
WorldEditUtils.createCylinder(
impactLoc.world, impactLoc.clone().subtract(0.0, 1.0, 0.0),
3, true, 2, Material.AIR
)
}, 2L)
attacker.sendActionBar(attacker.trans("kits.blackpanther.messages.wakanda_impact",
mapOf("count" to (splashTargets.size + 1).toString())))
player.sendActionBar(player.trans("kits.blackpanther.messages.wakanda_impact",
mapOf("count" to splashTargets.size.toString())))
// Reset fall distance so a second consecutive pounce requires a real fall
attacker.fallDistance = 0f
// Setze die Fall-Distanz auf 0 zurück, damit der Spieler selbst keinen Vanilla-Fallschaden bekommt
player.fallDistance = 0f
}
}

View File

@@ -101,11 +101,12 @@ class TheWorldKit : Kit() {
private val aggressivePassive = NoPassive(Playstyle.AGGRESSIVE)
private val defensivePassive = DefensivePassive()
override fun getActiveAbility(playstyle: Playstyle) = when (playstyle) {
override fun getActiveAbility(playstyle: Playstyle): ActiveAbility = when (playstyle) {
Playstyle.AGGRESSIVE -> aggressiveActive
Playstyle.DEFENSIVE -> defensiveActive
}
override fun getPassiveAbility(playstyle: Playstyle) = when (playstyle) {
override fun getPassiveAbility(playstyle: Playstyle): PassiveAbility = when (playstyle) {
Playstyle.AGGRESSIVE -> aggressivePassive
Playstyle.DEFENSIVE -> defensivePassive
}
@@ -114,10 +115,12 @@ class TheWorldKit : Kit() {
override fun giveItems(player: Player, playstyle: Playstyle) {
val active = getActiveAbility(playstyle)
val item = ItemBuilder(Material.CLOCK)
.name(active.name)
.lore(listOf(active.description))
.build()
cachedItems[player.uniqueId] = listOf(item)
player.inventory.addItem(item)
}

View File

@@ -2,6 +2,7 @@ package club.mcscrims.speedhg.listener
import org.bukkit.Material
import org.bukkit.attribute.Attribute
import org.bukkit.event.Event
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
@@ -14,7 +15,7 @@ class SoupListener : Listener {
@EventHandler(
priority = EventPriority.HIGHEST,
ignoreCancelled = true
ignoreCancelled = false
)
fun onSoup(
event: PlayerInteractEvent
@@ -25,24 +26,32 @@ class SoupListener : Listener {
if ( !action.isRightClick )
return
if ( !event.hasItem() ||
event.material != Material.MUSHROOM_STEW )
val item = event.item ?: return
val hand = event.hand ?: return
if ( item.type != Material.MUSHROOM_STEW )
return
if ( event.hand == EquipmentSlot.OFF_HAND )
return
event.setUseItemInHand( Event.Result.DENY )
event.setUseInteractedBlock( Event.Result.DENY )
if ( player.health < requireNotNull(player.getAttribute( Attribute.GENERIC_MAX_HEALTH )?.defaultValue ))
val maxHealth = player.getAttribute( Attribute.GENERIC_MAX_HEALTH )?.value ?: 20.0
var consumed = false
if ( player.health < maxHealth )
{
player.health = min( player.health + 7, requireNotNull(player.getAttribute( Attribute.GENERIC_MAX_HEALTH )?.defaultValue ))
player.inventory.setItemInMainHand(ItemStack( Material.BOWL ))
player.health = ( player.health + 7.0 ).coerceAtMost( maxHealth )
consumed = true
}
else if ( player.foodLevel < 20 )
{
player.foodLevel += 6
player.saturation += 7
player.inventory.setItemInMainHand(ItemStack( Material.BOWL ))
player.foodLevel = ( player.foodLevel + 6 ).coerceAtMost( 20 )
player.saturation = ( player.saturation + 7f ).coerceAtMost( player.foodLevel.toFloat() )
consumed = true
}
if ( consumed )
player.inventory.setItem( hand, ItemStack( Material.BOWL ))
}
}