0% found this document useful (0 votes)
6 views21 pages

Oath System for Minecraft Plugin

The document is a Kotlin class for a Minecraft plugin called Oathsmpv2, which implements various gameplay mechanics related to 'Oaths' and 'Oath Crystals'. It includes features such as giving players random Oaths, handling cooldowns for Oath abilities, and managing player inventory with respect to Oaths. The plugin also includes event listeners for player interactions, deaths, and respawns to enhance the gameplay experience.

Uploaded by

offcialkano
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views21 pages

Oath System for Minecraft Plugin

The document is a Kotlin class for a Minecraft plugin called Oathsmpv2, which implements various gameplay mechanics related to 'Oaths' and 'Oath Crystals'. It includes features such as giving players random Oaths, handling cooldowns for Oath abilities, and managing player inventory with respect to Oaths. The plugin also includes event listeners for player interactions, deaths, and respawns to enhance the gameplay experience.

Uploaded by

offcialkano
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

package [Link].

oathsmpv2

import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link].*
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link].*
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]

class Oathsmpv2 : JavaPlugin(), Listener {

companion object {
private const val PDC_OATH_KEY = "oath_id"
private const val PDC_CRYSTAL = "is_oath_crystal"

// damage constants (true damage)


private const val PRIMARY_TRUE_DAMAGE = 2.0 // 1 heart
private const val SECONDARY_TRUE_DAMAGE = 5.0 // 2.5 hearts
}

private lateinit var keyOath: NamespacedKey


private lateinit var keyCrystal: NamespacedKey

// Per-player, per-power cooldowns: playerUUID -> (abilityKey -> cooldown end


epoch millis)
private val cooldownsPerPower: MutableMap<UUID, MutableMap<String, Long>> =
HashMap()
// HUDs
private val hudCooldowns: MutableMap<UUID, MutableMap<String, Int>> = HashMap()

// persistent item restore on respawn


private val toRestoreOnRespawn: MutableMap<UUID, ItemStack> = HashMap()

// temp blocks placed for abilities -> revert later: playerUUID -> list of
(Location, originalMaterial)
private val tempPlacedBlocks: MutableMap<UUID, MutableList<Pair<Location,
Material>>> = HashMap()

override fun onEnable() {


keyOath = NamespacedKey(this, PDC_OATH_KEY)
keyCrystal = NamespacedKey(this, PDC_CRYSTAL)

[Link](this, this)
[Link]("giveoath")?.setExecutor(GiveOathCommand(this))

createRecipes()
[Link]("Oathsmpv2 enabled.")
}

override fun onDisable() {


// revert any temporary blocks
for ((_, list) in tempPlacedBlocks) {
for ((loc, mat) in list) {
try { [Link] = mat } catch (_: Exception) {}
}
}
[Link]("Oathsmpv2 disabled.")
}

// -------------------------
// Recipes / Items
// -------------------------
private fun createRecipes() {
val crystal = makeOathCrystal()
val key = NamespacedKey(this, "oath_crystal_recipe")
val recipe = ShapedRecipe(key, crystal)
[Link](" R ", "RNR", " R ")
[Link]('R', Material.NETHER_STAR)
[Link]('N', Material.NETHERITE_INGOT)
[Link](recipe)
}

fun makeOathItem(oath: Oath): ItemStack {


val item = ItemStack(Material.NETHER_STAR)
val meta = [Link]!!
[Link]("${[Link]}${[Link]}")
val lore = mutableListOf<String>()
[Link]([Link])
[Link]("${[Link]}Oath: ${[Link]}")
[Link] = lore
[Link](keyOath, [Link],
[Link])
[Link] = meta
return item
}
fun makeOathCrystal(): ItemStack {
val item = ItemStack(Material.END_CRYSTAL)
val meta = [Link]!!
[Link]("${[Link]}Oath Crystal")
[Link] = listOf("${[Link]}Right-click to roll a random Oath.")
[Link](keyCrystal, [Link],
[Link]())
[Link] = meta
return item
}

private fun isOath(item: ItemStack?): Boolean {


if (item == null || ![Link]()) return false
val pdc = [Link]!!.persistentDataContainer
return [Link](keyOath, [Link])
}

private fun isCrystal(item: ItemStack?): Boolean {


if (item == null || ![Link]()) return false
val pdc = [Link]!!.persistentDataContainer
return [Link](keyCrystal, [Link])
}

private fun playerHasOath(player: Player): Boolean {


return [Link] { isOath(it) }
}

fun giveOathToPlayer(player: Player, oath: Oath, replace: Boolean = false):


