Fix 9 bugs and features

9 identified bugs have been fixed, aswell as the podium where you would not spawn in the middle and missing messages
This commit is contained in:
TDSTOS
2026-04-14 00:23:29 +02:00
parent 445618ffaf
commit 2b875399e8
8 changed files with 225 additions and 82 deletions

View File

@@ -233,9 +233,12 @@ class PodiumManager(
val xOff = COLUMN_X_OFFSET[ entry.placement ] ?: return@forEach val xOff = COLUMN_X_OFFSET[ entry.placement ] ?: return@forEach
val height = COLUMN_HEIGHT[ entry.placement ] ?: return@forEach val height = COLUMN_HEIGHT[ entry.placement ] ?: return@forEach
val standLoc = center.clone() val standLoc = Location(
.add( xOff.toDouble(), height.toDouble(), 0.0 ) center.world,
.apply { yaw = 0f; pitch = 0f } center.blockX + xOff.toDouble() + 0.5, // Block-Mitte X
center.y + height,
center.blockZ.toDouble() + 0.5 // Block-Mitte Z
).apply { yaw = 0f; pitch = 0f }
entry.player.teleport( standLoc ) entry.player.teleport( standLoc )
entry.player.gameMode = GameMode.ADVENTURE entry.player.gameMode = GameMode.ADVENTURE

View File

@@ -129,10 +129,14 @@ class FeastManager(
// State erst im nächsten Tick lesen — Block-Commit braucht einen Tick // State erst im nächsten Tick lesen — Block-Commit braucht einen Tick
Bukkit.getScheduler().runTaskLater( plugin, { -> Bukkit.getScheduler().runTaskLater( plugin, { ->
val chest = chestBlock.state as? Chest ?: return@runTaskLater val freshBlock = world.getBlockAt( cx, platformY + 1, cz )
if ( freshBlock.type != Material.CHEST ) return@runTaskLater
val chest = freshBlock.state as? Chest ?: return@runTaskLater
chest.update( true, false ) // BlockState commiten, bevor Inventar beschrieben wird
fillChestWithLoot( chest ) fillChestWithLoot( chest )
chest.update( true ) }, 2L )
}, 1L )
} }
}, 5L ) }, 5L )
@@ -203,11 +207,12 @@ class FeastManager(
) { ) {
val loot = buildLootTable() val loot = buildLootTable()
val inventory = chest.blockInventory val inventory = chest.blockInventory
val slots = ( 0 until inventory.size ).shuffled() val slots = ( 0 until inventory.size ).shuffled().toMutableList()
loot.forEachIndexed { idx, item -> loot.forEachIndexed { idx, item ->
if ( idx < slots.size ) inventory.setItem(slots[ idx ], item ) if ( idx < slots.size ) inventory.setItem( slots[ idx ], item )
} }
// kein chest.update() nötig — blockInventory ist eine Live-Referenz
} }
/** /**

View File

@@ -7,6 +7,7 @@ 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.kit.listener.KitEventDispatcher.Companion.MAX_KNOCKBACK_HEIGHT_Y
import club.mcscrims.speedhg.util.AbilityUtils
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
@@ -18,6 +19,7 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent
import org.bukkit.event.player.PlayerMoveEvent 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 org.bukkit.util.Vector
import java.util.* import java.util.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@@ -184,11 +186,23 @@ class BlackPantherKit : Kit()
player: Player, player: Player,
playstyle: Playstyle playstyle: Playstyle
) { ) {
if ( playstyle != Playstyle.AGGRESSIVE ) return val item = when( playstyle )
val item = ItemBuilder( Material.BLACK_DYE ) {
.name( aggressiveActive.name ) Playstyle.AGGRESSIVE -> {
.lore(listOf( aggressiveActive.description )) ItemBuilder( Material.BLACK_DYE )
.build() .name( aggressiveActive.name )
.lore(listOf( aggressiveActive.description ))
.build()
}
Playstyle.DEFENSIVE -> {
ItemBuilder( Material.FEATHER )
.name( defensiveActive.name )
.lore(listOf( defensiveActive.description ))
.build()
}
}
cachedItems[ player.uniqueId ] = listOf( item ) cachedItems[ player.uniqueId ] = listOf( item )
player.inventory.addItem( item ) player.inventory.addItem( item )
} }
@@ -230,12 +244,11 @@ class BlackPantherKit : Kit()
plugin.languageManager.getRawMessage( player, "kits.height_restriction" ) plugin.languageManager.getRawMessage( player, "kits.height_restriction" )
) )
// Werte zum Aktivierungszeitpunkt snapshotten val capturedPushRadius = pushRadius
val capturedPushRadius = pushRadius val capturedKnockbackSpeed = pushKnockbackSpeed
val capturedKnockbackSpeed = pushKnockbackSpeed val capturedKnockbackY = pushKnockbackY
val capturedKnockbackY = pushKnockbackY val capturedFistModeDurationMs = fistModeDurationMs
val capturedFistModeDurationMs = fistModeDurationMs val capturedProjectileDelay = projectileDelayTicks
val capturedProjectileDelay = projectileDelayTicks
val enemies = player.world val enemies = player.world
.getNearbyEntities( player.location, capturedPushRadius, capturedPushRadius, capturedPushRadius ) .getNearbyEntities( player.location, capturedPushRadius, capturedPushRadius, capturedPushRadius )
@@ -245,6 +258,18 @@ class BlackPantherKit : Kit()
if ( enemies.isEmpty() ) if ( enemies.isEmpty() )
return AbilityResult.ConditionNotMet( "No enemies within ${capturedPushRadius.toInt()} blocks!" ) return AbilityResult.ConditionNotMet( "No enemies within ${capturedPushRadius.toInt()} blocks!" )
// ── Schockwellen-Partikel am Spieler (Aktivierungs-Burst) ──────────────
player.world.spawnParticle(
Particle.LARGE_SMOKE,
player.location.clone().add( 0.0, 1.0, 0.0 ),
30, 1.0, 0.4, 1.0, 0.08
)
player.world.spawnParticle(
Particle.EXPLOSION,
player.location.clone().add( 0.0, 0.5, 0.0 ),
2, 0.3, 0.2, 0.3, 0.0
)
val pushKey = NamespacedKey( plugin, PUSH_PROJECTILE_KEY ) val pushKey = NamespacedKey( plugin, PUSH_PROJECTILE_KEY )
enemies.forEach { enemy -> enemies.forEach { enemy ->
@@ -255,49 +280,116 @@ class BlackPantherKit : Kit()
.setY( capturedKnockbackY ) .setY( capturedKnockbackY )
enemy.velocity = knockDir enemy.velocity = knockDir
// ── Partikel-Spur von Spieler → Gegner (farbige Dust-Linie) ─────────
AbilityUtils.drawColoredParticleLine(
player.eyeLocation,
enemy.location.clone().add( 0.0, 1.0, 0.0 ),
20,
Color.fromRGB( 10, 10, 10 ) // Schwarz/Vibranium-Dunkel
)
// ── Aufprall-Burst am Gegner ─────────────────────────────────────────
enemy.world.spawnParticle( enemy.world.spawnParticle(
Particle.CRIT, Particle.CRIT,
enemy.location.clone().add( 0.0, 1.0, 0.0 ), enemy.location.clone().add( 0.0, 1.0, 0.0 ),
10, 0.3, 0.3, 0.3, 0.0 20, 0.4, 0.4, 0.4, 0.1
)
enemy.world.spawnParticle(
Particle.LARGE_SMOKE,
enemy.location.clone().add( 0.0, 1.0, 0.0 ),
8, 0.3, 0.3, 0.3, 0.04
) )
Bukkit.getScheduler().runTaskLater( plugin, { -> Bukkit.getScheduler().runTaskLater( plugin, { ->
if ( !player.isOnline ) return@runTaskLater if ( !player.isOnline ) return@runTaskLater
val snowball = player.world.spawn( player.eyeLocation, Snowball::class.java ) val snowball = player.world.spawn( player.eyeLocation, Snowball::class.java )
snowball.shooter = player snowball.shooter = player
val travelDir = enemy.location.toVector()
val travelDir = enemy.location.clone().add( 0.0, 1.0, 0.0 )
.toVector()
.subtract( player.eyeLocation.toVector() ) .subtract( player.eyeLocation.toVector() )
.normalize() .normalize()
.multiply( 1.8 ) .multiply( 1.8 )
snowball.velocity = travelDir snowball.velocity = travelDir
snowball.persistentDataContainer.set( pushKey, PersistentDataType.BYTE, 1 ) snowball.persistentDataContainer.set( pushKey, PersistentDataType.BYTE, 1 )
// ── Partikel-Spur für das Projektil (nachleuchtend) ─────────────
AbilityUtils.drawGenericParticleLine(
player.eyeLocation,
enemy.location.clone().add( 0.0, 1.0, 0.0 ),
15,
Particle.SOUL_FIRE_FLAME
)
}, capturedProjectileDelay ) }, capturedProjectileDelay )
} }
fistModeExpiry[ player.uniqueId ] = System.currentTimeMillis() + capturedFistModeDurationMs fistModeExpiry[ player.uniqueId ] = System.currentTimeMillis() + capturedFistModeDurationMs
player.sendActionBar( player.trans( "kits.blackpanther.messages.fist_mode_active" ) ) player.sendActionBar( player.trans( "kits.blackpanther.messages.fist_mode_active" ) )
player.world.playSound( player.location, Sound.ENTITY_RAVAGER_ROAR, 1f, 1.1f ) player.world.playSound( player.location, Sound.ENTITY_RAVAGER_ROAR, 1f, 1.1f )
player.world.playSound( player.location, Sound.ENTITY_PLAYER_ATTACK_SWEEP, 0.8f, 0.7f ) player.world.playSound( player.location, Sound.ENTITY_PLAYER_ATTACK_SWEEP, 0.8f, 0.7f )
return AbilityResult.Success return AbilityResult.Success
} }
} }
// ========================================================================= // =========================================================================
// DEFENSIVE active no active ability // DEFENSIVE active — Wakanda Leap (neu)
// ========================================================================= // =========================================================================
private class DefensiveActive : ActiveAbility( Playstyle.DEFENSIVE ) private inner class DefensiveActive : ActiveAbility( Playstyle.DEFENSIVE )
{ {
private val plugin get() = SpeedHG.instance
override val kitId: String = "blackpanther" override val kitId: String = "blackpanther"
override val name = "None"
override val description = "None" override val name: String
override val hardcodedHitsRequired: Int = 0 get() = plugin.languageManager.getDefaultRawMessage( "kits.blackpanther.items.leap.name" )
override val triggerMaterial = Material.BARRIER
override val description: String
get() = plugin.languageManager.getDefaultRawMessage( "kits.blackpanther.items.leap.description" )
override val hardcodedHitsRequired: Int = 10
override val triggerMaterial: Material
get() = Material.FEATHER
override fun execute( override fun execute(
player: Player player: Player
) = AbilityResult.Success ): AbilityResult
{
if ( player.location.y > MAX_KNOCKBACK_HEIGHT_Y )
return AbilityResult.ConditionNotMet(
plugin.languageManager.getRawMessage( player, "kits.height_restriction" )
)
// Steil nach oben schleudern — leicht in Blickrichtung geneigt (wie Riptide)
val lookDir = player.location.direction.setY( 0.0 ).normalize()
val launchVec = Vector( lookDir.x * 0.4, 2.6, lookDir.z * 0.4 )
player.velocity = launchVec
// Fallschaden unterdrücken + Spieler als "in der Luft per Ability" markieren
noFallDamagePlayers.add( player.uniqueId )
player.world.playSound( player.location, Sound.ENTITY_RAVAGER_ROAR, 1f, 1.4f )
player.world.playSound( player.location, Sound.ENTITY_PLAYER_ATTACK_SWEEP, 0.8f, 0.6f )
player.world.spawnParticle(
Particle.LARGE_SMOKE,
player.location.clone().add( 0.0, 0.5, 0.0 ),
20, 0.3, 0.2, 0.3, 0.07
)
player.world.spawnParticle(
Particle.CRIT,
player.location.clone().add( 0.0, 1.0, 0.0 ),
12, 0.4, 0.3, 0.4, 0.1
)
player.sendActionBar( player.trans( "kits.blackpanther.messages.wakanda_leap" ) )
return AbilityResult.Success
}
} }
// ========================================================================= // =========================================================================
@@ -340,12 +432,11 @@ class BlackPantherKit : Kit()
} }
// ========================================================================= // =========================================================================
// DEFENSIVE passive Wakanda Forever! (fall-pounce → AOE + crater) // DEFENSIVE passive Wakanda Forever! (Aufprall-AoE nach Ability-Launch)
// ========================================================================= // =========================================================================
private inner class DefensivePassive : PassiveAbility( Playstyle.DEFENSIVE ) private inner class DefensivePassive : PassiveAbility( Playstyle.DEFENSIVE )
{ {
private val plugin get() = SpeedHG.instance private val plugin get() = SpeedHG.instance
override val name: String override val name: String
@@ -357,17 +448,16 @@ class BlackPantherKit : Kit()
player: Player, player: Player,
event: PlayerMoveEvent event: PlayerMoveEvent
) { ) {
// Nur feuern wenn Spieler per Ability in der Luft ist
if ( !noFallDamagePlayers.contains( player.uniqueId ) ) return
// Nur wenn Spieler nach unten bewegt (fällt)
if ( event.to.y >= event.from.y ) return if ( event.to.y >= event.from.y ) return
val capturedPounceMinFall = pounceMinFall
if ( player.fallDistance < capturedPounceMinFall ) return
val blockBelow = event.to.clone().subtract( 0.0, 0.1, 0.0 ).block val blockBelow = event.to.clone().subtract( 0.0, 0.1, 0.0 ).block
if ( !blockBelow.type.isSolid ) return if ( !blockBelow.type.isSolid ) return
// ── Aufprall-AoE ────────────────────────────────────────────────────
val impactLoc = event.to.clone() val impactLoc = event.to.clone()
// Werte zum Aktivierungszeitpunkt snapshotten
val capturedPounceRadius = pounceRadius val capturedPounceRadius = pounceRadius
val capturedPounceDamage = pounceDamage val capturedPounceDamage = pounceDamage
@@ -378,8 +468,10 @@ class BlackPantherKit : Kit()
splashTargets.forEach { it.damage( capturedPounceDamage, player ) } splashTargets.forEach { it.damage( capturedPounceDamage, player ) }
impactLoc.world.spawnParticle( Particle.EXPLOSION, impactLoc, 3, 0.5, 0.5, 0.5, 0.0 ) // ── Partikel & Sounds ────────────────────────────────────────────────
impactLoc.world.spawnParticle( Particle.LARGE_SMOKE, impactLoc, 20, 1.0, 0.5, 1.0, 0.05 ) impactLoc.world.spawnParticle( Particle.EXPLOSION, impactLoc, 3, 0.5, 0.5, 0.5, 0.0 )
impactLoc.world.spawnParticle( Particle.LARGE_SMOKE, impactLoc, 25, 1.2, 0.5, 1.2, 0.06 )
impactLoc.world.spawnParticle( Particle.CRIT, impactLoc, 20, 1.0, 0.3, 1.0, 0.15 )
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 )
@@ -395,7 +487,8 @@ class BlackPantherKit : Kit()
mapOf( "count" to splashTargets.size.toString() ) ) mapOf( "count" to splashTargets.size.toString() ) )
) )
noFallDamagePlayers.add( player.uniqueId ) // Fallschaden wird vom KitEventDispatcher.onLeapFallDamage unterdrückt
// (noFallDamagePlayers.remove() passiert dort, NICHT hier)
player.fallDistance = 0f player.fallDistance = 0f
} }
} }

View File

@@ -169,7 +169,7 @@ class TridentKit : Kit()
val nameKey = if ( playstyle == Playstyle.AGGRESSIVE ) val nameKey = if ( playstyle == Playstyle.AGGRESSIVE )
"kits.trident.items.trident.aggressive.name" "kits.trident.items.trident.aggressive.name"
else else
"kits.trident.item.trident.defensive.name" "kits.trident.items.trident.defensive.name"
val trident = ItemBuilder( Material.TRIDENT ) val trident = ItemBuilder( Material.TRIDENT )
.name( plugin.languageManager.getDefaultRawMessage( nameKey ) ) .name( plugin.languageManager.getDefaultRawMessage( nameKey ) )

View File

@@ -191,8 +191,8 @@ class VenomKit : Kit()
AbilityUtils.createBeam( AbilityUtils.createBeam(
player, player,
player.location, player.eyeLocation, // Startpunkt = Augenpunkt
player.eyeLocation.toVector(), player.eyeLocation.direction, // Richtungsvektor aus Blickrichtung
Particle.DRAGON_BREATH, Particle.DRAGON_BREATH,
7.5, 0.1 7.5, 0.1
) { target -> ) { target ->

View File

@@ -7,6 +7,7 @@ import org.bukkit.Bukkit
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.Sound import org.bukkit.Sound
import org.bukkit.attribute.Attribute import org.bukkit.attribute.Attribute
import org.bukkit.entity.LivingEntity
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
@@ -114,10 +115,16 @@ class GameStateListener : Listener {
return return
} }
// BUG 2 FIX: Kein separater Invis-Whitelist-Block mehr. val isAlwaysPickup = alwaysMaterials.containsKey( block.type )
// Beide States (INVINCIBILITY + INGAME) laufen direkt in pickupBlock — val isInvisOnlyPickup = beforeInvisMaterials.containsKey( block.type )
// Map-Protection (Diamant, Eisen) ist bereits oben abgehandelt.
pickupBlock( event, player ) when {
isAlwaysPickup ->
pickupBlock( event, player )
isInvisOnlyPickup && gameManager.currentState == GameState.INVINCIBILITY ->
pickupBlock( event, player )
}
} }
private fun pickupBlock( private fun pickupBlock(
@@ -135,6 +142,14 @@ class GameStateListener : Listener {
} }
} }
if ( block.type == Material.CACTUS )
{
activeCactusBreaker[ player.uniqueId ] = player
Bukkit.getScheduler().runTask( plugin ) { ->
activeCactusBreaker.remove( player.uniqueId )
}
}
event.isCancelled = true event.isCancelled = true
// BUG 1 FIX: !! entfernt → Elvis mit null-Safe-Fallback auf GENERIC_SOUND. // BUG 1 FIX: !! entfernt → Elvis mit null-Safe-Fallback auf GENERIC_SOUND.
@@ -178,38 +193,54 @@ class GameStateListener : Listener {
* Kettenreaktion-Drops bekommen soll. * Kettenreaktion-Drops bekommen soll.
*/ */
private val activeMushroomBreaker: MutableMap<UUID, Player> = ConcurrentHashMap() private val activeMushroomBreaker: MutableMap<UUID, Player> = ConcurrentHashMap()
private val activeCactusBreaker: MutableMap<UUID, Player> = ConcurrentHashMap()
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false)
fun onBlockPhysics( fun onBlockPhysics(
event: BlockPhysicsEvent event: BlockPhysicsEvent
) { ) {
val block = event.block val block = event.block
if ( block.type != Material.RED_MUSHROOM &&
block.type != Material.BROWN_MUSHROOM ) return
if ( gameManager.currentState != GameState.INVINCIBILITY && if ( gameManager.currentState != GameState.INVINCIBILITY &&
gameManager.currentState != GameState.INGAME ) return gameManager.currentState != GameState.INGAME ) return
// Einen Spieler in der Nähe finden der gerade einen Pilz abbaut // ── Pilze (bestehende Logik) ──────────────────────────────────────────
val harvester = activeMushroomBreaker.values if ( block.type == Material.RED_MUSHROOM ||
.firstOrNull { it.location.distanceSquared( block.location ) <= 25.0 } block.type == Material.BROWN_MUSHROOM )
?: return // Keine aktive Spieleraktion — normales Physik-Event, ignorieren
// Block vor dem Pop einsammeln
event.isCancelled = true
val drops = block.getDrops( harvester.inventory.itemInMainHand, harvester )
if ( !hasInventorySpace( harvester ) )
{ {
drops.forEach { harvester.world.dropItem( block.location, it ) } val harvester = activeMushroomBreaker.values
} .firstOrNull { it.location.distanceSquared( block.location ) <= 25.0 }
else ?: return
{
drops.forEach { harvester.inventory.addItem( it ) } event.isCancelled = true
val drops = block.getDrops( harvester.inventory.itemInMainHand, harvester )
if ( !hasInventorySpace( harvester ) )
drops.forEach { harvester.world.dropItem( block.location, it ) }
else
drops.forEach { harvester.inventory.addItem( it ) }
block.type = Material.AIR
return
} }
block.type = Material.AIR // ── Kakteen (NEU) ─────────────────────────────────────────────────────
if ( block.type == Material.CACTUS )
{
val harvester = activeCactusBreaker.values
.firstOrNull { it.location.distanceSquared( block.location ) <= 25.0 }
?: return
event.isCancelled = true
val drops = block.getDrops( harvester.inventory.itemInMainHand, harvester )
if ( !hasInventorySpace( harvester ) )
drops.forEach { harvester.world.dropItem( block.location, it ) }
else
drops.forEach { harvester.inventory.addItem( it ) }
block.type = Material.AIR
}
} }
@EventHandler @EventHandler
@@ -404,6 +435,9 @@ class GameStateListener : Listener {
event: EntitySpawnEvent event: EntitySpawnEvent
) { ) {
if ( feastStarted ) return if ( feastStarted ) return
// Item-Drops, XP-Orbs, Projekile tc. NICHT blockieren
if ( event.entity !is LivingEntity ) return
if ( event.entity is Player ) return
event.isCancelled = true event.isCancelled = true
} }

