LootTables.kt
Branches > main > bedd093 > files / src / main / kotlin / net / bowmap / server / loot / LootTables.kt
package net.bowmap.server.loot
import org.bukkit.Material
import java.util.concurrent.ThreadLocalRandom
import net.bowmap.server.item.*
interface Loot {
fun getLoot(): List<Item>
}
data class LootList(val list: List<Loot>) : Loot {
init {
require(list.isNotEmpty()) { "Loot list must not be empty!" }
}
constructor(vararg loots: Loot) : this(loots.toList())
override fun getLoot(): List<Item> {
val i = ThreadLocalRandom.current().nextInt(list.size)
return list[i].getLoot()
}
}
data class MaterialLoot(val type: ItemType, val min: Int = 1, val max: Int = min) : Loot {
constructor(material: Material, min: Int = 1, max: Int = min) : this(MaterialItemType(material), min, max)
init {
require(min >= 1 && min <= max && max <= maxStackSize(type)) {
"Invalid min/max stack sizes!"
}
}
override fun getLoot(): List<Item> {
val amount = ThreadLocalRandom.current().nextInt(min, max + 1)
return listOf(Item(type = type, amount = amount))
}
}
data class Category(val weight: Int, val loot: Loot) : Loot {
constructor(name: String, weight: Int, vararg loots: Loot) : this(
weight,
LootList(loots.toList())
)
init {
require(weight > 0) { "weight must be > 0" }
}
override fun getLoot(): List<Item> = loot.getLoot()
}
private fun buildLookup(categories: Array<out Category>): Array<Category> {
val totalWeight = totalWeight(categories)
val lookup = ArrayList<Category>(totalWeight)
for (c in categories) {
repeat(c.weight) {
lookup.add(c)
}
}
return lookup.toTypedArray()
}
private fun totalWeight(categories: Array<out Category>): Int {
require(categories.isNotEmpty()) { "Category list must not be empty!" }
val total = categories.sumOf { it.weight }
require(total != 0) { "Weight cannot be 0" }
return total
}
data class WeightedLoot(private val lookup: Array<Category>, private val totalWeight: Int) : Loot {
constructor(vararg categories: Category) : this(buildLookup(categories), totalWeight(categories))
private fun pickRandomCategory(): Category {
val randomWeight = ThreadLocalRandom.current().nextInt(totalWeight)
return lookup[randomWeight]
}
override fun getLoot(): List<Item> {
return pickRandomCategory().getLoot()
}
}