Boolean {
val existing = [Link] { isOath(it) }
if (existing != null && !replace) {
[Link]("${[Link]}You already have an Oath equipped.
You may only hold one.")
return false
}
if (existing != null && replace) {
[Link](existing)
[Link]("${[Link]}Your previous Oath fades away...")
}
val item = makeOathItem(oath)
[Link](item)
[Link]("${[Link]}You received the Oath: $
{[Link]}")
return true
}

fun giveRandomOath(player: Player): Boolean {


val oath = [Link]().random()
return giveOathToPlayer(player, oath)
}

// -------------------------
// Inventory guards
// -------------------------
@EventHandler
fun onInventoryClick(ev: InventoryClickEvent) {
val cursor = [Link]
val current = [Link]
if (isOath(cursor) || isOath(current)) {
val invType = [Link]
if (invType != [Link]) {
[Link] = true
([Link] as? Player)?.sendMessage("${[Link]}Oaths
cannot be placed in containers.")
}
}
}

// -------------------------
// Interaction: crystal & oath use
// -------------------------
@EventHandler
fun onPlayerInteract(ev: PlayerInteractEvent) {
val player = [Link]
if ([Link] != [Link]) return
val item = [Link]
if (isCrystal(item) && ([Link] == Action.RIGHT_CLICK_AIR || [Link] ==
Action.RIGHT_CLICK_BLOCK)) {
[Link] = true
if ([Link] > 1) [Link] = [Link] - 1 else
[Link](null)
startCrystalRoll(player)
return
}
if (isOath(item) && ([Link] == Action.RIGHT_CLICK_AIR || [Link] ==
Action.RIGHT_CLICK_BLOCK)) {
[Link] = true
val id = [Link]?.persistentDataContainer?.get(keyOath,
[Link]) ?: return
val oath = [Link](id) ?: return
val isSecondary = [Link]
handleOathUse(player, oath, isSecondary)
}
}

// -------------------------
// Death / Respawn persistence
// -------------------------
@EventHandler
fun onPlayerDeath(ev: PlayerDeathEvent) {
val player = [Link]
val items = [Link]()
val oathItems = [Link] { isOath(it) }
if ([Link]()) {
[Link](oathItems)
toRestoreOnRespawn[[Link]] = [Link]()
}
}

@EventHandler
fun onPlayerRespawn(ev: PlayerRespawnEvent) {
val pid = [Link]
val item = [Link](pid) ?: return
object : BukkitRunnable() {
override fun run() {
[Link](item)
[Link]("${[Link]}Your Oath has been
returned.")
}
}.runTaskLater(this, 2L)
}

// first join
@EventHandler
fun onPlayerJoin(ev: PlayerJoinEvent) {
val player = [Link]
[Link]().runTaskLater(this, Runnable {
if (!playerHasOath(player)) {
giveRandomOath(player)
[Link]("${[Link]}You were given a random Oath
on first join.")
}
}, 20L)
}

// -------------------------
// Crystal roll (explosive cinematic)
// -------------------------
fun startCrystalRoll(player: Player) {
val durationTicks = 80 // 4s
val names = [Link]().map { [Link] }
[Link](PotionEffect([Link],
durationTicks / 2, 1))

object : BukkitRunnable() {
var t = 0
override fun run() {
if (![Link] || [Link]) { cancel(); return }
val loc = [Link]().add(0.0, 1.2, 0.0)

// Phase timings: 0-20 small spiral, 20-60 build sphere, 60-80


explode
if (t < 20) {
// tight colored spiral
val points = 20
for (i in 0 until points) {
val angle = (i + t * 6) * (2 * [Link] / points)
val x = cos(angle) * (0.6 + t * 0.01)
val z = sin(angle) * (0.6 + t * 0.01)
[Link](Particle.END_ROD,
[Link]().add(x, 0.2 + (t * 0.005), z), 0)
}
[Link]("${[Link]}Rolling...")
} else if (t < 60) {
// build energy sphere with dust transition
val radius = 0.8 + (t - 20) * 0.03
val points = 28
val color = [Link]([Link](60, 255),
[Link](60, 255), [Link](60, 255))
for (i in 0 until points) {
val angle = i * (2 * [Link] / points)
val x = cos(angle) * radius
val z = sin(angle) * radius
val pLoc = [Link]().add(x, 0.5 + [Link](t / 6.0) *
0.15, z)
[Link](Particle.DUST_COLOR_TRANSITION,
pLoc, 0, 0.0, 0.0, 0.0, 0.0, DustOptions(color, color, 1f))
if (i % 4 == 0)
[Link](Particle.EXPLOSION_NORMAL, pLoc, 0)
}
val idx = ((t - 20) / 4) % [Link]
[Link]("${[Link]}Rolling: $
{[Link]}${names[idx]}")
} else {
// explode finale
[Link](Particle.EXPLOSION_LARGE, loc, 1)
[Link]([Link], loc, 40, 0.6, 0.6, 0.6,
0.02)
[Link](Particle.END_ROD, loc, 40, 0.8, 0.8,
0.8, 0.02)
val rolled = [Link]().random()
giveOathToPlayer(player, rolled, replace = true)
[Link]("${[Link]}OATH AWAKENED", "$
{[Link]}${[Link]}", 10, 60, 10)
[Link]([Link])
// start HUDs for new cooldowns
startCooldownHUD(player, "${[Link]} Primary",
[Link])
startCooldownHUD(player, "${[Link]} Secondary",
[Link])
cancel()
}

t++
}
}.runTaskTimer(this, 0L, 2L)
}

// -------------------------
// Per-power cooldown gating
// -------------------------
fun handleOathUse(player: Player, oath: Oath, isSecondary: Boolean) {
val now = [Link]()
val key = "${[Link]}:${if (isSecondary) "sec" else "prim"}"
val playerMap = [Link]([Link])
{ mutableMapOf() }
val cooldownEnd = playerMap[key] ?: 0L
val remaining = cooldownEnd - now
if (remaining > 0) {
val seconds = ((remaining + 999) / 1000)
[Link]("${[Link]}$key Cooldown: ${seconds}s")
return
}
if (isSecondary) performSecondary(player, oath) else performPrimary(player,
oath)
val cdMillis = (if (isSecondary) [Link] else
[Link]) * 1000L
playerMap[key] = now + cdMillis
val hudName = "${[Link]} ${if (isSecondary) "Secondary" else
"Primary"}"
startCooldownHUD(player, hudName, if (isSecondary) [Link]
else [Link])
}

// -------------------------
// True damage helper (applies true damage amounts)
// -------------------------
private fun applyTrueDamage(target: LivingEntity, amount: Double, attacker:
Player? = null) {
val newHealth = [Link] - amount
if (newHealth > 0.0) {
try { [Link] = newHealth } catch (_: Exception) {}
} else {
if (attacker != null) {
try { [Link](1000.0, attacker) } catch (_: Exception)
{ [Link]() }
} else {
[Link]()
}
}
}

// -------------------------
// Implementations for each Oath's abilities
// -------------------------
private fun performPrimary(player: Player, oath: Oath) {
when (oath) {
[Link] -> primaryEmbers(player)
[Link] -> primaryFrostCryoLance(player)
[Link] -> primaryStormsStatic(player)
[Link] -> primaryEchoSonicPulse(player)
[Link] -> primaryVerdantThornLash(player)
[Link] -> primaryIronBash(player)
[Link] -> primaryRadianceBeam(player)
[Link] -> primaryAstraStellarPull(player)
[Link] -> primaryBloodCrimsonJab(player)
[Link] -> primarySoulSpiritSwipe(player)
[Link] -> primaryVoidSingularityPulse(player)
[Link] -> primaryZephyrWindSlash(player)
[Link] -> primaryTimeTemporalBlink(player)
}
}

private fun performSecondary(player: Player, oath: Oath) {


when (oath) {
[Link] -> secondaryEmbersInfernoBurst(player)
[Link] -> secondaryFrostGlacialPrison(player)
[Link] -> secondaryStormsTempestField(player)
[Link] -> secondaryEchoResonanceField(player)
[Link] -> secondaryVerdantBloomSurge(player)
[Link] -> secondaryIronFortressMode(player)
[Link] -> secondaryRadianceSolarPulse(player)
[Link] -> secondaryAstraNebulaSlam(player)
[Link] -> secondaryBloodVitalDrain(player)
[Link] -> secondarySoulEtherealHowl(player)
[Link] -> secondaryVoidBlackHole(player)
[Link] -> secondaryZephyrGaleLaunch(player)
[Link] -> secondaryTimeChronoRift(player)
}
}

// -------------------------
// 1) EMBERS (kept similar)
// -------------------------
private fun primaryEmbers(player: Player) {
val dir = [Link]()
val maxDist = 6
for (i in 1..maxDist) {
val pos =
[Link]().add([Link]().multiply([Link]()))
[Link]([Link], [Link](0.0, 1.0, 0.0), 4, 0.2,
0.2, 0.2, 0.01)
val ents = [Link](1.2, 1.2, 1.2)
for (e in ents) {
if (e is LivingEntity && e !== player) {
applyTrueDamage(e, PRIMARY_TRUE_DAMAGE, player)
[Link] = 2 * 20
spawnSpin(center = [Link](0.0, 0.6, 0.0), points = 10,
radius = 0.6)
}
}
}
spawnSpin(center = [Link](0.0, 1.0, 0.0), points = 18, radius
= 1.2)
}

private fun secondaryEmbersInfernoBurst(player: Player) {


val center = [Link]
val radius = 8.0
val ents = [Link](radius, 5.0, radius)
for (e in ents) {
if (e is LivingEntity && e !== player) {
applyTrueDamage(e, SECONDARY_TRUE_DAMAGE, player)
[Link] = [Link](Vector(0.0, 0.8, 0.0))
[Link] = 4 * 20
spawnPathParticles(center, [Link], 14)
}
}
spawnSpin(center = [Link](0.0, 1.0, 0.0), points = 24, radius = 2.0)
}

// -------------------------
// 2) FROST
// -------------------------
private fun primaryFrostCryoLance(player: Player) {
val eye = [Link]
val dir = [Link]()
val length = 18.0
val points = 28
val start = [Link]().add([Link]().multiply(1.0))
for (i in 0..points) {
val step = [Link]().add([Link]().multiply([Link]() *
(length / points)))
[Link]([Link], step, 1, 0.05, 0.05, 0.05,
0.01)
if (i % 5 == 0) [Link](Particle.BLOCK_CRUMBLE, step,
2, [Link]())
val nearby = [Link](1.2, 1.2, 1.2)
for (e in nearby) {
if (e is LivingEntity && e !== player) {
applyTrueDamage(e, PRIMARY_TRUE_DAMAGE, player)
[Link](PotionEffect([Link], 20 *
2, 1))
placeTemporaryBlock(player, [Link]().add(0.0, -1.0,
0.0), Material.POWDER_SNOW, durationTicks = 60)
spawnSpin(center = [Link](0.0, 0.6, 0.0), points = 10,
radius = 0.5)
}
}
}
}

private fun secondaryFrostGlacialPrison(player: Player) {


val center = [Link]()
val radius = 5
val durationTicks = 40 // 2s freeze in blocks
val placed = mutableListOf<Pair<Location, Material>>()
for (dx in -radius..radius) {
for (dz in -radius..radius) {
val bx = [Link] + dx
val bz = [Link] + dz
val by = [Link]
val loc = Location([Link], [Link](), [Link](),
[Link]())
try {
val original = [Link]
if ([Link] || ![Link]) {
val below = [Link]().add(0.0, -1.0, 0.0)
if ([Link]) {
[Link] = Material.POWDER_SNOW
[Link](loc to original)
}
} else {
val top = [Link]().add(0.0, 1.0, 0.0)
if ([Link]) {
val origTop = [Link]
[Link] = Material.POWDER_SNOW
[Link](top to origTop)
}
}
} catch (_: Exception) {}
}
}
tempPlacedBlocks[[Link]] = placed
val entities = [Link]([Link](), 4.0,
[Link]())
for (e in entities) {
if (e is LivingEntity && e !== player) {
val targetLoc = [Link]().add(0.0, -1.0, 0.0)
placeTemporaryBlock(player, targetLoc, Material.PACKED_ICE,
durationTicks = 40)
applyTrueDamage(e, SECONDARY_TRUE_DAMAGE, player)
[Link](PotionEffect([Link], 20 * 3,
2))
spawnChain(a = [Link](0.0, 0.6, 0.0), b = [Link](0.0,
1.0, 0.0), points = 14, center = center)
}
}
spawnFrostDomain(center, [Link](), ticks = 30)
object : BukkitRunnable() {
override fun run() {
val list = [Link]([Link]) ?:
mutableListOf()
for ((loc, mat) in list) {
try { if ([Link] == Material.POWDER_SNOW ||
[Link] == Material.PACKED_ICE) [Link] = mat } catch (_: Exception)
{}
}
}
}.runTaskLater(this, [Link]())
}

// -------------------------
// 3) STORMS
// -------------------------
private fun primaryStormsStatic(player: Player) {
val eye = [Link]
val dir = [Link]()
val length = 12.0
val points = 18
for (i in 0..points) {
val step = [Link]().add([Link]().multiply([Link]() *
(length / points)))
[Link](Particle.SONIC_BOOM, step, 0)
if (i % 4 == 0) [Link]([Link], step, 2)
val near = [Link](1.0, 1.0, 1.0)
for (e in near) if (e is LivingEntity && e !== player) {
applyTrueDamage(e, PRIMARY_TRUE_DAMAGE, player)
spawnSpin(center = [Link](0.0, 0.6, 0.0), points = 10,
radius = 0.6)
}
}
}

private fun secondaryStormsTempestField(player: Player) {


val center = [Link]
val radius = 7
val ticks = 30
object : BukkitRunnable() {
var t = 0
override fun run() {
if (t > ticks) { cancel(); return }
val points = 18 + (t % 6)
for (i in 0 until points) {
val angle = i * (2 * [Link] / points)
val x = cos(angle) * (radius * (0.4 + 0.6 * ([Link]() /
ticks)))
val z = sin(angle) * (radius * (0.4 + 0.6 * ([Link]() /
ticks)))
val loc = [Link]().add(x, 0.5, z)
[Link]([Link], loc, 1, 0.1, 0.1, 0.1,
0.0)
val colorA = [Link]
val colorB = [Link]
[Link](Particle.DUST_COLOR_TRANSITION, loc, 0,
0.0, 0.0, 0.0, 0.0, DustOptions(colorA, colorB, 1f))
val nearby = [Link](1.5, 2.0, 1.5)
for (e in nearby) if (e is LivingEntity && e !== player &&
[Link]() < 0.06) {
applyTrueDamage(e, SECONDARY_TRUE_DAMAGE, player)
spawnRing(center = [Link], points = 10, radius = 1.0)
}
}
t++
}
}.runTaskTimer(this, 0L, 6L)
}

// -------------------------
// 4) ECHO (Warden-themed) - updated secondary to 4 shockwaves + glow stacking
// -------------------------
private fun primaryEchoSonicPulse(player: Player) {
val eye = [Link]
val dir = [Link]()
val length = 14.0
val steps = 20
val start = [Link]().add([Link]().multiply(1.0))
for (i in 0..steps) {
val step = [Link]().add([Link]().multiply([Link]() *
(length / steps)))
[Link](Particle.SONIC_BOOM, step, 0)
[Link](Particle.SCULK_SOUL, step, 0)
val near = [Link](1.2, 1.2, 1.2)
for (e in near) if (e is LivingEntity && e !== player) {
applyTrueDamage(e, PRIMARY_TRUE_DAMAGE, player)
[Link](PotionEffect([Link], 20 * 1,
0))
spawnSpin(center = [Link](0.0, 0.6, 0.0), points = 10,
radius = 0.6)
}
}
}

private fun secondaryEchoResonanceField(player: Player) {


val center = [Link]
val maxRadius = 10.0
val waves = 4
val interval = 8L // ticks between waves
object : BukkitRunnable() {
var w = 0
override fun run() {
if (w >= waves) { cancel(); return }
val r = (maxRadius / waves) * (w + 1)
// visual ring
val ringPoints = 30
for (i in 0 until ringPoints) {
val angle = i * (2 * [Link] / ringPoints)
val x = cos(angle) * r
val z = sin(angle) * r
val loc = [Link]().add(x, 0.5, z)
[Link](Particle.SONIC_BOOM, loc, 0)
[Link](Particle.DUST_COLOR_TRANSITION, loc, 0,
0.0, 0.0, 0.0, 0.0, DustOptions([Link](40, 80, 180), [Link](100, 150,
255), 1f))
}
// damage & glowing: each of first 3 waves gives 1s glowing; final
wave gives 7s
val glowTicks = if (w < waves - 1) 20 * 1 else 20 * 7
val ents = [Link](r, 4.0, r)
for (e in ents) {
if (e is LivingEntity && e !== player) {
applyTrueDamage(e, SECONDARY_TRUE_DAMAGE / (if (w == waves
- 1) 1.0 else 1.5), player)
[Link](PotionEffect([Link],
glowTicks, 0))
spawnRing(center = [Link], points = 10, radius = 0.8 +
w * 0.2)
}
}
w++
}
}.runTaskTimer(this, 0L, interval)
}

// -------------------------
// 5) VERDANT
// -------------------------
private fun primaryVerdantThornLash(player: Player) {
val eye = [Link]
val dir = [Link]()
val length = 10.0
val points = 16
for (i in 0..points) {
val step = [Link]().add([Link]().multiply([Link]() *
(length / points)))
[Link](Particle.HAPPY_VILLAGER, step, 1)
if (i % 4 == 0) [Link](Particle.BLOCK_MARKER, step,
1, Material.OAK_LEAVES.createBlockData())
val near = [Link](1.2, 1.2, 1.2)
for (e in near) if (e is LivingEntity && e !== player) {
[Link] =
[Link]().subtract([Link]()).normalize().multiply(0.6
)
applyTrueDamage(e, PRIMARY_TRUE_DAMAGE, player)
[Link](PotionEffect([Link], 20 * 2, 0))
spawnSpin(center = [Link](0.0, 0.6, 0.0), points = 10,
radius = 0.5)
}
}
}

private fun secondaryVerdantBloomSurge(player: Player) {


val center = [Link]
val list = [Link](7.5, 5.0, 7.5)
for (e in list) if (e is LivingEntity && e !== player) {
applyTrueDamage(e, SECONDARY_TRUE_DAMAGE, player)
[Link](PotionEffect([Link], 20 * 4, 1))
spawnChain(a = [Link](0.0, 0.6, 0.0), b = [Link](0.0, 1.0,
0.0), points = 12, center = center)
}
spawnSpin(center = [Link](0.0, 1.0, 0.0), points = 18, radius = 1.6)
}

// -------------------------
// 6) IRON
// -------------------------
private fun primaryIronBash(player: Player) {
val center = [Link]
val list = [Link](6.0, 4.5, 6.0)
for (e in list) if (e is LivingEntity && e !== player) {
[Link](player, 1.6f, ([Link].x - [Link].x).toFloat(),
([Link].z - [Link].z).toFloat())
applyTrueDamage(e, PRIMARY_TRUE_DAMAGE, player)
spawnPathParticles(center, [Link], 8)
}
val dust = DustOptions([Link](160,160,160),
[Link](160,160,160), 1f)
[Link](Particle.DUST_COLOR_TRANSITION, [Link](0.0,
0.5, 0.0), 0, 0.0, 0.0, 0.0, 0.0, dust)
}

private fun secondaryIronFortressMode(player: Player) {


[Link](PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 20
* 6, 1))
val center = [Link]
val list = [Link](5.5, 4.0, 5.5)
for (e in list) if (e is LivingEntity && e !== player) {
[Link](player, 1.4f, ([Link].x - [Link].x).toFloat(),
([Link].z - [Link].z).toFloat())
}
spawnRing(center = [Link](0.0, 1.0, 0.0), points = 20, radius = 1.6)
}

// -------------------------
// 7) RADIANCE
// -------------------------
private fun primaryRadianceBeam(player: Player) {
val eye = [Link]
val dir = [Link]()
val length = 12.0
for (i in 0..24) {
val step = [Link]().add([Link]().multiply([Link]() *
(length / 24)))
[Link](Particle.DUST_COLOR_TRANSITION, step, 0,
0.0,0.0,0.0,0.0, DustOptions([Link], [Link], 1f))
if (i % 5 == 0) [Link](Particle.END_ROD, step, 0)
val near = [Link](0.8, 0.8, 0.8)
for (e in near) if (e is LivingEntity && e !== player) {
applyTrueDamage(e, PRIMARY_TRUE_DAMAGE, player)
[Link](PotionEffect([Link], 20*1,
0))
}
}
}

private fun secondaryRadianceSolarPulse(player: Player) {


val center = [Link]
val list = [Link](6.5, 4.5, 6.5)
for (e in list) if (e is LivingEntity && e !== player) {
applyTrueDamage(e, SECONDARY_TRUE_DAMAGE, player)
[Link](PotionEffect([Link], 20*3, 0))
spawnSpin(center = [Link](0.0, 0.6, 0.0), points = 12, radius =
1.0)
}
spawnRing(center = [Link](0.0, 1.0, 0.0), points = 24, radius = 2.0)
}

// -------------------------
// 8) ASTRA
// -------------------------
private fun primaryAstraStellarPull(player: Player) {
val list = [Link](12.0, 6.0, 12.0)
for (e in list) if (e is LivingEntity && e !== player) {
val dirToPlayer =
[Link]().subtract([Link]()).normalize()
val pullStrength = 2.4
[Link] = [Link](pullStrength).setY(0.9)
spawnChain(a = [Link](0.0, 0.6, 0.0), b =
[Link](0.0, 1.2, 0.0), points = 18, center = [Link])
applyTrueDamage(e, PRIMARY_TRUE_DAMAGE, player)
}
spawnRing(center = [Link](0.0, 1.0, 0.0), points = 22, radius
= 2.2)
}

private fun secondaryAstraNebulaSlam(player: Player) {


val list = [Link](12.0, 6.0, 12.0)
for (e in list) if (e is LivingEntity && e !== player) {
[Link] = [Link](Vector(0.0, 1.6, 0.0))
applyTrueDamage(e, SECONDARY_TRUE_DAMAGE, player)
spawnRing(center = [Link], points = 12, radius = 1.2)
}
spawnSpin(center = [Link](0.0,1.0,0.0), points = 18, radius =
1.8)
}

// -------------------------
// 9) BLOOD
// -------------------------
private fun primaryBloodCrimsonJab(player: Player) {
val eye = [Link]
val dir = [Link]()
val points = 14
for (i in 0..points) {
val step = [Link]().add([Link]().multiply([Link]() *
(10.0/points)))
[Link](Particle.DUST_COLOR_TRANSITION, step, 0, 0.0,
0.0, 0.0, 0.0, DustOptions([Link](140,10,10), [Link](180,40,40), 1f))
val near = [Link](1.0,1.0,1.0)
for (e in near) if (e is LivingEntity && e !== player) {
applyTrueDamage(e, PRIMARY_TRUE_DAMAGE, player)
try { [Link] =
min([Link](Attribute.MAX_HEALTH)!!.value, [Link] + 0.5) } catch
(_: Exception) {}
spawnSpin(center = [Link](0.0,0.6,0.0), points = 10, radius
= 0.6)
}
}
}

private fun secondaryBloodVitalDrain(player: Player) {


val center = [Link]
val list = [Link](6.5, 4.0, 6.5)
var healTotal = 0.0
for (e in list) if (e is LivingEntity && e !== player) {
applyTrueDamage(e, SECONDARY_TRUE_DAMAGE, player)
spawnChain(a = [Link](0.0, 0.6, 0.0), b = [Link](0.0, 1.0,
0.0), points = 12, center = center)
healTotal += 1.0
}
if (healTotal > 0) {
try { [Link] =
min([Link](Attribute.MAX_HEALTH)!!.value, [Link] + healTotal) }
catch (_: Exception) {}
}
}

// -------------------------
// 10) SOUL
// -------------------------
private fun primarySoulSpiritSwipe(player: Player) {
val eye = [Link]
val dir = [Link]()
val len = 8.0
for (i in 0..16) {
val step = [Link]().add([Link]().multiply([Link]() *
(len/16)))
[Link](Particle.SOUL_FIRE_FLAME, step, 1)
val near = [Link](1.0,1.0,1.0)
for (e in near) if (e is LivingEntity && e !== player) {
applyTrueDamage(e, PRIMARY_TRUE_DAMAGE, player)
spawnSpin(center = [Link](0.0,0.6,0.0), points = 10, radius
= 0.6)
}
}
}

private fun secondarySoulEtherealHowl(player: Player) {


val wolf = [Link]([Link], [Link]) as
Wolf
[Link] = true
[Link](player)
[Link] = "${[Link]}'s Spirit"
[Link](PotionEffect([Link], 20*20, 0))
object : BukkitRunnable() {
var ticks = 0
override fun run() {
if (ticks > 40 || [Link]) { [Link](); cancel(); return }
for (e in [Link](1.2, 1.2, 1.2)) {
if (e is LivingEntity && e !== player && e !== wolf) {
applyTrueDamage(e, SECONDARY_TRUE_DAMAGE, player)
spawnSpin(center = [Link](0.0,0.6,0.0), points =
12, radius = 0.9)
}
}
[Link] = [Link]().multiply(0.8)
ticks++
}
}.runTaskTimer(this, 0L, 2L)
}

// -------------------------
// 11) VOID
// -------------------------
private fun primaryVoidSingularityPulse(player: Player) {
val center = [Link]
val orb = [Link]().add([Link]().multiply(3.0))
val points = 14
for (i in 0..points) {
val angle = i * (2*[Link] / points)
val x = [Link](angle) * 0.6
val z = [Link](angle) * 0.6
val loc = [Link]().add(x, 0.2, z)
[Link]([Link], loc, 1)
val nearby = [Link](1.2,1.2,1.2)
for (e in nearby) if (e is LivingEntity && e !== player) {
[Link] =
[Link]([Link]().subtract([Link]()).normalize
().multiply(0.4)).setY(0.3)
applyTrueDamage(e, PRIMARY_TRUE_DAMAGE, player)
}
}
spawnRing(center = orb, points = 16, radius = 1.0)
}

private fun secondaryVoidBlackHole(player: Player) {


val center = [Link]
val radius = 6.0
val durationTicks = 40
object : BukkitRunnable() {
var t = 0
override fun run() {
if (t > durationTicks) { cancel(); return }
val progress = [Link]()/durationTicks
val curRadius = radius * (1.0 - progress*0.6)
val ents = [Link](curRadius, 4.0, curRadius)
for (e in ents) if (e is LivingEntity && e !== player) {
val toCenter =
[Link]().subtract([Link]()).normalize().multiply(0.9)
[Link] = [Link](toCenter).setY(0.2)
if (t % 10 == 0) applyTrueDamage(e, SECONDARY_TRUE_DAMAGE,
player)
spawnSpin(center = [Link](0.0,0.6,0.0), points = 10,
radius = 0.8)
}
spawnRing(center = [Link](0.0,1.0,0.0), points = 20, radius =
curRadius*0.7)
t++
}
}.runTaskTimer(this, 0L, 2L)
}

// -------------------------
// 12) ZEPHYR
// -------------------------
private fun primaryZephyrWindSlash(player: Player) {
val eye = [Link]
val dir = [Link]()
val len = 14.0
val points = 18
for (i in 0..points) {
val step =
[Link]().add([Link]().multiply([Link]()*(len/points)))
[Link]([Link], step, 1)
val near = [Link](0.9,0.9,0.9)
for (e in near) if (e is LivingEntity && e !== player) {
applyTrueDamage(e, PRIMARY_TRUE_DAMAGE, player)
[Link] = [Link]([Link]().multiply(0.6))
}
}
}

private fun secondaryZephyrGaleLaunch(player: Player) {


[Link] = [Link](Vector(0.0, 1.6, 0.0))
val center = [Link]
val list = [Link](6.0, 6.0, 6.0)
for (e in list) if (e is LivingEntity && e !== player) {
applyTrueDamage(e, SECONDARY_TRUE_DAMAGE, player)
[Link] = [Link](Vector(0.0, 0.8, 0.0))
spawnRing(center = [Link], points = 12, radius = 1.0)
}
spawnSpin(center = [Link](0.0,1.0,0.0), points = 20, radius = 2.0)
}

// -------------------------
// 13) TIME
// -------------------------
private fun primaryTimeTemporalBlink(player: Player) {
val back =
[Link]().add([Link]().multiply(-5.0))
spawnRing(center = [Link], points = 12, radius = 1.2)
[Link](back)
spawnRing(center = [Link], points = 14, radius = 1.4)
}

private fun secondaryTimeChronoRift(player: Player) {


val center = [Link]
val radius = 5.0
val durationTicks = 60
object : BukkitRunnable() {
var t = 0
override fun run() {
if (t > durationTicks) { cancel(); return }
val ents = [Link](radius, 4.0, radius)
for (e in ents) if (e is LivingEntity && e !== player) {
[Link](PotionEffect([Link], 40,
2))
spawnSpin(center = [Link](0.0,0.6,0.0), points = 10,
radius = 0.8)
}
t++
}
}.runTaskTimer(this, 0L, 4L)
spawnRing(center = [Link](0.0,1.0,0.0), points = 24, radius = radius)
}

// -------------------------
// Helpers: particles & temporary blocks
// -------------------------
private fun placeTemporaryBlock(player: Player, loc: Location, mat: Material,
durationTicks: Int = 40) {
try {
val world = [Link] ?: return
val b = [Link](loc)
val original = [Link]
if (original == mat) return
[Link] = mat
val list = [Link]([Link])
{ mutableListOf() }
[Link]([Link] to original)
object : BukkitRunnable() {
override fun run() {
try { if ([Link] == mat) [Link] = original } catch (_:
Exception) {}
}
}.runTaskLater(this, [Link]())
} catch (_: Exception) {}
}

private fun spawnSpin(center: Location, points: Int, radius: Double) {


object : BukkitRunnable() {
var t = 0
override fun run() {
if (t > 8) { cancel(); return }
for (i in 0 until points) {
val angle = (i + t * 5) * (2 * [Link] / points)
val x = cos(angle) * radius
val z = sin(angle) * radius
try {
[Link](Particle.END_ROD,
[Link]().add(x, 0.3, z), 0)
[Link]([Link],
[Link]().add(x*0.6, 0.2, z*0.6), 0)
} catch (_: Exception) {}
}
t++
}
}.runTaskTimer(this, 0L, 2L)
}

private fun spawnRing(center: Location, points: Int, radius: Double) {


for (i in 0 until points) {
val angle = i * (2 * [Link] / points)
val x = cos(angle) * radius
val z = sin(angle) * radius
try {
[Link]([Link],
[Link]().add(x, 0.1, z), 2, 0.05,0.05,0.05,0.01)
[Link](Particle.END_ROD, [Link]().add(x,
0.3, z), 0)
} catch (_: Exception) {}
}
}

private fun spawnChain(a: Location, b: Location, points: Int, center: Location)


{
val diff = [Link]().subtract([Link]())
for (i in 0..points) {
val step = [Link]().add([Link]().multiply([Link]()/points))
val amp = [Link]([Link]()/points * [Link]) * 0.3
try {
[Link](Particle.END_ROD, [Link]().add(0.0, amp,
0.0), 0)
[Link](Particle.SOUL_FIRE_FLAME,
[Link]().add(0.0, amp/2.0, 0.0), 0)
} catch (_: Exception) {}
}
}

private fun spawnPathParticles(a: Location, b: Location, points: Int) {


val diff = [Link]().subtract([Link]())
for (i in 0..points) {
val step = [Link]().add([Link]().multiply([Link]()/points))
try {
[Link]([Link], [Link](0.0, 0.2, 0.0),
1)
[Link]([Link], step, 0)
} catch (_: Exception) {}
}
}

private fun spawnFrostDomain(center: Location, maxRadius: Double, ticks: Int) {


object : BukkitRunnable() {
var t = 0
override fun run() {
if (![Link]([Link], [Link]))
{ cancel(); return }
val progress = if (ticks <= 0) 1.0 else [Link]() /
[Link]()
val radius = maxRadius * progress
if (t > ticks) { cancel(); return }
val points = (12 + (radius * 4)).toInt().coerceAtLeast(12)
for (i in 0 until points) {
val angle = i * (2 * [Link] / points)
val x = [Link](angle) * radius
val z = [Link](angle) * radius
val loc = [Link]().add(x, 0.1, z)
try {
[Link]([Link], loc, 2,
0.05,0.05,0.05,0.01)
[Link]([Link],
[Link](0.0,0.5,0.0), 1, 0.1,0.1,0.1,0.01)
} catch (_: Exception) {}
}
val entities = [Link](center, radius, 2.0,
radius)
for (e in entities) if (e is LivingEntity)
[Link](PotionEffect([Link], 40, 1))
t++
}
}.runTaskTimer(this, 0L, 2L)
}

// -------------------------
// HUD helper
// -------------------------
private fun startCooldownHUD(player: Player, name: String, seconds: Int) {
[Link]([Link]) { mutableMapOf() }[name] =
seconds
object : BukkitRunnable() {
override fun run() {
val map = hudCooldowns[[Link]] ?: run { cancel(); return }
val cd = map[name] ?: run { cancel(); return }
if (cd <= 0) {
[Link]("${[Link]}$name ${[Link]}
[READY]")
[Link](name)
cancel(); return
}
val totalBlocks = 10
val filled = (([Link]() / [Link](1)) *
totalBlocks).toInt().coerceIn(0, totalBlocks)
val filledStr = "█".repeat(filled)
val emptyStr = "█".repeat(totalBlocks - filled)
val bar = "${[Link]}$filledStr${ChatColor.DARK_GRAY}
$emptyStr${[Link]} ${cd}s"
[Link]("${[Link]}$name: $bar")
map[name] = cd - 1
}
}.runTaskTimer(this, 0L, 20L)
}

// helper DustOptions factory


private fun DustOptions(colorA: Color, colorB: Color, size: Float): DustOptions
{
return DustOptions(colorA, size)
}
}

private fun [Link](player: Player, f: Float, toFloat: Float,


toFloat2: Float) {}

// -------------------------
// Oath enum (primary=14s, secondary=30s)
// -------------------------
enum class Oath(val id: String, val displayName: String, val description:
List<String>, val primaryCooldown: Int, val secondaryCooldown: Int) {
EMBERS("embers","Embers", listOf("Flame Dash (Primary)","Inferno Burst
(Secondary)"), 14, 30),
FROST("frost","Frost", listOf("Cryo Lance (Primary)","Glacial Prison
(Secondary)"), 14, 30),
STORMS("storms","Storms", listOf("Static Strike (Primary)","Tempest Field
(Secondary)"), 14, 30),
ECHO("echo","Echo", listOf("Sonic Pulse (Primary)","Resonance Field
(Secondary)"), 14, 30),
VERDANT("verdant","Verdant", listOf("Thorn Lash (Primary)","Bloom Surge
(Secondary)"), 14, 30),
IRON("iron","Iron", listOf("Iron Bash (Primary)","Fortress Mode (Secondary)"),
14, 30),
RADIANCE("radiance","Radiance", listOf("Light Beam (Primary)","Solar Pulse
(Secondary)"), 14, 30),
ASTRA("astra","Astra", listOf("Stellar Pull (Primary)","Nebula Slam
(Secondary)"), 14, 30),
BLOOD("blood","Blood", listOf("Crimson Jab (Primary)","Vital Drain
(Secondary)"), 14, 30),
SOUL("soul","Soul", listOf("Spirit Swipe (Primary)","Ethereal Howl
(Secondary)"), 14, 30),
VOID("void","Void", listOf("Singularity Pulse (Primary)","Black Hole
(Secondary)"), 14, 30),
ZEPHYR("zephyr","Zephyr", listOf("Wind Slash (Primary)","Gale Launch
(Secondary)"), 14, 30),
TIME("time","Time", listOf("Temporal Blink (Primary)","Chrono Rift
(Secondary)"), 14, 30);

companion object {
fun fromId(id: String): Oath? = values().find { [Link](id, ignoreCase
= true) || [Link](id, ignoreCase = true) }
}
}

// -------------------------
// /giveoath command
// -------------------------
class GiveOathCommand(private val plugin: Oathsmpv2) : CommandExecutor {
override fun onCommand(sender: CommandSender, command: Command, label: String,
args: Array<out String>): Boolean {
if (sender !is Player) {
[Link]("This command can only be used in-game.")
return true
}
val player = sender
if ([Link]()) {
[Link](player); return true
}
val name = [Link](" ")
val oath = [Link](name)
if (oath != null) [Link](player, oath, replace = true)
else [Link]("${[Link]}Unknown Oath '$name'. Available: $
{[Link]().joinToString(", ") { [Link] }}")
return true
}
}

You might also like