aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/kotlin/features/inventory/PetFeatures.kt535
1 files changed, 489 insertions, 46 deletions
diff --git a/src/main/kotlin/features/inventory/PetFeatures.kt b/src/main/kotlin/features/inventory/PetFeatures.kt
index 965e705..cdac6a0 100644
--- a/src/main/kotlin/features/inventory/PetFeatures.kt
+++ b/src/main/kotlin/features/inventory/PetFeatures.kt
@@ -1,24 +1,39 @@
package moe.nea.firmament.features.inventory
+import java.util.regex.Matcher
import org.joml.Vector2i
+import net.minecraft.entity.player.PlayerInventory
import net.minecraft.item.ItemStack
import net.minecraft.text.Text
import net.minecraft.util.Formatting
+import net.minecraft.util.StringIdentifiable
import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HudRenderEvent
+import moe.nea.firmament.events.ProcessChatEvent
+import moe.nea.firmament.events.SlotClickEvent
import moe.nea.firmament.events.SlotRenderEvents
import moe.nea.firmament.jarvis.JarvisIntegration
+import moe.nea.firmament.repo.ExpLadders
+import moe.nea.firmament.repo.ExpensiveItemCacheApi
+import moe.nea.firmament.repo.ItemCache.asItemStack
+import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.FirmFormatters.formatPercent
import moe.nea.firmament.util.FirmFormatters.shortFormat
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SBData
+import moe.nea.firmament.util.SkyBlockIsland
import moe.nea.firmament.util.data.Config
import moe.nea.firmament.util.data.ManagedConfig
+import moe.nea.firmament.util.formattedString
+import moe.nea.firmament.util.parseShortNumber
import moe.nea.firmament.util.petData
import moe.nea.firmament.util.render.drawGuiTexture
import moe.nea.firmament.util.skyblock.Rarity
+import moe.nea.firmament.util.skyblock.TabListAPI
+import moe.nea.firmament.util.skyblockUUID
import moe.nea.firmament.util.titleCase
+import moe.nea.firmament.util.unformattedString
import moe.nea.firmament.util.useMatch
import moe.nea.firmament.util.withColor
@@ -29,82 +44,510 @@ object PetFeatures {
@Config
object TConfig : ManagedConfig(identifier, Category.INVENTORY) {
val highlightEquippedPet by toggle("highlight-pet") { true }
- var petOverlay by toggle("pet-overlay") { false }
+ val petOverlay by toggle("pet-overlay") { false }
val petOverlayHud by position("pet-overlay-hud", 80, 10) {
Vector2i()
}
+ val petOverlayHudStyle by choice("pet-overlay-hud-style") { PetOverlayHudStyles.PLAIN_NO_BACKGROUND }
}
- val petMenuTitle = "Pets(?: \\([0-9]+/[0-9]+\\))?".toPattern()
- var petItemStack: ItemStack? = null
+ enum class PetOverlayHudStyles : StringIdentifiable {
+ PLAIN_NO_BACKGROUND,
+ COLOUR_NO_BACKGROUND,
+ PLAIN_BACKGROUND,
+ COLOUR_BACKGROUND,
+ ICON_ONLY;
+
+ override fun asString() : String {
+ return name
+ }
+ }
+
+ private val petMenuTitle = "Pets(?: \\([0-9]+/[0-9]+\\))?".toPattern()
+ private val autopetPattern =
+ "§cAutopet §eequipped your §7\\[Lvl (\\d{1,3})\\] §([fa956d])([\\w\\s]+)§e! §aVIEW RULE".toPattern()
+ private val petItemPattern = "§aYour pet is now holding (§[fa956d][\\w\\s]+)§a.".toPattern()
+ private val petLevelUpPattern = "§aYour §([fa956d])([\\w\\s]+) §aleveled up to level §9(\\d+)§a!".toPattern()
+ private val petMap = HashMap<String, ParsedPet>()
+ private var currentPetUUID: String = ""
+ private var tempTabPet: ParsedPet? = null
+ private var tempChatPet: ParsedPet? = null
@Subscribe
fun onSlotRender(event: SlotRenderEvents.Before) {
- if (!TConfig.highlightEquippedPet) return
- val stack = event.slot.stack
- if (stack.petData?.active == true)
- petMenuTitle.useMatch(MC.screenName ?: return) {
- petItemStack = stack
+ // Cache pets
+ petMenuTitle.useMatch(MC.screenName ?: return) {
+ val stack = event.slot.stack
+ if (!stack.isEmpty) cachePet(stack)
+ if (stack.petData?.active == true) {
+ if (currentPetUUID == "") currentPetUUID = stack.skyblockUUID.toString()
+ // Highlight active pet feature
+ if (!TConfig.highlightEquippedPet) return
event.context.drawGuiTexture(
Firmament.identifier("selected_pet_background"),
event.slot.x, event.slot.y, 16, 16,
)
}
+ }
+ }
+
+ private fun cachePet(stack: ItemStack) {
+ // Cache information about a pet
+ if (stack.skyblockUUID == null) return
+ if (petMap.containsKey(stack.skyblockUUID.toString()) &&
+ petMap[stack.skyblockUUID.toString()]?.isComplete == true) return
+
+ val pet = PetParser.parsePetMenuSlot(stack) ?: return
+ petMap[stack.skyblockUUID.toString()] = pet
+ }
+
+ @Subscribe
+ fun onSlotClick(event: SlotClickEvent) {
+ // Check for switching/removing pet manually
+ petMenuTitle.useMatch(MC.screenName ?: return) {
+ if (event.slot.inventory is PlayerInventory) return
+ if (event.button != 0 && event.button != 1) return
+ val petData = event.stack.petData ?: return
+ if (petData.active == true) {
+ currentPetUUID = "None"
+ return
+ }
+ if (event.button != 0) return
+ if (!petMap.containsKey(event.stack.skyblockUUID.toString())) cachePet(event.stack)
+ currentPetUUID = event.stack.skyblockUUID.toString()
+ }
+ }
+
+ @Subscribe
+ fun onChatEvent(event: ProcessChatEvent) {
+ println("^^^" + event.text.formattedString() + "$$$")
+ // Handle AutoPet
+ var matcher = autopetPattern.matcher(event.text.formattedString())
+ if (matcher.matches()) {
+ val tempMap = petMap.filter { (uuid, pet) ->
+ pet.name == matcher.group(3) &&
+ pet.rarity == PetParser.reversePetColourMap[matcher.group(2)] &&
+ pet.level <= matcher.group(1).toInt()
+ }
+ if (tempMap.isNotEmpty()) {
+ currentPetUUID = tempMap.keys.first()
+ } else {
+ tempChatPet = PetParser.parsePetChatMessage(matcher.group(3), matcher.group(2), matcher.group(1).toInt())
+ currentPetUUID = ""
+ }
+ tempTabPet = null
+ return
+ }
+ // Handle changing pet item
+ // This is needed for when pet item can't be found in tab list
+ matcher = petItemPattern.matcher(event.text.formattedString())
+ if (matcher.matches()) {
+ petMap[currentPetUUID]?.petItem = matcher.group(1)
+ tempTabPet?.petItem = matcher.group(1)
+ tempChatPet?.petItem = matcher.group(1)
+ // TODO: Handle tier boost pet items if required
+ // I'm not rich enough to be able to test tier boosts
+ }
+ // Handle pet levelling up
+ // This is needed for when pet level can't be found in tab list
+ matcher = petLevelUpPattern.matcher(event.text.formattedString())
+ if (matcher.matches()) {
+ val tempPet =
+ PetParser.parsePetChatMessage(matcher.group(2), matcher.group(1), matcher.group(3).toInt()) ?: return
+ val tempMap = petMap.filter { (uuid, pet) ->
+ pet.name == tempPet.name &&
+ pet.rarity == tempPet.rarity &&
+ pet.level <= tempPet.level
+ }
+ if (tempMap.isNotEmpty()) petMap[tempMap.keys.first()]?.update(tempPet)
+ if (tempTabPet?.name == tempPet.name && tempTabPet?.rarity == tempPet.rarity) {
+ tempTabPet?.update(tempPet)
+ }
+ if (tempChatPet?.name == tempPet.name && tempChatPet?.rarity == tempPet.rarity) tempChatPet?.update(tempPet)
+ }
+ }
+
+ private fun renderLinesAndBackground(it: HudRenderEvent, lines: List<Text>) {
+ // Render background for the hud
+ if (TConfig.petOverlayHudStyle == PetOverlayHudStyles.PLAIN_BACKGROUND ||
+ TConfig.petOverlayHudStyle == PetOverlayHudStyles.COLOUR_BACKGROUND) {
+ var maxWidth = 0
+ lines.forEach { if (MC.font.getWidth(it) > maxWidth) maxWidth = MC.font.getWidth(it.unformattedString) }
+ val height = if (MC.font.fontHeight * lines.size > 32) MC.font.fontHeight * lines.size else 32
+ it.context.fill(0, -3, 40 + maxWidth, height + 2, 0x80000000.toInt())
+ }
+
+ // Render text for the hud
+ lines.forEachIndexed { index, line ->
+ it.context.drawText(
+ MC.font,
+ line.copy().withColor(Formatting.GRAY),
+ 36,
+ MC.font.fontHeight * index,
+ -1,
+ true
+ )
+ }
}
@Subscribe
fun onRenderHud(it: HudRenderEvent) {
if (!TConfig.petOverlay || !SBData.isOnSkyblock) return
- val itemStack = petItemStack ?: return
- val petData = petItemStack?.petData ?: return
- val rarity = Rarity.fromNeuRepo(petData.tier)
- val rarityCode = Rarity.colourMap[rarity] ?: Formatting.WHITE
- val xp = petData.level
- val petType = titleCase(petData.type)
- val heldItem = petData.heldItem?.let { item -> "Held Item: ${titleCase(item)}" }
+
+ // Possibly handle Montezuma as a future feature? Could track how many pieces have been found etc
+ // Would likely need to be a separate config toggle though since that has
+ // very different usefulness/purpose to the pet hud outside of rift
+ if (SBData.skyblockLocation == SkyBlockIsland.RIFT) return
+
+ // Initial data
+ var pet: ParsedPet? = null
+ // Do not render the HUD if there is no pet active
+ if (currentPetUUID == "None") return
+ // Get active pet from cache
+ if (currentPetUUID != "") pet = petMap[currentPetUUID]
+ // Parse tab widget for pet data
+ val tabPet = PetParser.parseTabWidget(TabListAPI.getWidgetLines(TabListAPI.WidgetName.PET))
+ if (pet == null && tabPet == null && tempTabPet == null && tempChatPet == null) {
+ // No data on current pet
+ it.context.matrices.pushMatrix()
+ TConfig.petOverlayHud.applyTransformations(JarvisIntegration.jarvis, it.context.matrices)
+ val lines = mutableListOf<Text>()
+ lines.add(Text.literal("" + Formatting.WHITE + "Unknown Pet"))
+ lines.add(Text.literal("Open Pets Menu To Fix"))
+ renderLinesAndBackground(it, lines)
+ it.context.matrices.popMatrix()
+ return
+ }
+ if (pet == null) {
+ // Pet is only known through tab widget or chat message, potentially saved from tab widget elsewhere
+ // (e.g. another server or before removing the widget from the tab list)
+ pet = tabPet ?: tempTabPet ?: tempChatPet ?: return
+ if (tempTabPet == null) tempTabPet = tabPet
+ }
+
+ // Update pet based on tab widget if needed
+ if (tabPet != null && pet.name == tabPet.name && pet.rarity == tabPet.rarity) {
+ if (tabPet.level > pet.level) {
+ // Level has increased since caching
+ pet.level = tabPet.level
+ pet.currentExp = tabPet.currentExp
+ pet.expForNextLevel = tabPet.expForNextLevel
+ pet.totalExp = tabPet.totalExp
+ } else if (tabPet.currentExp > pet.currentExp) {
+ // Exp has increased since caching, level has not
+ pet.currentExp = tabPet.currentExp
+ pet.totalExp = tabPet.totalExp
+ }
+ if (tabPet.petItem != pet.petItem && tabPet.petItem != "Unknown") {
+ // Pet item has changed since caching
+ pet.petItem = tabPet.petItem
+ pet.petItemStack = tabPet.petItemStack
+ }
+ }
+
+ // Set the text for the HUD
+
+ val lines = mutableListOf<Text>()
+
+ if (TConfig.petOverlayHudStyle == PetOverlayHudStyles.COLOUR_NO_BACKGROUND ||
+ TConfig.petOverlayHudStyle == PetOverlayHudStyles.COLOUR_BACKGROUND) {
+ // Colour Style
+ lines.add(Text.literal("[Lvl ${pet.level}] ").append(Text.literal(pet.name)
+ .withColor((Rarity.colourMap[pet.rarity]) ?: Formatting.WHITE)))
+
+ lines.add(Text.literal(pet.petItem))
+ if (pet.level != pet.maxLevel) {
+ // Exp data
+ lines.add(
+ Text.literal(
+ "" + Formatting.YELLOW + "Required L${pet.level + 1}: ${shortFormat(pet.currentExp)}" +
+ Formatting.GOLD + "/" + Formatting.YELLOW +
+ "${shortFormat(pet.expForNextLevel)} " + Formatting.GOLD +
+ "(${formatPercent(pet.currentExp / pet.expForNextLevel)})"
+ )
+ )
+ lines.add(
+ Text.literal(
+ "" + Formatting.YELLOW + "Required L100: ${shortFormat(pet.totalExp)}" +
+ Formatting.GOLD + "/" + Formatting.YELLOW +
+ "${shortFormat(pet.expForMax)} " + Formatting.GOLD +
+ "(${formatPercent(pet.totalExp / pet.expForMax)})"
+ )
+ )
+ } else {
+ // Overflow Exp data
+ lines.add(Text.literal(
+ "" + Formatting.AQUA + Formatting.BOLD + "MAX LEVEL"
+ ))
+ lines.add(Text.literal(
+ "" + Formatting.GOLD + "+" + Formatting.YELLOW + "${shortFormat(pet.overflowExp)} XP"
+ ))
+ }
+ } else if (TConfig.petOverlayHudStyle == PetOverlayHudStyles.PLAIN_NO_BACKGROUND ||
+ TConfig.petOverlayHudStyle == PetOverlayHudStyles.PLAIN_BACKGROUND) {
+ // Plain Style
+ lines.add(Text.literal("[Lvl ${pet.level}] ").append(Text.literal(pet.name)
+ .withColor((Rarity.colourMap[pet.rarity]) ?: Formatting.WHITE)))
+
+ lines.add(Text.literal(if (pet.petItem != "None" && pet.petItem != "Unknown")
+ pet.petItem.substring(2) else pet.petItem))
+ if (pet.level != pet.maxLevel) {
+ // Exp data
+ lines.add(
+ Text.literal(
+ "Required L${pet.level + 1}: ${shortFormat(pet.currentExp)}/" +
+ "${shortFormat(pet.expForNextLevel)} " +
+ "(${formatPercent(pet.currentExp / pet.expForNextLevel)})"
+ )
+ )
+ lines.add(
+ Text.literal(
+ "Required L100: ${shortFormat(pet.totalExp)}/${shortFormat(pet.expForMax)} " +
+ "(${formatPercent(pet.totalExp / pet.expForMax)})"
+ )
+ )
+ } else {
+ // Overflow Exp data
+ lines.add(Text.literal(
+ "MAX LEVEL"
+ ))
+ lines.add(Text.literal(
+ "+${shortFormat(pet.overflowExp)} XP"
+ ))
+ }
+ }
+
+ // Render HUD
it.context.matrices.pushMatrix()
TConfig.petOverlayHud.applyTransformations(JarvisIntegration.jarvis, it.context.matrices)
- val lines = mutableListOf<Text>()
+ renderLinesAndBackground(it, lines)
+
+ // Draw the ItemStack
it.context.matrices.pushMatrix()
it.context.matrices.translate(-0.5F, -0.5F)
it.context.matrices.scale(2f, 2f)
- it.context.drawItem(itemStack, 0, 0)
+ it.context.drawItem(pet.petItemStack.value, 0, 0)
it.context.matrices.popMatrix()
- lines.add(Text.literal("[Lvl ${xp.currentLevel}] ").append(Text.literal(petType).withColor(rarityCode)))
- if (heldItem != null) lines.add(Text.literal(heldItem))
- if (xp.currentLevel != xp.maxLevel) lines.add(
- Text.literal(
- "Required L${xp.currentLevel + 1}: ${shortFormat(xp.expInCurrentLevel.toDouble())}/${
- shortFormat(
- xp.expRequiredForNextLevel.toDouble()
- )
- } (${formatPercent(xp.percentageToNextLevel.toDouble())})"
- )
- )
- lines.add(
- Text.literal(
- "Required L100: ${shortFormat(xp.expTotal.toDouble())}/${shortFormat(xp.expRequiredForMaxLevel.toDouble())} (${
- formatPercent(
- xp.percentageToMaxLevel.toDouble()
- )
- })"
- )
+ it.context.matrices.popMatrix()
+ }
+}
+
+object PetParser {
+ private val petNamePattern = " §7\\[Lvl (\\d{1,3})] §([fa956d])([\\w\\s]+)".toPattern()
+ private val petItemPattern = " (§[fa956dbc4][\\s\\w]+)".toPattern()
+ private val petExpPattern = " §e((?:\\d{1,3}[,.]?)+\\d*[kM]?)§6\\/§e((?:\\d{1,3}[,.]?)+\\d*[kM]?) XP §6\\(\\d+(?:.\\d+)?%\\)".toPattern()
+ private val petOverflowExpPattern = " §6\\+§e((?:\\d{1,3}[,.])+\\d*[kM]?) XP".toPattern()
+ private val katPattern = " Kat:.*".toPattern()
+
+ val reversePetColourMap = mapOf(
+ "f" to Rarity.COMMON,
+ "a" to Rarity.UNCOMMON,
+ "9" to Rarity.RARE,
+ "5" to Rarity.EPIC,
+ "6" to Rarity.LEGENDARY,
+ "d" to Rarity.MYTHIC
+ )
+
+ val found = HashMap<String, Matcher>()
+
+ @OptIn(ExpensiveItemCacheApi::class)
+ fun parsePetChatMessage(name: String, rarityCode: String, level: Int) : ParsedPet? {
+ val petId = name.uppercase().replace(" ", "_")
+ val petRarity = reversePetColourMap[rarityCode] ?: Rarity.COMMON
+
+ val neuRarity = petRarity.neuRepoRarity ?: return null
+ val expLadder = ExpLadders.getExpLadder(petId, neuRarity)
+
+ var currentExp = 0.0
+ val expForNextLevel: Double
+ if (found.containsKey("exp")) {
+ currentExp = parseShortNumber(found.getValue("exp").group(1))
+ expForNextLevel = parseShortNumber(found.getValue("exp").group(2))
+ } else {
+ expForNextLevel = expLadder.getPetExpForLevel(level + 1).toDouble() -
+ expLadder.getPetExpForLevel(level).toDouble()
+ }
+
+ val totalExpBeforeLevel = expLadder.getPetExpForLevel(level).toDouble()
+ val totalExp = totalExpBeforeLevel + currentExp
+ val maxLevel = RepoManager.neuRepo.constants.petLevelingData.petLevelingBehaviourOverrides[petId]?.maxLevel ?: 100
+ val expForMax = expLadder.getPetExpForLevel(maxLevel).toDouble()
+ val petItemStack = lazy { RepoManager.neuRepo.items.items[petId + ";" + petRarity.ordinal].asItemStack() }
+
+ return ParsedPet(
+ name,
+ petRarity,
+ level,
+ -1,
+ expLadder,
+ currentExp,
+ expForNextLevel,
+ totalExp,
+ totalExpBeforeLevel,
+ expForMax,
+ 0.0,
+ "Unknown",
+ petItemStack,
+ false
)
+ }
- for ((index, line) in lines.withIndex()) {
- it.context.drawText(
- MC.font,
- line.copy().withColor(Formatting.GRAY),
- 36,
- MC.font.fontHeight * index,
- -1,
- true
- )
+ @OptIn(ExpensiveItemCacheApi::class)
+ fun parseTabWidget(lines: List<Text>): ParsedPet? {
+ found.clear()
+ for (line in lines.reversed()) {
+ if (!found.containsKey("kat")) {
+ val matcher = katPattern.matcher(line.formattedString())
+ if (matcher.matches()) {
+ found["kat"] = matcher
+ continue
+ }
+ }
+ if (!found.containsKey("exp")) {
+ val matcher = petExpPattern.matcher(line.formattedString())
+ if (matcher.matches()) {
+ found["exp"] = matcher
+ continue
+ }
+ }
+ if (!found.containsKey("exp")) {
+ val matcher = petOverflowExpPattern.matcher(line.formattedString())
+ if (matcher.matches()) {
+ found["overflow"] = matcher
+ continue
+ }
+ }
+ if (!found.containsKey("item")) {
+ val matcher = petItemPattern.matcher(line.formattedString())
+ if (matcher.matches()) {
+ found["item"] = matcher
+ continue
+ }
+ }
+ if (!found.containsKey("name")) {
+ val matcher = petNamePattern.matcher(line.formattedString())
+ if (matcher.matches()) {
+ found["name"] = matcher
+ continue
+ }
+ }
}
+ if (!found.containsKey("name")) return null
- it.context.matrices.popMatrix()
+ val petName = titleCase(found.getValue("name").group(3))
+ val petRarity = reversePetColourMap.getValue(found.getValue("name").group(2))
+ val petId = petName.uppercase().replace(" ", "_")
+
+ val petLevel = found.getValue("name").group(1).toInt()
+
+ val neuRarity = petRarity.neuRepoRarity ?: return null
+ val expLadder = ExpLadders.getExpLadder(petId, neuRarity)
+
+ var currentExp = 0.0
+ val expForNextLevel: Double
+ if (found.containsKey("exp")) {
+ currentExp = parseShortNumber(found.getValue("exp").group(1))
+ expForNextLevel = parseShortNumber(found.getValue("exp").group(2))
+ } else {
+ expForNextLevel = expLadder.getPetExpForLevel(petLevel + 1).toDouble() -
+ expLadder.getPetExpForLevel(petLevel).toDouble()
+ }
+
+ val overflowExp: Double = if (found.containsKey("overflow"))
+ parseShortNumber(found.getValue("overflow").group(1)) else 0.0
+
+ val totalExpBeforeLevel = expLadder.getPetExpForLevel(petLevel).toDouble()
+ val totalExp = totalExpBeforeLevel + currentExp
+ val maxLevel = RepoManager.neuRepo.constants.petLevelingData.petLevelingBehaviourOverrides[petId]?.maxLevel ?: 100
+ val expForMax = expLadder.getPetExpForLevel(maxLevel).toDouble()
+ val petItemStack = lazy { RepoManager.neuRepo.items.items[petId + ";" + petRarity.ordinal].asItemStack() }
+
+
+ var petItem = "Unknown"
+ if (found.containsKey("item")) {
+ petItem = found.getValue("item").group(1)
+ }
+
+ return ParsedPet(
+ petName,
+ petRarity,
+ petLevel,
+ maxLevel,
+ expLadder,
+ currentExp,
+ expForNextLevel,
+ totalExp,
+ totalExpBeforeLevel,
+ expForMax,
+ overflowExp,
+ petItem,
+ petItemStack,
+ false
+ )
+ }
+
+ fun parsePetMenuSlot(stack: ItemStack) : ParsedPet? {
+ val petData = stack.petData ?: return null
+ val expData = petData.level
+ val overflow = if (expData.expTotal - expData.expRequiredForMaxLevel > 0)
+ (expData.expTotal - expData.expRequiredForMaxLevel).toDouble() else 0.0
+ val petItem = if (stack.petData?.heldItem != null)
+ RepoManager.neuRepo.items.items.getValue(stack.petData?.heldItem).displayName else "None"
+ return ParsedPet(
+ titleCase(petData.type),
+ Rarity.fromNeuRepo(petData.tier) ?: Rarity.COMMON,
+ expData.currentLevel,
+ expData.maxLevel,
+ ExpLadders.getExpLadder(petData.skyblockId.toString(), petData.tier),
+ expData.expInCurrentLevel.toDouble(),
+ expData.expRequiredForNextLevel.toDouble(),
+ expData.expTotal.toDouble(),
+ expData.expTotal.toDouble() - expData.expInCurrentLevel.toDouble(),
+ expData.expRequiredForMaxLevel.toDouble(),
+ overflow,
+ petItem,
+ lazy { stack },
+ true
+ )
+ }
+}
+
+data class ParsedPet(
+ val name: String,
+ val rarity: Rarity,
+ var level: Int,
+ val maxLevel: Int,
+ val expLadder: ExpLadders.ExpLadder?,
+ var currentExp: Double,
+ var expForNextLevel: Double,
+ var totalExp: Double,
+ var totalExpBeforeLevel: Double,
+ val expForMax: Double,
+ var overflowExp: Double,
+ var petItem: String,
+ var petItemStack: Lazy<ItemStack>,
+ var isComplete: Boolean
+) {
+ fun update(other: ParsedPet) {
+ // Update the pet data to reflect another instance (of itself)
+ if (other.level > level) {
+ level = other.level
+ currentExp = other.currentExp
+ expForNextLevel = other.expForNextLevel
+ totalExp = other.totalExp
+ totalExpBeforeLevel = other.totalExpBeforeLevel
+ overflowExp = other.overflowExp
+ } else {
+ if (other.currentExp > currentExp) currentExp = other.currentExp
+ expForNextLevel = other.expForNextLevel
+ if (other.totalExp > totalExp) totalExp = other.totalExp
+ if (other.totalExpBeforeLevel > totalExpBeforeLevel) totalExpBeforeLevel = other.totalExpBeforeLevel
+ if (other.overflowExp > overflowExp) overflowExp = other.overflowExp
+ }
+ if (other.petItem != "Unknown") petItem = other.petItem
+ isComplete = false
}
}