View File

@@ -89,21 +89,24 @@ class GourmetPerk : Perk(), Listener {
// ── Soup listener ───────────────────────────────────────────────────────── // ── Soup listener ─────────────────────────────────────────────────────────
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @EventHandler( priority = EventPriority.MONITOR, ignoreCancelled = true )
fun onSoupConsume( fun onSoupConsume(
event: PlayerInteractEvent event: PlayerInteractEvent
) { ) {
// Nur Rechtsklick — verhindert Trigger beim Schlagen/Links-Klick
if ( !event.action.isRightClick ) return
if ( event.hand != EquipmentSlot.HAND ) return if ( event.hand != EquipmentSlot.HAND ) return
val player = event.player val player = event.player
if ( !activePlayers.contains( player.uniqueId ) ) return if ( !activePlayers.contains( player.uniqueId ) ) return
val item = event.item ?: return // Ursprüngliches Item muss MUSHROOM_STEW gewesen sein
if ( item.type != Material.MUSHROOM_STEW ) return val originalItem = event.item ?: return
if ( originalItem.type != Material.MUSHROOM_STEW ) return
// Only fire when the item is actually going to be consumed — i.e. when // Nach SoupListener (HIGHEST) ist der Slot eine Bowl, wenn tatsächlich getrunken
// the player is not at full hunger (vanilla consumption gate). val currentItem = player.inventory.getItem( event.hand!! )
if ( player.foodLevel >= 20 ) return if ( currentItem.type != Material.BOWL ) return
val dur = durationTicks val dur = durationTicks
player.addPotionEffect( PotionEffect( PotionEffectType.REGENERATION, dur, 0, false, true, true ) ) player.addPotionEffect( PotionEffect( PotionEffectType.REGENERATION, dur, 0, false, true, true ) )

View File

@@ -599,29 +599,33 @@ kits:
curse_received: '<red>🔮 You have been cursed by a Voodoo player!</red>' curse_received: '<red>🔮 You have been cursed by a Voodoo player!</red>'
ability_charged: '<yellow>⚡ Ability recharged!</yellow>' ability_charged: '<yellow>⚡ Ability recharged!</yellow>'
# ── Black Panther ───────────────────────────────────────────────────────────── # ── BlackPanther (neue Defensive-Leap Fähigkeit aus vorherigem Fix) ─────────
# FIX: Added clarity that AGGRESSIVE is Push + 12 s Vibranium Fists (6.5 dmg/hit).
# DEFENSIVE Wakanda pounce now mentions 3-block fall requirement and crater.
blackpanther: blackpanther:
name: '<gradient:dark_gray:white><bold>Black Panther</bold></gradient>' # Lore-Zeile für DEF aktualisieren:
lore: lore:
- ' ' - ' '
- '<dark_gray>[AGG]</dark_gray> <gray>Push nearby enemies, then unleash <yellow>6.5 dmg</yellow> fists for <yellow>12 s</yellow>.</gray>' - '<dark_gray>[AGG]</dark_gray> <gray>Push nearby enemies, then unleash <yellow>6.5 dmg</yellow> fists for <yellow>12 s</yellow>.</gray>'
- '<dark_aqua>[DEF]</dark_aqua> <gray>Fall <yellow>3+ blocks</yellow> onto a foe — <red>AOE damage</red> + crater.</gray>' - '<dark_aqua>[DEF]</dark_aqua> <gray>Activate to <yellow>leap skyward</yellow> — land for <red>AOE impact</red> + crater.</gray>'
items: items:
push: push:
name: '<gray>⚡ Vibranium Pulse</gray>' name: '<gray>⚡ Vibranium Pulse</gray>'
description: 'Knock back all nearby enemies and activate 12 s Vibranium Fist Mode' description: 'Knock back all nearby enemies and activate 12 s Vibranium Fist Mode'
# NEU — Leap-Item für Defensive:
leap:
name: '<white>⬆ Wakanda Leap</white>'
description: 'Launch skyward — land on enemies for AOE damage + crater (fall damage disabled)'
passive: passive:
aggressive: aggressive:
name: '<gray>Vibranium Fists</gray>' name: '<gray>Vibranium Fists</gray>'
description: '6.5 bare-hand damage for 12 s after activating Push' description: '6.5 bare-hand damage for 12 s after activating Push'
defensive: defensive:
name: '<white>Wakanda Forever!</white>' name: '<white>Wakanda Forever!</white>'
description: 'Fall from 3+ blocks onto an enemy for AOE damage and a crater impact' description: 'Activate Leap, then land on enemies for AOE damage and a crater'
messages: messages:
fist_mode_active: '<gray>⚡ Vibranium Fists active for <yellow>12 seconds</yellow>!</gray>' fist_mode_active: '<gray>⚡ Vibranium Fists active for <yellow>12 seconds</yellow>!</gray>'
wakanda_impact: '<white>⚡ Wakanda Forever! Hit <yellow><count></yellow> enemy(s)!</white>' wakanda_impact: '<white>⚡ Wakanda Forever! Hit <yellow><count></yellow> enemy(s)!</white>'
# NEU:
wakanda_leap: '<white>⬆ Wakanda Forever — brace for impact!</white>'
ability_charged: '<yellow>⚡ Ability recharged!</yellow>' ability_charged: '<yellow>⚡ Ability recharged!</yellow>'
# ── TheWorld ────────────────────────────────────────────────────────────────── # ── TheWorld ──────────────────────────────────────────────────────────────────
@@ -768,11 +772,12 @@ kits:
name: '<aqua>Trident Parry</aqua>' name: '<aqua>Trident Parry</aqua>'
description: '20% chance to parry melee attacks: launch attacker back with Slowness I' description: '20% chance to parry melee attacks: launch attacker back with Slowness I'
messages: messages:
dive_launched: '<aqua>⚡ Launched! <yellow><charges></yellow> charge(s) remaining.</aqua>' dive_launched: '<aqua>⚡ Launched! Brace for impact!</aqua>'
charges_left: '<aqua>⚡ <yellow><charges></yellow> dive charge(s) left!</aqua>' parry_success: '<aqua>🛡 Parried! Attacker bounced back!</aqua>'
sequence_done: '<gray>Dive sequence complete.</gray>' parried_by_victim: '<red>Your attack was parried!</red>'
parry_success: '<aqua>⚡ Parried!</aqua>' charges_left: '<aqua>⚡ <yellow><charges></yellow> dive charge(s) remaining!</aqua>'
parried_by_victim: '<red>⚡ Your attack was parried!</red>' sequence_done: '<gray>Sequence complete — recharging...</gray>'
ability_charged: '<yellow>⚡ Ability recharged!</yellow>'
# ── Blitzcrank ──────────────────────────────────────────────────────────────── # ── Blitzcrank ────────────────────────────────────────────────────────────────
blitzcrank: blitzcrank: