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:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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 )
|
{
|
||||||
|
Playstyle.AGGRESSIVE -> {
|
||||||
|
ItemBuilder( Material.BLACK_DYE )
|
||||||
.name( aggressiveActive.name )
|
.name( aggressiveActive.name )
|
||||||
.lore(listOf( aggressiveActive.description ))
|
.lore(listOf( aggressiveActive.description ))
|
||||||
.build()
|
.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,7 +244,6 @@ 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
|
||||||
@@ -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,22 +280,48 @@ 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 )
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,22 +333,63 @@ class BlackPantherKit : Kit()
|
|||||||
|
|
||||||
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 ) }
|
||||||
|
|
||||||
|
// ── Partikel & Sounds ────────────────────────────────────────────────
|
||||||
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, 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 ) )
|
||||||
|
|||||||
@@ -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 ->
|
||||||
|
|||||||
@@ -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.
|
|
||||||
|
when {
|
||||||
|
isAlwaysPickup ->
|
||||||
pickupBlock( event, player )
|
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) ──────────────────────────────────────────
|
||||||
|
if ( block.type == Material.RED_MUSHROOM ||
|
||||||
|
block.type == Material.BROWN_MUSHROOM )
|
||||||
|
{
|
||||||
val harvester = activeMushroomBreaker.values
|
val harvester = activeMushroomBreaker.values
|
||||||
.firstOrNull { it.location.distanceSquared( block.location ) <= 25.0 }
|
.firstOrNull { it.location.distanceSquared( block.location ) <= 25.0 }
|
||||||
?: return // Keine aktive Spieleraktion — normales Physik-Event, ignorieren
|
?: return
|
||||||
|
|
||||||
// Block vor dem Pop einsammeln
|
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
|
|
||||||
val drops = block.getDrops( harvester.inventory.itemInMainHand, harvester )
|
val drops = block.getDrops( harvester.inventory.itemInMainHand, harvester )
|
||||||
|
|
||||||
if ( !hasInventorySpace( harvester ) )
|
if ( !hasInventorySpace( harvester ) )
|
||||||
{
|
|
||||||
drops.forEach { harvester.world.dropItem( block.location, it ) }
|
drops.forEach { harvester.world.dropItem( block.location, it ) }
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
drops.forEach { harvester.inventory.addItem( it ) }
|
drops.forEach { harvester.inventory.addItem( it ) }
|
||||||
}
|
|
||||||
|
|
||||||
block.type = Material.AIR
|
block.type = Material.AIR
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 ) )
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user