|
|
|
|
@@ -2,6 +2,7 @@ package club.mcscrims.speedhg.perk.impl
|
|
|
|
|
|
|
|
|
|
import club.mcscrims.speedhg.SpeedHG
|
|
|
|
|
import club.mcscrims.speedhg.game.GameState
|
|
|
|
|
import club.mcscrims.speedhg.kit.impl.SpieloKit
|
|
|
|
|
import club.mcscrims.speedhg.perk.Perk
|
|
|
|
|
import net.kyori.adventure.text.Component
|
|
|
|
|
import net.kyori.adventure.text.minimessage.MiniMessage
|
|
|
|
|
@@ -16,12 +17,21 @@ import java.util.concurrent.ConcurrentHashMap
|
|
|
|
|
/**
|
|
|
|
|
* ## Orakel
|
|
|
|
|
*
|
|
|
|
|
* Zeigt das Kit und die Entfernung des nächsten lebenden Gegners per Actionbar an,
|
|
|
|
|
* sobald der Träger **schleicht** oder **einen Kompass hält**.
|
|
|
|
|
* Zeigt das Kit, den Namen und die **Entfernung in Blöcken** zum nächsten lebenden Gegner
|
|
|
|
|
* per Actionbar an, sobald der Träger **schleicht** oder **einen Kompass hält**.
|
|
|
|
|
*
|
|
|
|
|
* **Spielo-Synergie (Platzhalter):** Wenn der Träger das "spielo"-Kit besitzt,
|
|
|
|
|
* wird ein Hinweis auf das nächste Gamble-Ergebnis angezeigt. Logik muss beim
|
|
|
|
|
* Implementieren des Spielo-Kits befüllt werden.
|
|
|
|
|
* ## Spielo-Synergie
|
|
|
|
|
*
|
|
|
|
|
* Wenn der Träger das `spielo`-Kit besitzt, wird ein zusätzlicher Gamble-Status-Hinweis
|
|
|
|
|
* an die Actionbar angehängt:
|
|
|
|
|
*
|
|
|
|
|
* | Zustand | Anzeige |
|
|
|
|
|
* |--------------------------------|--------------------------------|
|
|
|
|
|
* | Animation läuft gerade | `⚙ Gambling…` (gelb) |
|
|
|
|
|
* | Bereit (kein Cooldown aktiv) | `🎲 Ready` (grün) |
|
|
|
|
|
* | Cooldown läuft noch | `⏳ Cooldown` (dunkelgrau) |
|
|
|
|
|
*
|
|
|
|
|
* Der Cooldown-State wird über `activeCooldowns` im [SpieloKit] ausgelesen.
|
|
|
|
|
*/
|
|
|
|
|
class OraclePerk : Perk() {
|
|
|
|
|
|
|
|
|
|
@@ -30,76 +40,112 @@ class OraclePerk : Perk() {
|
|
|
|
|
|
|
|
|
|
override val id = "oracle"
|
|
|
|
|
override val displayName: Component
|
|
|
|
|
get() = plugin.languageManager.getDefaultComponent("perks.oracle.name", mapOf())
|
|
|
|
|
get() = plugin.languageManager.getDefaultComponent( "perks.oracle.name", mapOf() )
|
|
|
|
|
override val lore: List<String>
|
|
|
|
|
get() = plugin.languageManager.getDefaultRawMessageList("perks.oracle.lore")
|
|
|
|
|
get() = plugin.languageManager.getDefaultRawMessageList( "perks.oracle.lore" )
|
|
|
|
|
override val icon = Material.SPYGLASS
|
|
|
|
|
|
|
|
|
|
/** Laufende Tracker-Tasks pro Spieler. */
|
|
|
|
|
private val trackerTasks = ConcurrentHashMap<UUID, BukkitTask>()
|
|
|
|
|
|
|
|
|
|
override fun onActivate(player: Player) {
|
|
|
|
|
override fun onActivate(
|
|
|
|
|
player: Player
|
|
|
|
|
) {
|
|
|
|
|
val task = object : BukkitRunnable() {
|
|
|
|
|
override fun run() {
|
|
|
|
|
if (!player.isOnline) { cancel(); return }
|
|
|
|
|
if ( !player.isOnline ) { cancel(); return }
|
|
|
|
|
|
|
|
|
|
// Nur während aktiver Spielphasen anzeigen
|
|
|
|
|
val state = plugin.gameManager.currentState
|
|
|
|
|
if (state != GameState.INGAME && state != GameState.INVINCIBILITY) return
|
|
|
|
|
if ( state != GameState.INGAME && state != GameState.INVINCIBILITY ) return
|
|
|
|
|
|
|
|
|
|
// Träger muss selbst noch leben
|
|
|
|
|
if (!plugin.gameManager.alivePlayers.contains(player.uniqueId)) return
|
|
|
|
|
if ( !plugin.gameManager.alivePlayers.contains( player.uniqueId ) ) return
|
|
|
|
|
|
|
|
|
|
// Nur anzeigen wenn Bedingung erfüllt
|
|
|
|
|
val isHoldingCompass = player.inventory.itemInMainHand.type == Material.COMPASS
|
|
|
|
|
if (!isHoldingCompass && !player.isSneaking) return
|
|
|
|
|
if ( !isHoldingCompass && !player.isSneaking ) return
|
|
|
|
|
|
|
|
|
|
val nearest = findNearestEnemy(player) ?: return
|
|
|
|
|
player.sendActionBar(buildTrackerComponent(player, nearest))
|
|
|
|
|
val nearest = findNearestEnemy( player ) ?: return
|
|
|
|
|
player.sendActionBar( buildTrackerComponent( player, nearest ) )
|
|
|
|
|
}
|
|
|
|
|
}.runTaskTimer(plugin, 0L, 10L) // Refresh alle 0.5 Sekunden
|
|
|
|
|
}.runTaskTimer( plugin, 0L, 10L )
|
|
|
|
|
|
|
|
|
|
trackerTasks[player.uniqueId] = task
|
|
|
|
|
trackerTasks[ player.uniqueId ] = task
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onDeactivate(player: Player) {
|
|
|
|
|
trackerTasks.remove(player.uniqueId)?.cancel()
|
|
|
|
|
override fun onDeactivate(
|
|
|
|
|
player: Player
|
|
|
|
|
) {
|
|
|
|
|
trackerTasks.remove( player.uniqueId )?.cancel()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Intern ────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
private fun findNearestEnemy(player: Player): Player? =
|
|
|
|
|
private fun findNearestEnemy(
|
|
|
|
|
player: Player
|
|
|
|
|
): Player? =
|
|
|
|
|
plugin.gameManager.alivePlayers
|
|
|
|
|
.asSequence()
|
|
|
|
|
.filter { it != player.uniqueId }
|
|
|
|
|
.mapNotNull { plugin.server.getPlayer(it) }
|
|
|
|
|
.filter { !plugin.perkManager.isGhost(it) }
|
|
|
|
|
.mapNotNull { plugin.server.getPlayer( it ) }
|
|
|
|
|
.filter { !plugin.perkManager.isGhost( it ) }
|
|
|
|
|
.filter { !plugin.presetTeamManager.areInSameTeam( player, it ) }
|
|
|
|
|
.minByOrNull { it.location.distanceSquared(player.location) }
|
|
|
|
|
.minByOrNull { it.location.distanceSquared( player.location ) }
|
|
|
|
|
|
|
|
|
|
private fun buildTrackerComponent(player: Player, nearest: Player): Component {
|
|
|
|
|
val distance = player.location.distance(nearest.location).toInt()
|
|
|
|
|
val kitDisplay = plugin.kitManager.getSelectedKit(nearest)?.displayName
|
|
|
|
|
?: mm.deserialize("<gray>???")
|
|
|
|
|
private fun buildTrackerComponent(
|
|
|
|
|
player: Player,
|
|
|
|
|
nearest: Player
|
|
|
|
|
): Component
|
|
|
|
|
{
|
|
|
|
|
val distance = player.location.distance( nearest.location ).toInt()
|
|
|
|
|
val kitDisplay = plugin.kitManager.getSelectedKit( nearest )?.displayName
|
|
|
|
|
?: mm.deserialize( "<gray>???" )
|
|
|
|
|
|
|
|
|
|
val base = mm.deserialize(
|
|
|
|
|
"<gold>⚲ <yellow><name></yellow> <dark_gray>·</dark_gray> " +
|
|
|
|
|
"<white>Kit: </white><kit><dark_gray> · </dark_gray><yellow><distance>m</yellow>",
|
|
|
|
|
Placeholder.unparsed("name", nearest.name),
|
|
|
|
|
Placeholder.component("kit", kitDisplay),
|
|
|
|
|
Placeholder.unparsed("distance", distance.toString())
|
|
|
|
|
"<gold>⚲ <yellow><n></yellow> <dark_gray>·</dark_gray> " +
|
|
|
|
|
"<white>Kit: </white><kit>" +
|
|
|
|
|
"<dark_gray> · </dark_gray><yellow><distance> blocks</yellow>",
|
|
|
|
|
Placeholder.unparsed( "name", nearest.name ),
|
|
|
|
|
Placeholder.component( "kit", kitDisplay ),
|
|
|
|
|
Placeholder.unparsed( "distance", distance.toString() )
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// ── Spielo-Synergie (Platzhalter) ─────────────────────────────────
|
|
|
|
|
val playerKit = plugin.kitManager.getSelectedKit(player)
|
|
|
|
|
if (playerKit?.id != "spielo") return base
|
|
|
|
|
// ── Spielo-Synergie ────────────────────────────────────────────────
|
|
|
|
|
val playerKit = plugin.kitManager.getSelectedKit( player )
|
|
|
|
|
if ( playerKit?.id != "spielo" ) return base
|
|
|
|
|
|
|
|
|
|
// TODO: Mit echter Spielo-Logik ersetzen sobald das Kit existiert.
|
|
|
|
|
// Temporär: alterniert sekündlich als visueller Platzhalter.
|
|
|
|
|
val isGoodGamble = (System.currentTimeMillis() / 3_000L) % 2 == 0L
|
|
|
|
|
val hint = if (isGoodGamble) mm.deserialize(" <green>⬆ Good Gamble")
|
|
|
|
|
else mm.deserialize(" <red>⬇ Bad Gamble")
|
|
|
|
|
val spieloKit = playerKit as? SpieloKit ?: return base
|
|
|
|
|
val hint = buildSpieloHint( player, spieloKit )
|
|
|
|
|
|
|
|
|
|
return base.append(hint)
|
|
|
|
|
return base.append( hint )
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Ermittelt den aktuellen Gamble-Status des Spielers und gibt den passenden
|
|
|
|
|
* Actionbar-Anhang zurück.
|
|
|
|
|
*
|
|
|
|
|
* | Zustand | Rückgabe |
|
|
|
|
|
* |-----------------------|----------------------------|
|
|
|
|
|
* | Animation läuft | ` ⚙ Gambling…` (gelb) |
|
|
|
|
|
* | Cooldown aktiv | ` ⏳ Cooldown` (dunkelgrau) |
|
|
|
|
|
* | Bereit | ` 🎲 Ready` (grün) |
|
|
|
|
|
*/
|
|
|
|
|
private fun buildSpieloHint(
|
|
|
|
|
player: Player,
|
|
|
|
|
spieloKit: SpieloKit
|
|
|
|
|
): Component
|
|
|
|
|
{
|
|
|
|
|
if ( spieloKit.gamblingPlayers.contains( player.uniqueId ) )
|
|
|
|
|
return mm.deserialize( " <yellow>⚙ Gambling…" )
|
|
|
|
|
|
|
|
|
|
val lastUse = spieloKit.activeCooldowns[ player.uniqueId ] ?: 0L
|
|
|
|
|
val cooldownMs = SpieloKit.DEFAULT_ACTIVE_COOLDOWN_MS
|
|
|
|
|
val onCooldown = System.currentTimeMillis() - lastUse < cooldownMs
|
|
|
|
|
|
|
|
|
|
return if ( onCooldown )
|
|
|
|
|
mm.deserialize( " <dark_gray>⏳ Cooldown" )
|
|
|
|
|
else
|
|
|
|
|
mm.deserialize( " <green>🎲 Ready" )
|
|
|
|
|
}
|
|
|
|
|
}
|