WIP: Reforge Recipes
This commit is contained in:
@@ -29,18 +29,7 @@ object ItemRarityCosmetics : FirmamentFeature {
|
||||
override val config: ManagedConfig
|
||||
get() = TConfig
|
||||
|
||||
private val rarityToColor = mapOf(
|
||||
Rarity.COMMON to Formatting.WHITE,
|
||||
Rarity.UNCOMMON to Formatting.GREEN,
|
||||
Rarity.RARE to Formatting.BLUE,
|
||||
Rarity.EPIC to Formatting.DARK_PURPLE,
|
||||
Rarity.LEGENDARY to Formatting.GOLD,
|
||||
Rarity.MYTHIC to Formatting.LIGHT_PURPLE,
|
||||
Rarity.DIVINE to Formatting.AQUA,
|
||||
Rarity.SPECIAL to Formatting.RED,
|
||||
Rarity.VERY_SPECIAL to Formatting.RED,
|
||||
Rarity.SUPREME to Formatting.DARK_RED,
|
||||
).mapValues {
|
||||
private val rarityToColor = Rarity.colourMap.mapValues {
|
||||
val c = Color(it.value.colorValue!!)
|
||||
c.rgb
|
||||
}
|
||||
|
||||
@@ -111,8 +111,9 @@ object EntityRenderer {
|
||||
renderContext: DrawContext,
|
||||
posX: Int,
|
||||
posY: Int,
|
||||
mouseX: Float,
|
||||
mouseY: Float
|
||||
// TODO: Add width, height properties here
|
||||
mouseX: Double,
|
||||
mouseY: Double
|
||||
) {
|
||||
var bottomOffset = 0.0F
|
||||
var currentEntity = entity
|
||||
@@ -148,15 +149,15 @@ object EntityRenderer {
|
||||
y2: Int,
|
||||
size: Float,
|
||||
bottomOffset: Float,
|
||||
mouseX: Float,
|
||||
mouseY: Float,
|
||||
mouseX: Double,
|
||||
mouseY: Double,
|
||||
entity: LivingEntity
|
||||
) {
|
||||
context.enableScissorWithTranslation(x1.toFloat(), y1.toFloat(), x2.toFloat(), y2.toFloat())
|
||||
val centerX = (x1 + x2) / 2f
|
||||
val centerY = (y1 + y2) / 2f
|
||||
val targetYaw = atan(((centerX - mouseX) / 40.0f).toDouble()).toFloat()
|
||||
val targetPitch = atan(((centerY - mouseY) / 40.0f).toDouble()).toFloat()
|
||||
val targetYaw = atan(((centerX - mouseX) / 40.0f)).toFloat()
|
||||
val targetPitch = atan(((centerY - mouseY) / 40.0f)).toFloat()
|
||||
val rotateToFaceTheFront = Quaternionf().rotateZ(Math.PI.toFloat())
|
||||
val rotateToFaceTheCamera = Quaternionf().rotateX(targetPitch * 20.0f * (Math.PI.toFloat() / 180))
|
||||
rotateToFaceTheFront.mul(rotateToFaceTheCamera)
|
||||
|
||||
@@ -39,6 +39,7 @@ import moe.nea.firmament.util.TestUtil
|
||||
import moe.nea.firmament.util.directLiteralStringContent
|
||||
import moe.nea.firmament.util.mc.FirmamentDataComponentTypes
|
||||
import moe.nea.firmament.util.mc.appendLore
|
||||
import moe.nea.firmament.util.mc.displayNameAccordingToNbt
|
||||
import moe.nea.firmament.util.mc.loreAccordingToNbt
|
||||
import moe.nea.firmament.util.mc.modifyLore
|
||||
import moe.nea.firmament.util.mc.setCustomName
|
||||
@@ -131,6 +132,7 @@ object ItemCache : IReloadable {
|
||||
val itemInstance =
|
||||
ItemStack.fromNbt(MC.defaultRegistries, modernItemTag).getOrNull() ?: return brokenItemStack(this)
|
||||
itemInstance.loreAccordingToNbt = lore.map { un189Lore(it) }
|
||||
itemInstance.displayNameAccordingToNbt = un189Lore(displayName)
|
||||
val extraAttributes = oldItemTag.getCompound("tag").getCompound("ExtraAttributes")
|
||||
if (extraAttributes != null)
|
||||
itemInstance.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(extraAttributes))
|
||||
|
||||
@@ -108,6 +108,8 @@ data class Reforge(
|
||||
|
||||
@Serializable(with = RarityMapped.Serializer::class)
|
||||
sealed interface RarityMapped<T> {
|
||||
fun get(rarity: Rarity): T?
|
||||
|
||||
class Serializer<T>(
|
||||
val values: KSerializer<T>
|
||||
) : KSerializer<RarityMapped<T>> {
|
||||
@@ -137,10 +139,18 @@ data class Reforge(
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Direct<T>(val value: T) : RarityMapped<T>
|
||||
data class Direct<T>(val value: T) : RarityMapped<T> {
|
||||
override fun get(rarity: Rarity): T {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class PerRarity<T>(val values: Map<Rarity, T>) : RarityMapped<T>
|
||||
data class PerRarity<T>(val values: Map<Rarity, T>) : RarityMapped<T> {
|
||||
override fun get(rarity: Rarity): T? {
|
||||
return values[rarity]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,22 +9,31 @@ import net.minecraft.item.ItemStack
|
||||
import net.minecraft.network.RegistryByteBuf
|
||||
import net.minecraft.network.codec.PacketCodec
|
||||
import net.minecraft.network.codec.PacketCodecs
|
||||
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.ItemCache.asItemStack
|
||||
import moe.nea.firmament.util.FirmFormatters
|
||||
import moe.nea.firmament.util.LegacyFormattingCode
|
||||
import moe.nea.firmament.util.ReforgeId
|
||||
import moe.nea.firmament.util.SkyblockId
|
||||
import moe.nea.firmament.util.blue
|
||||
import moe.nea.firmament.util.directLiteralStringContent
|
||||
import moe.nea.firmament.util.extraAttributes
|
||||
import moe.nea.firmament.util.getReforgeId
|
||||
import moe.nea.firmament.util.getUpgradeStars
|
||||
import moe.nea.firmament.util.grey
|
||||
import moe.nea.firmament.util.mc.appendLore
|
||||
import moe.nea.firmament.util.mc.displayNameAccordingToNbt
|
||||
import moe.nea.firmament.util.mc.loreAccordingToNbt
|
||||
import moe.nea.firmament.util.petData
|
||||
import moe.nea.firmament.util.prepend
|
||||
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.skyblockId
|
||||
import moe.nea.firmament.util.useMatch
|
||||
import moe.nea.firmament.util.withColor
|
||||
|
||||
data class SBItemStack constructor(
|
||||
@@ -84,6 +93,117 @@ data class SBItemStack constructor(
|
||||
}
|
||||
return SBItemStack(neuIngredient.skyblockId, neuIngredient.amount.toInt())
|
||||
}
|
||||
|
||||
fun appendEnhancedStats(
|
||||
itemStack: ItemStack,
|
||||
reforgeStats: Map<String, Double>,
|
||||
buffKind: BuffKind,
|
||||
) {
|
||||
val namedReforgeStats = reforgeStats
|
||||
.mapKeysTo(mutableMapOf()) { statIdToName(it.key) }
|
||||
val loreMut = itemStack.loreAccordingToNbt.toMutableList()
|
||||
var statBlockLastIndex = -1
|
||||
for (i in loreMut.indices) {
|
||||
val statLine = parseStatLine(loreMut[i])
|
||||
if (statLine == null && statBlockLastIndex >= 0) {
|
||||
break
|
||||
}
|
||||
if (statLine == null) {
|
||||
continue
|
||||
}
|
||||
statBlockLastIndex = i
|
||||
val statBuff = namedReforgeStats.remove(statLine.statName) ?: continue
|
||||
loreMut[i] = statLine.addStat(statBuff, buffKind).reconstitute()
|
||||
}
|
||||
if (namedReforgeStats.isNotEmpty() && statBlockLastIndex == -1) {
|
||||
loreMut.add(0, Text.literal(""))
|
||||
}
|
||||
// If there is no stat block the statBlockLastIndex falls through to -1
|
||||
// TODO: this is good enough for some items. some other items might have their stats at a different place.
|
||||
for ((statName, statBuff) in namedReforgeStats) {
|
||||
val statLine = StatLine(statName, null).addStat(statBuff, buffKind)
|
||||
loreMut.add(statBlockLastIndex + 1, statLine.reconstitute())
|
||||
}
|
||||
itemStack.loreAccordingToNbt = loreMut
|
||||
}
|
||||
|
||||
data class StatFormatting(
|
||||
val postFix: String,
|
||||
val color: Formatting,
|
||||
)
|
||||
|
||||
val formattingOverrides = mapOf(
|
||||
"Sea Creature Chance" to StatFormatting("%", Formatting.RED),
|
||||
"Strength" to StatFormatting("", Formatting.RED),
|
||||
"Damage" to StatFormatting("", Formatting.RED),
|
||||
"Bonus Attack Speed" to StatFormatting("%", Formatting.RED),
|
||||
"Shot Cooldown" to StatFormatting("s", Formatting.RED),
|
||||
"Ability Damage" to StatFormatting("%", Formatting.RED),
|
||||
"Crit Damage" to StatFormatting("%", Formatting.RED),
|
||||
"Crit Chance" to StatFormatting("%", Formatting.RED),
|
||||
"Trophy Fish Chance" to StatFormatting("%", Formatting.GREEN),
|
||||
// TODO: add other types and make this a repo json
|
||||
)
|
||||
|
||||
|
||||
private val statLabelRegex = "(?<statName>.*): ".toPattern()
|
||||
|
||||
enum class BuffKind(
|
||||
val color: Formatting,
|
||||
val prefix: String,
|
||||
val postFix: String,
|
||||
) {
|
||||
REFORGE(Formatting.BLUE, "(", ")"),
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
data class StatLine(
|
||||
val statName: String,
|
||||
val value: Text?,
|
||||
val rest: List<Text> = listOf(),
|
||||
val valueNum: Double? = value?.directLiteralStringContent?.trim(' ', '%', '+')?.toDoubleOrNull()
|
||||
) {
|
||||
fun addStat(amount: Double, buffKind: BuffKind): StatLine {
|
||||
val formattedAmount = FirmFormatters.formatCommas(amount, 1, includeSign = true)
|
||||
return copy(
|
||||
valueNum = (valueNum ?: 0.0) + amount,
|
||||
value = null,
|
||||
rest = rest +
|
||||
listOf(
|
||||
Text.literal(
|
||||
buffKind.prefix + formattedAmount +
|
||||
statFormatting.postFix +
|
||||
buffKind.postFix + " ")
|
||||
.withColor(buffKind.color)))
|
||||
}
|
||||
|
||||
fun formatValue() =
|
||||
Text.literal(FirmFormatters.formatCommas(valueNum ?: 0.0, 1, includeSign = true) + statFormatting.postFix + " ")
|
||||
.setStyle(Style.EMPTY.withColor(statFormatting.color))
|
||||
|
||||
val statFormatting = formattingOverrides[statName] ?: StatFormatting("", Formatting.GREEN)
|
||||
fun reconstitute(): Text =
|
||||
Text.literal("").setStyle(Style.EMPTY.withItalic(false))
|
||||
.append(Text.literal("$statName: ").grey())
|
||||
.append(value ?: formatValue())
|
||||
.also { rest.forEach(it::append) }
|
||||
}
|
||||
|
||||
private fun statIdToName(statId: String): String {
|
||||
return statId.split("_").joinToString(" ") {
|
||||
it.replaceFirstChar { it.uppercaseChar() }
|
||||
}
|
||||
}
|
||||
|
||||
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(statName, sibs[1], sibs.subList(2, sibs.size))
|
||||
}
|
||||
}
|
||||
|
||||
constructor(skyblockId: SkyblockId, petData: PetData) : this(
|
||||
@@ -134,11 +254,19 @@ data class SBItemStack constructor(
|
||||
}
|
||||
|
||||
|
||||
private fun appendReforgeStatsToLore(
|
||||
private fun appendReforgeInfo(
|
||||
itemStack: ItemStack,
|
||||
) {
|
||||
val rarity = itemStack.rarity
|
||||
val lore = itemStack.loreAccordingToNbt
|
||||
val rarity = Rarity.fromItem(itemStack) ?: return
|
||||
val reforgeId = this.reforge ?: return
|
||||
val reforge = ReforgeStore.modifierLut[reforgeId] ?: return
|
||||
val reforgeStats = reforge.reforgeStats?.get(rarity) ?: mapOf()
|
||||
itemStack.displayNameAccordingToNbt = itemStack.displayNameAccordingToNbt.copy()
|
||||
.prepend(Text.literal(reforge.reforgeName + " ").formatted(Rarity.colourMap[rarity] ?: Formatting.WHITE))
|
||||
val data = itemStack.extraAttributes.copy()
|
||||
data.putString("modifier", reforgeId.id)
|
||||
itemStack.extraAttributes = data
|
||||
appendEnhancedStats(itemStack, reforgeStats, BuffKind.REFORGE)
|
||||
}
|
||||
|
||||
// TODO: avoid instantiating the item stack here
|
||||
@@ -156,8 +284,8 @@ data class SBItemStack constructor(
|
||||
injectReplacementDataForPets(replacementData)
|
||||
return@run neuItem.asItemStack(idHint = skyblockId, replacementData)
|
||||
.copyWithCount(stackSize)
|
||||
.also { appendReforgeInfo(it) }
|
||||
.also { it.appendLore(extraLore) }
|
||||
.also { if (reforge != null) it.appendLore(listOf(Text.literal("Reforge: $reforge"))) } // TODO: use this for proper rendering
|
||||
.also { enhanceStatsByStars(it, stars) }
|
||||
}
|
||||
if (itemStack_ == null)
|
||||
|
||||
10
src/main/kotlin/util/AprilFoolsUtil.kt
Normal file
10
src/main/kotlin/util/AprilFoolsUtil.kt
Normal file
@@ -0,0 +1,10 @@
|
||||
package moe.nea.firmament.util
|
||||
|
||||
import java.time.LocalDateTime
|
||||
import java.time.Month
|
||||
|
||||
object AprilFoolsUtil {
|
||||
val isAprilFoolsDay = LocalDateTime.now().let {
|
||||
it.dayOfMonth == 1 && it.month == Month.APRIL
|
||||
}
|
||||
}
|
||||
@@ -15,21 +15,25 @@ import net.minecraft.text.Text
|
||||
|
||||
object FirmFormatters {
|
||||
fun formatCommas(int: Int, segments: Int = 3): String = formatCommas(int.toLong(), segments)
|
||||
fun formatCommas(long: Long, segments: Int = 3): String {
|
||||
fun formatCommas(long: Long, segments: Int = 3, includeSign: Boolean = false): String {
|
||||
if (long < 0 && long != Long.MIN_VALUE) {
|
||||
return "-" + formatCommas(-long, segments, false)
|
||||
}
|
||||
val prefix = if (includeSign) "+" else ""
|
||||
val α = long / 1000
|
||||
if (α != 0L) {
|
||||
return formatCommas(α, segments) + "," + (long - α * 1000).toString().padStart(3, '0')
|
||||
return prefix + formatCommas(α, segments) + "," + (long - α * 1000).toString().padStart(3, '0')
|
||||
}
|
||||
return long.toString()
|
||||
return prefix + long.toString()
|
||||
}
|
||||
|
||||
fun formatCommas(float: Float, fractionalDigits: Int): String = formatCommas(float.toDouble(), fractionalDigits)
|
||||
fun formatCommas(double: Double, fractionalDigits: Int): String {
|
||||
fun formatCommas(double: Double, fractionalDigits: Int, includeSign: Boolean = false): String {
|
||||
val long = double.toLong()
|
||||
val δ = (double - long).absoluteValue
|
||||
val μ = pow(10, fractionalDigits)
|
||||
val digits = (μ * δ).toInt().toString().padStart(fractionalDigits, '0').trimEnd('0')
|
||||
return formatCommas(long) + (if (digits.isEmpty()) "" else ".$digits")
|
||||
return formatCommas(long, includeSign = includeSign) + (if (digits.isEmpty()) "" else ".$digits")
|
||||
}
|
||||
|
||||
fun formatDistance(distance: Double): String {
|
||||
|
||||
@@ -106,7 +106,10 @@ data class HypixelPetInfo(
|
||||
|
||||
private val jsonparser = Json { ignoreUnknownKeys = true }
|
||||
|
||||
val ItemStack.extraAttributes: NbtCompound
|
||||
var ItemStack.extraAttributes: NbtCompound
|
||||
set(value) {
|
||||
set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(value))
|
||||
}
|
||||
get() {
|
||||
val customData = get(DataComponentTypes.CUSTOM_DATA) ?: run {
|
||||
val component = NbtComponent.of(NbtCompound())
|
||||
|
||||
@@ -5,8 +5,8 @@ import net.minecraft.component.type.LoreComponent
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.text.Text
|
||||
|
||||
var ItemStack.loreAccordingToNbt
|
||||
get() = get(DataComponentTypes.LORE)?.lines ?: listOf()
|
||||
var ItemStack.loreAccordingToNbt: List<Text>
|
||||
get() = get(DataComponentTypes.LORE)?.lines ?: listOf()
|
||||
set(value) {
|
||||
set(DataComponentTypes.LORE, LoreComponent(value))
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.text.Style
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Formatting
|
||||
import moe.nea.firmament.util.StringUtil.words
|
||||
import moe.nea.firmament.util.collections.lastNotNullOfOrNull
|
||||
import moe.nea.firmament.util.mc.loreAccordingToNbt
|
||||
@@ -46,10 +48,23 @@ enum class Rarity(vararg altNames: String) {
|
||||
}
|
||||
|
||||
val names = setOf(name) + altNames
|
||||
|
||||
val text: Text get() = Text.literal(name).setStyle(Style.EMPTY.withColor(colourMap[this]))
|
||||
val neuRepoRarity: RepoRarity? = RepoRarity.entries.find { it.name == name }
|
||||
|
||||
companion object {
|
||||
// TODO: inline those formattings as fields
|
||||
val colourMap = mapOf(
|
||||
Rarity.COMMON to Formatting.WHITE,
|
||||
Rarity.UNCOMMON to Formatting.GREEN,
|
||||
Rarity.RARE to Formatting.BLUE,
|
||||
Rarity.EPIC to Formatting.DARK_PURPLE,
|
||||
Rarity.LEGENDARY to Formatting.GOLD,
|
||||
Rarity.MYTHIC to Formatting.LIGHT_PURPLE,
|
||||
Rarity.DIVINE to Formatting.AQUA,
|
||||
Rarity.SPECIAL to Formatting.RED,
|
||||
Rarity.VERY_SPECIAL to Formatting.RED,
|
||||
Rarity.SUPREME to Formatting.DARK_RED,
|
||||
)
|
||||
val byName = entries.flatMap { en -> en.names.map { it to en } }.toMap()
|
||||
val fromNeuRepo = entries.associateBy { it.neuRepoRarity }
|
||||
|
||||
|
||||
@@ -7,4 +7,5 @@ object SkyBlockItems {
|
||||
val ENCHANTED_DIAMOND = SkyblockId("ENCHANTED_DIAMOND")
|
||||
val DIAMOND = SkyblockId("DIAMOND")
|
||||
val ANCESTRAL_SPADE = SkyblockId("ANCESTRAL_SPADE")
|
||||
val REFORGE_ANVIL = SkyblockId("REFORGE_ANVIL")
|
||||
}
|
||||
|
||||
@@ -133,6 +133,7 @@ fun MutableText.darkGreen() = withColor(Formatting.DARK_GREEN)
|
||||
fun MutableText.purple() = withColor(Formatting.DARK_PURPLE)
|
||||
fun MutableText.pink() = withColor(Formatting.LIGHT_PURPLE)
|
||||
fun MutableText.yellow() = withColor(Formatting.YELLOW)
|
||||
fun MutableText.gold() = withColor(Formatting.GOLD)
|
||||
fun MutableText.grey() = withColor(Formatting.GRAY)
|
||||
fun MutableText.red() = withColor(Formatting.RED)
|
||||
fun MutableText.white() = withColor(Formatting.WHITE)
|
||||
@@ -146,6 +147,11 @@ fun MutableText.clickCommand(command: String): MutableText {
|
||||
}
|
||||
}
|
||||
|
||||
fun MutableText.prepend(text: Text): MutableText {
|
||||
siblings.addFirst(text)
|
||||
return this
|
||||
}
|
||||
|
||||
fun Text.transformEachRecursively(function: (Text) -> Text): Text {
|
||||
val c = this.content
|
||||
if (c is TranslatableTextContent) {
|
||||
|
||||
Reference in New Issue
Block a user