Effect.kt

Branches > main > bfb8108 > files / src / main / kotlin / net / bowmap / stormbow / Effect.kt

package net.bowmap.stormbow

import net.kyori.adventure.text.Component
import net.kyori.adventure.text.format.NamedTextColor.*
import net.kyori.adventure.audience.Audience
import org.bukkit.inventory.ItemStack
import org.bukkit.Bukkit
import org.bukkit.Location
import net.bowmap.stormbow.game.*
import kotlinx.collections.immutable.*

/// An effect is a piece of data representing a side effect that can be executed,
/// such as with a Bukkit API call
sealed interface Effect

/// An effect that knows how to execute itself.
/// Some effects are to be run by event listeners themselves
sealed interface DefaultEffect : Effect {
  fun execute()
}

/// An effect that requires an event handler to respond to it
sealed interface EventEffect : Effect

data class Effects(val list: PersistentList<Effect>) {
  constructor(vararg effects: Effect) : this(effects.toList().toPersistentList())
}

fun execute(effects: Effects) {
  effects.list.forEach { effect ->
    if (effect is DefaultEffect) {
      effect.execute()
    }
  }
}

/// Returns a the first effect of type T in the list effects
inline fun <reified T : Effect> find(effects: Effects): T? =
  effects.list.filterIsInstance<T>().firstOrNull()

/// Returns whether an effect of type T exists in the list of effects
inline fun <reified T : Effect> contains(effects: Effects): Boolean =
  effects.list.any {it is T}


// TODO you can send a message to more than one audience
// I'd like audiences to just be able to be collections :/
data class SendMessage(val audience: Collection<Audience>, val message: Component) : DefaultEffect {
  override fun execute() {
    audience.forEach { a ->
      a.sendMessage(message)
    }
  }
}

data class Broadcast(val message: Component) : DefaultEffect {
  override fun execute() {
    Bukkit.broadcast(message)
  }
}

data class Debug(val id: String, val x: Any?) : DefaultEffect {
  override fun execute() {
    Bukkit.broadcast(Component.text("Debug ($id): $x", GRAY))
  }
}

// Also make Player, mutable players are yucky
data class Give(val player: Player, val items: List<Item>) : DefaultEffect {
  constructor(player: Player, item: Item) : this(player, listOf(item))
  override fun execute() {
    Bukkit.getPlayer(player.uuid)?.give(items.map(::toItemStack))
  }
}

/// Cancels the current action.
/// Events will generally call .setCancelled(true), but this is a logical action, and they could do something else.
class Cancel() : EventEffect
data class SetFishTime(val ticks: Int) : EventEffect

data class Teleport(val entity: Entity, val location: Location) : DefaultEffect {
  override fun execute() {
    Bukkit.getEntity(entity.uuid)?.teleport(location)
  }
}