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.Player
|
||||||
import org.bukkit.entity.Snowball
|
import org.bukkit.entity.Snowball
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||||
|
import org.bukkit.event.player.PlayerMoveEvent
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
import org.bukkit.persistence.PersistentDataType
|
import org.bukkit.persistence.PersistentDataType
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -240,39 +241,41 @@ 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 onHitEnemy(attacker: Player, victim: Player, event: EntityDamageByEntityEvent) {
|
override fun onMove(player: Player, event: PlayerMoveEvent)
|
||||||
if (attacker.fallDistance < POUNCE_MIN_FALL) return
|
{
|
||||||
|
if ( event.to.y >= event.from.y ) return
|
||||||
|
if ( player.fallDistance < POUNCE_MIN_FALL ) return
|
||||||
|
|
||||||
// ── Instant damage to all enemies in splash radius ─────────────────
|
val blockBelow = event.to.clone().subtract( 0.0, 0.1, 0.0 ).block
|
||||||
val splashTargets = victim.world
|
if ( !blockBelow.type.isSolid ) return
|
||||||
.getNearbyEntities(victim.location, POUNCE_RADIUS, POUNCE_RADIUS, POUNCE_RADIUS)
|
|
||||||
|
val impactLoc = event.to.clone()
|
||||||
|
|
||||||
|
val splashTargets = impactLoc.world
|
||||||
|
.getNearbyEntities( impactLoc, POUNCE_RADIUS, POUNCE_RADIUS, POUNCE_RADIUS )
|
||||||
.filterIsInstance<Player>()
|
.filterIsInstance<Player>()
|
||||||
.filter { it != attacker && plugin.gameManager.alivePlayers.contains(it.uniqueId) }
|
.filter { it != player && plugin.gameManager.alivePlayers.contains( it.uniqueId ) }
|
||||||
.onEach { t -> t.damage(POUNCE_DAMAGE, attacker) }
|
|
||||||
|
|
||||||
// Direct victim also receives meteor damage
|
splashTargets.forEach { it.damage( POUNCE_DAMAGE, player ) }
|
||||||
event.damage = POUNCE_DAMAGE
|
|
||||||
|
|
||||||
// ── 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.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_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)
|
||||||
|
|
||||||
// ── Crater (radius 3, hollow = false so the depression looks natural) ─
|
// Async WorldEdit Krater (Vorsicht: Blöcke setzen muss synchron passieren, also normaler Scheduler)
|
||||||
Bukkit.getScheduler().runTaskLater(plugin, { ->
|
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),
|
||||||
3, true, 2, Material.AIR
|
3, true, 2, Material.AIR
|
||||||
)
|
)
|
||||||
}, 2L)
|
}, 2L)
|
||||||
|
|
||||||
attacker.sendActionBar(attacker.trans("kits.blackpanther.messages.wakanda_impact",
|
player.sendActionBar(player.trans("kits.blackpanther.messages.wakanda_impact",
|
||||||
mapOf("count" to (splashTargets.size + 1).toString())))
|
mapOf("count" to splashTargets.size.toString())))
|
||||||
|
|
||||||
// Reset fall distance so a second consecutive pounce requires a real fall
|
// Setze die Fall-Distanz auf 0 zurück, damit der Spieler selbst keinen Vanilla-Fallschaden bekommt
|
||||||
attacker.fallDistance = 0f
|
player.fallDistance = 0f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,11 +101,12 @@ class TheWorldKit : Kit() {
|
|||||||
private val aggressivePassive = NoPassive(Playstyle.AGGRESSIVE)
|
private val aggressivePassive = NoPassive(Playstyle.AGGRESSIVE)
|
||||||
private val defensivePassive = DefensivePassive()
|
private val defensivePassive = DefensivePassive()
|
||||||
|
|
||||||
override fun getActiveAbility(playstyle: Playstyle) = when (playstyle) {
|
override fun getActiveAbility(playstyle: Playstyle): ActiveAbility = when (playstyle) {
|
||||||
Playstyle.AGGRESSIVE -> aggressiveActive
|
Playstyle.AGGRESSIVE -> aggressiveActive
|
||||||
Playstyle.DEFENSIVE -> defensiveActive
|
Playstyle.DEFENSIVE -> defensiveActive
|
||||||
}
|
}
|
||||||
override fun getPassiveAbility(playstyle: Playstyle) = when (playstyle) {
|
|
||||||
|
override fun getPassiveAbility(playstyle: Playstyle): PassiveAbility = when (playstyle) {
|
||||||
Playstyle.AGGRESSIVE -> aggressivePassive
|
Playstyle.AGGRESSIVE -> aggressivePassive
|
||||||
Playstyle.DEFENSIVE -> defensivePassive
|
Playstyle.DEFENSIVE -> defensivePassive
|
||||||
}
|
}
|
||||||
@@ -114,10 +115,12 @@ class TheWorldKit : Kit() {
|
|||||||
|
|
||||||
override fun giveItems(player: Player, playstyle: Playstyle) {
|
override fun giveItems(player: Player, playstyle: Playstyle) {
|
||||||
val active = getActiveAbility(playstyle)
|
val active = getActiveAbility(playstyle)
|
||||||
|
|
||||||
val item = ItemBuilder(Material.CLOCK)
|
val item = ItemBuilder(Material.CLOCK)
|
||||||
.name(active.name)
|
.name(active.name)
|
||||||
.lore(listOf(active.description))
|
.lore(listOf(active.description))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
cachedItems[player.uniqueId] = listOf(item)
|
cachedItems[player.uniqueId] = listOf(item)
|
||||||
player.inventory.addItem(item)
|
player.inventory.addItem(item)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package club.mcscrims.speedhg.listener
|
|||||||
|
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import org.bukkit.attribute.Attribute
|
import org.bukkit.attribute.Attribute
|
||||||
|
import org.bukkit.event.Event
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.event.EventHandler
|
||||||
import org.bukkit.event.EventPriority
|
import org.bukkit.event.EventPriority
|
||||||
import org.bukkit.event.Listener
|
import org.bukkit.event.Listener
|
||||||
@@ -14,7 +15,7 @@ class SoupListener : Listener {
|
|||||||
|
|
||||||
@EventHandler(
|
@EventHandler(
|
||||||
priority = EventPriority.HIGHEST,
|
priority = EventPriority.HIGHEST,
|
||||||
ignoreCancelled = true
|
ignoreCancelled = false
|
||||||
)
|
)
|
||||||
fun onSoup(
|
fun onSoup(
|
||||||
event: PlayerInteractEvent
|
event: PlayerInteractEvent
|
||||||
@@ -25,24 +26,32 @@ class SoupListener : Listener {
|
|||||||
if ( !action.isRightClick )
|
if ( !action.isRightClick )
|
||||||
return
|
return
|
||||||
|
|
||||||
if ( !event.hasItem() ||
|
val item = event.item ?: return
|
||||||
event.material != Material.MUSHROOM_STEW )
|
val hand = event.hand ?: return
|
||||||
|
|
||||||
|
if ( item.type != Material.MUSHROOM_STEW )
|
||||||
return
|
return
|
||||||
|
|
||||||
if ( event.hand == EquipmentSlot.OFF_HAND )
|
event.setUseItemInHand( Event.Result.DENY )
|
||||||
return
|
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.health = ( player.health + 7.0 ).coerceAtMost( maxHealth )
|
||||||
player.inventory.setItemInMainHand(ItemStack( Material.BOWL ))
|
consumed = true
|
||||||
}
|
}
|
||||||
else if ( player.foodLevel < 20 )
|
else if ( player.foodLevel < 20 )
|
||||||
{
|
{
|
||||||
player.foodLevel += 6
|
player.foodLevel = ( player.foodLevel + 6 ).coerceAtMost( 20 )
|
||||||
player.saturation += 7
|
player.saturation = ( player.saturation + 7f ).coerceAtMost( player.foodLevel.toFloat() )
|
||||||
player.inventory.setItemInMainHand(ItemStack( Material.BOWL ))
|
consumed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( consumed )
|
||||||
|
player.inventory.setItem( hand, ItemStack( Material.BOWL ))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user