aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt12
-rw-r--r--src/main/kotlin/commands/rome.kt4
-rw-r--r--src/main/kotlin/repo/SBItemStack.kt30
-rw-r--r--src/main/kotlin/repo/item/SBItemStats.kt19
-rw-r--r--src/main/kotlin/repo/item/SBReforge.kt66
-rw-r--r--src/main/kotlin/repo/item/StatBlock.kt163
-rw-r--r--src/main/kotlin/util/skyblock/stats/BuffKind.kt15
-rw-r--r--src/main/kotlin/util/skyblock/stats/StatBlock.kt61
-rw-r--r--src/main/kotlin/util/skyblock/stats/StatFormatting.kt63
-rw-r--r--src/main/kotlin/util/skyblock/stats/StatLine.kt71
10 files changed, 309 insertions, 195 deletions
diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt
index 8e86967..7a289b9 100644
--- a/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt
+++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt
@@ -17,6 +17,7 @@ import me.shedaniel.rei.api.common.display.Display
import me.shedaniel.rei.api.common.display.DisplaySerializer
import me.shedaniel.rei.api.common.entry.EntryIngredient
import me.shedaniel.rei.api.common.entry.EntryStack
+import util.skyblock.stats.StatFormatting
import net.minecraft.entity.EntityType
import net.minecraft.entity.SpawnReason
import net.minecraft.text.Text
@@ -31,7 +32,7 @@ import moe.nea.firmament.repo.ReforgeStore
import moe.nea.firmament.repo.RepoItemTypeCache
import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.repo.SBItemStack
-import moe.nea.firmament.repo.item.StatBlock
+import moe.nea.firmament.util.skyblock.stats.StatBlock
import moe.nea.firmament.util.AprilFoolsUtil
import moe.nea.firmament.util.FirmFormatters
import moe.nea.firmament.util.SkyblockId
@@ -40,6 +41,7 @@ import moe.nea.firmament.util.grey
import moe.nea.firmament.util.skyblock.ItemType
import moe.nea.firmament.util.skyblock.Rarity
import moe.nea.firmament.util.skyblock.SkyBlockItems
+import moe.nea.firmament.util.skyblock.stats.StatLine
import moe.nea.firmament.util.skyblockId
import moe.nea.firmament.util.tr
@@ -107,8 +109,8 @@ class SBReforgeRecipe(
for ((i, statId) in display.reforge.statUniverse.withIndex()) {
val label = Widgets.createLabel(
Point(bounds.minX + 10 + 24 + 24 + 20, bounds.minY + 8 + i * 11),
- StatBlock.StatLine( // TODO: add helper methods for constructing stat lines
- StatBlock.findStatFormatting(SBItemStack.statIdToName(statId)),
+ StatLine(
+ StatFormatting.findForId(statId),
0.0
).reconstitute(7))
.horizontalAlignment(Label.LEFT_ALIGNED)
@@ -120,8 +122,8 @@ class SBReforgeRecipe(
val stats = display.reforge.reforgeStats?.get(entry.rarity) ?: mapOf()
for ((stat, label) in statToLineMappings) {
label.message =
- StatBlock.StatLine(
- StatBlock.findStatFormatting(SBItemStack.statIdToName(stat)),
+ StatLine(
+ StatFormatting.findForId(stat),
stats[stat] ?: 0.0
).reconstitute(7)
}
diff --git a/src/main/kotlin/commands/rome.kt b/src/main/kotlin/commands/rome.kt
index 3b3ab7a..5bdd0ed 100644
--- a/src/main/kotlin/commands/rome.kt
+++ b/src/main/kotlin/commands/rome.kt
@@ -257,8 +257,10 @@ fun firmamentCommand() = literal("firmament") {
dataT.gold()
else if (oldData == data)
dataT.lime()
- else
+ else {
+ println("Mismatched prop ${prop}:\nExpected: ${oldData}\nActual : ${data}")
dataT.red()
+ }
source.sendFeedback(Text.literal("${prop.javaClass.simpleName}")
.blue()
.append(Text.literal(": ").grey())
diff --git a/src/main/kotlin/repo/SBItemStack.kt b/src/main/kotlin/repo/SBItemStack.kt
index 93cf52c..5644901 100644
--- a/src/main/kotlin/repo/SBItemStack.kt
+++ b/src/main/kotlin/repo/SBItemStack.kt
@@ -5,6 +5,7 @@ import com.mojang.serialization.codecs.RecordCodecBuilder
import io.github.moulberry.repo.constants.PetNumbers
import io.github.moulberry.repo.data.NEUIngredient
import io.github.moulberry.repo.data.NEUItem
+import util.skyblock.stats.StatFormatting
import net.minecraft.item.ItemStack
import net.minecraft.network.RegistryByteBuf
import net.minecraft.network.codec.PacketCodec
@@ -14,7 +15,7 @@ import net.minecraft.text.Text
import net.minecraft.util.Formatting
import moe.nea.firmament.repo.ItemCache.asItemStack
import moe.nea.firmament.repo.ItemCache.withFallback
-import moe.nea.firmament.repo.item.StatBlock
+import moe.nea.firmament.util.skyblock.stats.StatBlock
import moe.nea.firmament.util.FirmFormatters
import moe.nea.firmament.util.LegacyFormattingCode
import moe.nea.firmament.util.MC
@@ -37,6 +38,7 @@ import moe.nea.firmament.util.removeColorCodes
import moe.nea.firmament.util.skyBlockId
import moe.nea.firmament.util.skyblock.ItemType
import moe.nea.firmament.util.skyblock.Rarity
+import moe.nea.firmament.util.skyblock.stats.BuffKind
import moe.nea.firmament.util.skyblockId
import moe.nea.firmament.util.unformattedString
import moe.nea.firmament.util.useMatch
@@ -112,7 +114,7 @@ data class SBItemStack constructor(
buffKind: BuffKind,
) {
val namedReforgeStats = reforgeStats
- .mapKeysTo(mutableMapOf()) { statIdToName(it.key) }
+ .mapKeysTo(mutableMapOf()) { StatFormatting.statIdToName(it.key) }
val loreMut = itemStack.loreAccordingToNbt.toMutableList()
val statBlock = StatBlock.fromLore(loreMut)
@@ -122,30 +124,6 @@ data class SBItemStack constructor(
statBlock.applyModifications(loreMut)
itemStack.loreAccordingToNbt = loreMut
}
-
- data class StatFormatting(
- val name: String,
- val postFix: String,
- val color: Formatting,
- val isStarAffected: Boolean = true,
- )
-
- enum class BuffKind(
- val color: Formatting,
- val prefix: String,
- val postFix: String,
- val isHidden: Boolean,
- ) {
- REFORGE(Formatting.BLUE, "(", ")", false),
- STAR_BUFF(Formatting.RESET, "", "", true),
- CATA_STAR_BUFF(Formatting.DARK_GRAY, "(", ")", false),
- ;
- }
-
- fun statIdToName(statId: String): String {
- val segments = statId.split("_")
- return segments.joinToString(" ") { it.replaceFirstChar { it.uppercaseChar() } }
- }
}
constructor(skyblockId: SkyblockId, petData: PetData) : this(
diff --git a/src/main/kotlin/repo/item/SBItemStats.kt b/src/main/kotlin/repo/item/SBItemStats.kt
new file mode 100644
index 0000000..94a40d0
--- /dev/null
+++ b/src/main/kotlin/repo/item/SBItemStats.kt
@@ -0,0 +1,19 @@
+package moe.nea.firmament.repo.item
+
+import com.google.auto.service.AutoService
+import net.minecraft.item.ItemStack
+import moe.nea.firmament.util.mc.loreAccordingToNbt
+import moe.nea.firmament.util.skyblock.stats.StatBlock
+
+@AutoService(SBItemProperty::class)
+object SBItemStats : SBItemProperty<StatBlock>() {
+ override fun fromStack(
+ stack: ItemStack,
+ store: SBItemData
+ ): StatBlock? {
+ return StatBlock.fromLore(stack.loreAccordingToNbt)
+ }
+
+ override val order: Int
+ get() = 100
+}
diff --git a/src/main/kotlin/repo/item/SBReforge.kt b/src/main/kotlin/repo/item/SBReforge.kt
new file mode 100644
index 0000000..231e3cc
--- /dev/null
+++ b/src/main/kotlin/repo/item/SBReforge.kt
@@ -0,0 +1,66 @@
+package moe.nea.firmament.repo.item
+
+import com.google.auto.service.AutoService
+import net.minecraft.item.ItemStack
+import net.minecraft.text.Style
+import net.minecraft.text.Text
+import moe.nea.firmament.repo.ItemCache
+import moe.nea.firmament.repo.ReforgeStore
+import moe.nea.firmament.repo.SBItemStack
+import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.ReforgeId
+import moe.nea.firmament.util.blue
+import moe.nea.firmament.util.getReforgeId
+import moe.nea.firmament.util.grey
+import moe.nea.firmament.util.mc.displayNameAccordingToNbt
+import moe.nea.firmament.util.mc.modifyLore
+import moe.nea.firmament.util.modifyExtraAttributes
+import moe.nea.firmament.util.prepend
+import moe.nea.firmament.util.reconstitute
+import moe.nea.firmament.util.skyblock.Rarity
+import moe.nea.firmament.util.skyblock.stats.BuffKind
+import moe.nea.firmament.util.unformattedString
+
+@AutoService(SBItemProperty::class)
+object SBReforge : SBItemProperty.State<ReforgeId>() {
+ override fun applyToStack(
+ stack: ItemStack,
+ store: SBItemData,
+ value: ReforgeId?
+ ): ItemStack {
+ val reforgeId = value ?: return stack
+ stack.modifyExtraAttributes { data ->
+ data.putString("modifier", reforgeId.id)
+ }
+ val rarity = Rarity.fromItem(stack) ?: return stack
+ val reforge = ReforgeStore.modifierLut[reforgeId] ?: return stack
+ stack.displayNameAccordingToNbt = stack.displayNameAccordingToNbt.copy()
+ .prepend(Text.literal(reforge.reforgeName + " ").formatted(rarity.colour()))
+ val reforgeStats = reforge.reforgeStats?.get(rarity) ?: mapOf()
+ SBItemStack.appendEnhancedStats(stack, reforgeStats, BuffKind.REFORGE)
+ reforge.reforgeAbility?.get(rarity)?.let { reforgeAbility ->
+ val formattedReforgeAbility = ItemCache.un189Lore(reforgeAbility)
+ .grey()
+ stack.modifyLore {
+ val lastBlank = it.indexOfLast { it.unformattedString.isBlank() }
+ val newList = mutableListOf<Text>()
+ newList.addAll(it.subList(0, lastBlank))
+ newList.add(Text.literal(""))
+ newList.add(Text.literal("${reforge.reforgeName} Bonus").blue())
+ MC.font.textHandler.wrapLines(formattedReforgeAbility, 180, Style.EMPTY).mapTo(newList) {
+ it.reconstitute()
+ }
+ newList.addAll(it.subList(lastBlank, it.size))
+ newList
+ }
+ }
+ return stack
+ }
+
+ override fun fromStack(
+ stack: ItemStack,
+ store: SBItemData
+ ): ReforgeId? {
+ return stack.getReforgeId()
+ }
+}
diff --git a/src/main/kotlin/repo/item/StatBlock.kt b/src/main/kotlin/repo/item/StatBlock.kt
deleted file mode 100644
index 94643a2..0000000
--- a/src/main/kotlin/repo/item/StatBlock.kt
+++ /dev/null
@@ -1,163 +0,0 @@
-package moe.nea.firmament.repo.item
-
-import kotlin.collections.forEach
-import kotlin.collections.plus
-import net.minecraft.text.Style
-import net.minecraft.text.Text
-import net.minecraft.text.TextColor
-import net.minecraft.util.Formatting
-import moe.nea.firmament.repo.SBItemStack.Companion.BuffKind
-import moe.nea.firmament.repo.SBItemStack.Companion.StatFormatting
-import moe.nea.firmament.util.FirmFormatters
-import moe.nea.firmament.util.directLiteralStringContent
-import moe.nea.firmament.util.grey
-import moe.nea.firmament.util.useMatch
-import moe.nea.firmament.util.withColor
-
-data class StatBlock(
- val indexedByName: Map<String, StatLine>,
- val startIndex: Int,
- val endIndex: Int,
- private val modifiedLines: MutableMap<String, StatLine> = mutableMapOf()
-) {
-
- /**
- * Note that the returned stat line must be created by copying from the original stat line (to keep indexes in sync).
- */
- fun modify(statName: String, mod: (StatLine) -> StatLine) {
- val existing = modifiedLines[statName] ?: indexedByName[statName] ?: StatLine(findStatFormatting(statName), 0.0)
- modifiedLines[statName] = mod(existing)
- }
-
- fun applyModifications(lore: MutableList<Text>) {
- if (modifiedLines.isEmpty()) return
- var nextAppendIndex = endIndex
- if (startIndex < 0) // No existing stat block, insert the after space.
- lore.add(0, Text.literal(""))
- modifiedLines.values.forEach { line ->
- val loreLine = if (line.loreIndex < 0) {
- lore.add(nextAppendIndex, Text.literal(""))
- nextAppendIndex++
- } else line.loreIndex
- lore[loreLine] = line.reconstitute()
- }
- }
-
- companion object {
- fun fromLore(lore: List<Text>): StatBlock {
- val map = mutableMapOf<String, StatLine>()
- var start = -1
- var end = 0
- for ((index, text) in lore.withIndex()) {
- val statLine = parseStatLine(text)
- ?.copy(loreIndex = index)
- if (statLine == null) {
- if (start < 0) continue
- else break
- }
- map[statLine.statName] = statLine
- if (start < 0)
- start = index
- end = index + 1
- }
- return StatBlock(map, start, end)
- }
-
- val allFormattingOverrides = listOf(
- StatFormatting("Sea Creature Chance", "%", Formatting.RED),
- StatFormatting("Strength", "", Formatting.RED),
- StatFormatting("Damage", "", Formatting.RED),
- StatFormatting("Bonus Attack Speed", "%", Formatting.RED),
- StatFormatting("Shot Cooldown", "s", Formatting.GREEN, false),
- StatFormatting("Ability Damage", "%", Formatting.RED),
- StatFormatting("Crit Damage", "%", Formatting.RED),
- StatFormatting("Crit Chance", "%", Formatting.RED),
- StatFormatting("Ability Damage", "%", Formatting.RED),
- StatFormatting("Trophy Fish Chance", "%", Formatting.GREEN),
- StatFormatting("Health", "", Formatting.GREEN),
- StatFormatting("Defense", "", Formatting.GREEN),
- StatFormatting("Fishing Speed", "", Formatting.GREEN),
- StatFormatting("Double Hook Chance", "%", Formatting.GREEN),
- StatFormatting("Mining Speed", "", Formatting.GREEN),
- StatFormatting("Mining Fortune", "", Formatting.GREEN),
- StatFormatting("Heat Resistance", "", Formatting.GREEN),
- StatFormatting("Swing Range", "", Formatting.GREEN),
- StatFormatting("Rift Time", "", Formatting.GREEN),
- StatFormatting("Speed", "", Formatting.GREEN),
- StatFormatting("Farming Fortune", "", Formatting.GREEN),
- StatFormatting("True Defense", "", Formatting.GREEN),
- StatFormatting("Mending", "", Formatting.GREEN),
- StatFormatting("Foraging Wisdom", "", Formatting.GREEN),
- StatFormatting("Farming Wisdom", "", Formatting.GREEN),
- StatFormatting("Foraging Fortune", "", Formatting.GREEN),
- StatFormatting("Magic Find", "", Formatting.GREEN),
- StatFormatting("Ferocity", "", Formatting.GREEN),
- StatFormatting("Bonus Pest Chance", "%", Formatting.GREEN),
- StatFormatting("Cold Resistance", "", Formatting.GREEN),
- StatFormatting("Pet Luck", "", Formatting.GREEN),
- StatFormatting("Fear", "", Formatting.GREEN),
- StatFormatting("Mana Regen", "%", Formatting.GREEN),
- StatFormatting("Rift Damage", "", Formatting.GREEN),
- StatFormatting("Hearts", "", Formatting.GREEN),
- StatFormatting("Vitality", "", Formatting.GREEN),
- // TODO: make this a repo json
- )
- val formattingOverrides = allFormattingOverrides.associateBy { it.name }
- fun findStatFormatting(name: String) =
- formattingOverrides[name] ?: StatFormatting(name, "", Formatting.GREEN)
-
- private val statLabelRegex = "(?<statName>.*): ".toPattern()
- private fun parseStatLine(line: Text): StatLine? {
- val sibs = line.siblings
- val stat = sibs.firstOrNull() ?: return null
- if (stat.style.color != TextColor.fromFormatting(Formatting.GRAY)) return null
- val statLabel = stat.directLiteralStringContent ?: return null
- val statName = statLabelRegex.useMatch(statLabel) { group("statName") } ?: return null
- return StatLine(findStatFormatting(statName),
- sibs[1]?.directLiteralStringContent?.trim(' ', 's', '%', '+')?.toDoubleOrNull() ?: 0.0,
- sibs.subList(2, sibs.size))
- }
-
- }
-
- data class StatLine(
- val stat: StatFormatting,
- val value: Double,
- val modifiers: List<Text> = listOf(),
- val loreIndex: Int = -1,
- ) {
- fun formatValue() =
- Text.literal(FirmFormatters.formatCommas(
- value, 1, includeSign = true) + stat.postFix + " ")
- .setStyle(Style.EMPTY.withColor(stat.color))
-
- val statName get() = stat.name
- fun reconstitute(abbreviateTo: Int = Int.MAX_VALUE): Text =
- Text.literal("").setStyle(Style.EMPTY.withItalic(false))
- .append(Text.literal("${abbreviate(abbreviateTo)}: ").grey())
- .append(formatValue())
- .also { modifiers.forEach(it::append) }
-
- fun addStat(amount: Double, buffKind: BuffKind): StatLine {
- val formattedAmount = FirmFormatters.formatCommas(amount, 1, includeSign = true)
- return copy(
- value = value + amount,
- modifiers = modifiers +
- if (buffKind.isHidden) emptyList()
- else listOf(
- Text.literal(
- buffKind.prefix + formattedAmount +
- stat.postFix +
- buffKind.postFix + " ")
- .withColor(buffKind.color)))
- }
-
- private fun abbreviate(abbreviateTo: Int): String {
- if (abbreviateTo >= statName.length) return statName
- val segments = statName.split(" ")
- return segments.joinToString(" ") {
- it.substring(0, maxOf(1, abbreviateTo / segments.size))
- }
- }
- }
-}
diff --git a/src/main/kotlin/util/skyblock/stats/BuffKind.kt b/src/main/kotlin/util/skyblock/stats/BuffKind.kt
new file mode 100644
index 0000000..c0b45c4
--- /dev/null
+++ b/src/main/kotlin/util/skyblock/stats/BuffKind.kt
@@ -0,0 +1,15 @@
+package moe.nea.firmament.util.skyblock.stats
+
+import net.minecraft.util.Formatting
+
+enum class BuffKind(
+ val color: Formatting,
+ val prefix: String,
+ val postFix: String,
+ val isHidden: Boolean,
+) {
+ REFORGE(Formatting.BLUE, "(", ")", false),
+ STAR_BUFF(Formatting.RESET, "", "", true),
+ CATA_STAR_BUFF(Formatting.DARK_GRAY, "(", ")", false),
+ ;
+}
diff --git a/src/main/kotlin/util/skyblock/stats/StatBlock.kt b/src/main/kotlin/util/skyblock/stats/StatBlock.kt
new file mode 100644
index 0000000..3865e79
--- /dev/null
+++ b/src/main/kotlin/util/skyblock/stats/StatBlock.kt
@@ -0,0 +1,61 @@
+package moe.nea.firmament.util.skyblock.stats
+
+import util.skyblock.stats.StatFormatting
+import moe.nea.firmament.util.directLiteralStringContent
+import moe.nea.firmament.util.useMatch
+import net.minecraft.text.Text
+import net.minecraft.text.TextColor
+import net.minecraft.util.Formatting
+
+data class StatBlock(
+ val indexedByName: Map<String, StatLine>,
+ val startIndex: Int,
+ val endIndex: Int,
+ private val modifiedLines: MutableMap<String, StatLine> = mutableMapOf()
+) {
+
+ /**
+ * Note that the returned stat line must be created by copying from the original stat line (to keep indexes in sync).
+ */
+ fun modify(statName: String, mod: (StatLine) -> StatLine) {
+ val existing =
+ modifiedLines[statName] ?: indexedByName[statName]
+ ?: StatLine(StatFormatting.findForName(statName), 0.0)
+ modifiedLines[statName] = mod(existing)
+ }
+
+ fun applyModifications(lore: MutableList<Text>) {
+ if (modifiedLines.isEmpty()) return
+ var nextAppendIndex = endIndex
+ if (startIndex < 0) // No existing stat block, insert the after space.
+ lore.add(0, Text.literal(""))
+ modifiedLines.values.forEach { line ->
+ val loreLine = if (line.loreIndex < 0) {
+ lore.add(nextAppendIndex, Text.literal(""))
+ nextAppendIndex++
+ } else line.loreIndex
+ lore[loreLine] = line.reconstitute()
+ }
+ }
+
+ companion object {
+ fun fromLore(lore: List<Text>): StatBlock {
+ val map = mutableMapOf<String, StatLine>()
+ var start = -1
+ var end = 0
+ for ((index, text) in lore.withIndex()) {
+ val statLine = StatLine.fromLoreLine(text)
+ ?.copy(loreIndex = index)
+ if (statLine == null) {
+ if (start < 0) continue
+ else break
+ }
+ map[statLine.statName] = statLine
+ if (start < 0)
+ start = index
+ end = index + 1
+ }
+ return StatBlock(map, start, end)
+ }
+ }
+}
diff --git a/src/main/kotlin/util/skyblock/stats/StatFormatting.kt b/src/main/kotlin/util/skyblock/stats/StatFormatting.kt
new file mode 100644
index 0000000..28a329e
--- /dev/null
+++ b/src/main/kotlin/util/skyblock/stats/StatFormatting.kt
@@ -0,0 +1,63 @@
+package util.skyblock.stats
+
+import net.minecraft.util.Formatting
+
+data class StatFormatting(
+ val name: String,
+ val postFix: String,
+ val color: Formatting,
+ val isStarAffected: Boolean = true,
+) {
+ companion object {
+ fun statIdToName(statId: String): String {
+ val segments = statId.split("_")
+ return segments.joinToString(" ") { it.replaceFirstChar { it.uppercaseChar() } }
+ }
+ fun findForName(name: String) =
+ formattingOverrides[name] ?: StatFormatting(name, "", Formatting.GREEN)
+
+ fun findForId(id: String) = findForName(statIdToName(id))
+
+ val allFormattingOverrides = listOf(
+ StatFormatting("Sea Creature Chance", "%", Formatting.RED),
+ StatFormatting("Strength", "", Formatting.RED),
+ StatFormatting("Damage", "", Formatting.RED),
+ StatFormatting("Bonus Attack Speed", "%", Formatting.RED),
+ StatFormatting("Shot Cooldown", "s", Formatting.GREEN, false),
+ StatFormatting("Ability Damage", "%", Formatting.RED),
+ StatFormatting("Crit Damage", "%", Formatting.RED),
+ StatFormatting("Crit Chance", "%", Formatting.RED),
+ StatFormatting("Ability Damage", "%", Formatting.RED),
+ StatFormatting("Trophy Fish Chance", "%", Formatting.GREEN),
+ StatFormatting("Health", "", Formatting.GREEN),
+ StatFormatting("Defense", "", Formatting.GREEN),
+ StatFormatting("Fishing Speed", "", Formatting.GREEN),
+ StatFormatting("Double Hook Chance", "%", Formatting.GREEN),
+ StatFormatting("Mining Speed", "", Formatting.GREEN),
+ StatFormatting("Mining Fortune", "", Formatting.GREEN),
+ StatFormatting("Heat Resistance", "", Formatting.GREEN),
+ StatFormatting("Swing Range", "", Formatting.GREEN),
+ StatFormatting("Rift Time", "", Formatting.GREEN),
+ StatFormatting("Speed", "", Formatting.GREEN),
+ StatFormatting("Farming Fortune", "", Formatting.GREEN),
+ StatFormatting("True Defense", "", Formatting.GREEN),
+ StatFormatting("Mending", "", Formatting.GREEN),
+ StatFormatting("Foraging Wisdom", "", Formatting.GREEN),
+ StatFormatting("Farming Wisdom", "", Formatting.GREEN),
+ StatFormatting("Foraging Fortune", "", Formatting.GREEN),
+ StatFormatting("Magic Find", "", Formatting.GREEN),
+ StatFormatting("Ferocity", "", Formatting.GREEN),
+ StatFormatting("Bonus Pest Chance", "%", Formatting.GREEN),
+ StatFormatting("Cold Resistance", "", Formatting.GREEN),
+ StatFormatting("Pet Luck", "", Formatting.GREEN),
+ StatFormatting("Fear", "", Formatting.GREEN),
+ StatFormatting("Mana Regen", "%", Formatting.GREEN),
+ StatFormatting("Rift Damage", "", Formatting.GREEN),
+ StatFormatting("Hearts", "", Formatting.GREEN),
+ StatFormatting("Vitality", "", Formatting.GREEN),
+ // TODO: make this a repo json
+ )
+ val formattingOverrides = allFormattingOverrides.associateBy { it.name }
+
+ }
+}
diff --git a/src/main/kotlin/util/skyblock/stats/StatLine.kt b/src/main/kotlin/util/skyblock/stats/StatLine.kt
new file mode 100644
index 0000000..5a1c236
--- /dev/null
+++ b/src/main/kotlin/util/skyblock/stats/StatLine.kt
@@ -0,0 +1,71 @@
+package moe.nea.firmament.util.skyblock.stats
+
+import moe.nea.firmament.util.FirmFormatters
+import moe.nea.firmament.util.grey
+import moe.nea.firmament.util.withColor
+import net.minecraft.text.Style
+import net.minecraft.text.Text
+import util.skyblock.stats.StatFormatting
+import net.minecraft.text.TextColor
+import net.minecraft.util.Formatting
+import moe.nea.firmament.util.directLiteralStringContent
+import moe.nea.firmament.util.useMatch
+
+data class StatLine(
+ val stat: StatFormatting,
+ val value: Double,
+ val modifiers: List<Text> = listOf(),
+ val loreIndex: Int = -1,
+) {
+ val statName get() = stat.name
+
+ fun formatValue() =
+ Text.literal(
+ FirmFormatters.formatCommas(value, 1, includeSign = true) + stat.postFix + " "
+ ).setStyle(Style.EMPTY.withColor(stat.color))
+
+ fun reconstitute(abbreviateTo: Int = Int.MAX_VALUE): Text =
+ Text.literal("").setStyle(Style.EMPTY.withItalic(false))
+ .append(Text.literal("${abbreviate(abbreviateTo)}: ").grey())
+ .append(formatValue())
+ .also { modifiers.forEach(it::append) }
+
+ /*
+ TODO: fix up the formatting of these
+ Expected: StatBlock(indexedByName={Speed=StatLine(stat=StatFormatting(name=Speed, postFix=, color=§a, isStarAffected=true), value=5.0, modifiers=[literal{(+5)}[style={color=blue}]], loreIndex=0), Foraging Wisdom=StatLine(stat=StatFormatting(name=Foraging Wisdom, postFix=, color=§a, isStarAffected=true), value=1.5, modifiers=[literal{(+1.5)}[style={color=blue}]], loreIndex=1)}, startIndex=0, endIndex=2, modifiedLines={})
+ Actual : StatBlock(indexedByName={Speed=StatLine(stat=StatFormatting(name=Speed, postFix=, color=§a, isStarAffected=true), value=5.0, modifiers=[literal{(+5) }[style={color=blue,!bold,!italic}]], loreIndex=0), Foraging Wisdom=StatLine(stat=StatFormatting(name=Foraging Wisdom, postFix=, color=§a, isStarAffected=true), value=1.2, modifiers=[literal{(+1.2) }[style={color=blue,!bold,!italic}]], loreIndex=1)}, startIndex=0, endIndex=2, modifiedLines={})*/
+ fun addStat(amount: Double, buffKind: BuffKind): StatLine {
+ val formattedAmount = FirmFormatters.formatCommas(amount, 1, includeSign = true)
+ val modifierText = Text.literal(
+ buffKind.prefix + formattedAmount + stat.postFix + buffKind.postFix + " ")
+ .withColor(buffKind.color)
+ return copy(
+ value = value + amount,
+ modifiers = modifiers +
+ if (buffKind.isHidden) emptyList()
+ else listOf(modifierText))
+ }
+
+ private fun abbreviate(abbreviateTo: Int): String {
+ if (abbreviateTo >= statName.length) return statName
+ val segments = statName.split(" ")
+ return segments.joinToString(" ") {
+ it.substring(0, maxOf(1, abbreviateTo / segments.size))
+ }
+ }
+
+ companion object {
+ private val statLabelRegex = "(?<statName>.*): ".toPattern()
+ fun fromLoreLine(line: Text): StatLine? {
+ val sibs = line.siblings
+ if (sibs.size < 2) return null
+ val stat = sibs.first() ?: return null
+ if (stat.style.color != TextColor.fromFormatting(Formatting.GRAY)) return null
+ val statLabel = stat.directLiteralStringContent ?: return null
+ val statName = statLabelRegex.useMatch(statLabel) { group("statName") } ?: return null
+ return StatLine(StatFormatting.findForName(statName),
+ sibs[1]?.directLiteralStringContent?.trim(' ', 's', '%', '+')?.toDoubleOrNull() ?: 0.0,
+ sibs.subList(2, sibs.size))
+ }
+ }
+}