aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/util/skyblock/AbilityUtils.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/util/skyblock/AbilityUtils.kt')
-rw-r--r--src/main/kotlin/util/skyblock/AbilityUtils.kt138
1 files changed, 138 insertions, 0 deletions
diff --git a/src/main/kotlin/util/skyblock/AbilityUtils.kt b/src/main/kotlin/util/skyblock/AbilityUtils.kt
new file mode 100644
index 0000000..0f0adbe
--- /dev/null
+++ b/src/main/kotlin/util/skyblock/AbilityUtils.kt
@@ -0,0 +1,138 @@
+package moe.nea.firmament.util.skyblock
+
+import kotlin.time.Duration
+import net.minecraft.item.ItemStack
+import net.minecraft.text.Text
+import moe.nea.firmament.util.ErrorUtil
+import moe.nea.firmament.util.directLiteralStringContent
+import moe.nea.firmament.util.mc.loreAccordingToNbt
+import moe.nea.firmament.util.parseShortNumber
+import moe.nea.firmament.util.parseTimePattern
+import moe.nea.firmament.util.unformattedString
+import moe.nea.firmament.util.useMatch
+
+object AbilityUtils {
+ data class ItemAbility(
+ val name: String,
+ val hasPowerScroll: Boolean,
+ val activation: AbilityActivation,
+ val manaCost: Int?,
+ val descriptionLines: List<Text>,
+ val cooldown: Duration?,
+ )
+
+ @JvmInline
+ value class AbilityActivation(
+ val label: String
+ ) {
+ companion object {
+ val RIGHT_CLICK = AbilityActivation("RIGHT CLICK")
+ val SNEAK_RIGHT_CLICK = AbilityActivation("SNEAK RIGHT CLICK")
+ val SNEAK = AbilityActivation("SNEAK")
+ val EMPTY = AbilityActivation("")
+ fun of(text: String?): AbilityActivation {
+ val trimmed = text?.trim()
+ if (trimmed.isNullOrBlank())
+ return EMPTY
+ return AbilityActivation(trimmed)
+ }
+ }
+ }
+
+ private val abilityNameRegex = "Ability: (?<name>.*?) *".toPattern()
+ private fun findAbility(iterator: ListIterator<Text>): ItemAbility? {
+ if (!iterator.hasNext()) {
+ return null
+ }
+ val line = iterator.next()
+ // The actual information about abilities is stored in the siblings
+ if (line.directLiteralStringContent != "") return null
+ var powerScroll: Boolean = false // This should instead determine the power scroll based on text colour
+ var abilityName: String? = null
+ var activation: String? = null
+ var hasProcessedActivation = false
+ for (sibling in line.siblings) {
+ val directContent = sibling.directLiteralStringContent ?: continue
+ if (directContent == "⦾ ") {
+ powerScroll = true
+ continue
+ }
+ if (!hasProcessedActivation && abilityName != null) {
+ hasProcessedActivation = true
+ activation = directContent
+ continue
+ }
+ abilityNameRegex.useMatch<Nothing>(directContent) {
+ abilityName = group("name")
+ continue
+ }
+ if (abilityName != null) {
+ ErrorUtil.softError("Found abilityName $abilityName without finding but encountered unprocessable element in: $line")
+ }
+ return null
+ }
+ if (abilityName == null) return null
+ val descriptionLines = mutableListOf<Text>()
+ var manaCost: Int? = null
+ var cooldown: Duration? = null
+ while (iterator.hasNext()) {
+ val descriptionLine = iterator.next()
+ if (descriptionLine.unformattedString == "") break
+ var nextIsManaCost = false
+ var isSpecialLine = false
+ var nextIsDuration = false
+ for (sibling in descriptionLine.siblings) {
+ val directContent = sibling.directLiteralStringContent ?: continue
+ if ("Mana Cost: " == directContent) { // TODO: 'Soulflow Cost: ' support (or maybe a generic 'XXX Cost: ')
+ nextIsManaCost = true
+ isSpecialLine = true
+ continue
+ }
+ if ("Cooldown: " == directContent) {
+ nextIsDuration = true
+ isSpecialLine = true
+ continue
+ }
+ if (nextIsDuration) {
+ nextIsDuration = false
+ cooldown = parseTimePattern(directContent)
+ continue
+ }
+ if (nextIsManaCost) {
+ nextIsManaCost = false
+ manaCost = parseShortNumber(directContent).toInt()
+ continue
+ }
+ if (isSpecialLine) {
+ ErrorUtil.softError("Unknown special line segment: '$sibling' in '$descriptionLine'")
+ }
+ }
+ if (!isSpecialLine) {
+ descriptionLines.add(descriptionLine)
+ }
+ }
+ return ItemAbility(
+ abilityName,
+ powerScroll,
+ AbilityActivation.of(activation),
+ manaCost,
+ descriptionLines,
+ cooldown
+ )
+ }
+
+ fun getAbilities(lore: List<Text>): List<ItemAbility> {
+ val iterator = lore.listIterator()
+ val abilities = mutableListOf<ItemAbility>()
+ while (iterator.hasNext()) {
+ findAbility(iterator)?.let(abilities::add)
+ }
+
+ return abilities
+ }
+
+ fun getAbilities(itemStack: ItemStack): List<ItemAbility> {
+ return getAbilities(itemStack.loreAccordingToNbt)
+ }
+
+}