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:
@@ -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.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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 ))
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user