Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,14 @@
"current state of the player's accessory bag."
]
}
},
"bestiary": {
"level": "<gray>Bestiary Level: </gray><yellow><0></yellow>",
"tiers": "<gray>Tiers: </gray><yellow><0></yellow><gold>/</gold><yellow><1></yellow>",
"progress": "<gray>Progress: </gray><green><0>%</green>",
"mobs_maxed": "<gray>Mobs Maxed: </gray><yellow><0></yellow><gold>/</gold><yellow><1></yellow>",
"next_milestone": "<gray>Next Milestone: </gray><yellow><0></yellow><gold>/</gold><yellow>10</yellow>",
"milestone_progress": "<yellow><0></yellow><gold>/</gold><yellow>10</yellow>"
}
},
"themes": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ package me.owdding.skyblockpv.screens.windowed.tabs.combat

import com.mojang.authlib.GameProfile
import com.mojang.datafixers.util.Either
import me.owdding.lib.displays.Alignment
import me.owdding.lib.displays.Display
import me.owdding.lib.displays.DisplayWidget
import me.owdding.lib.displays.Displays
import me.owdding.lib.displays.asTable
import me.owdding.lib.displays.asWidget
import me.owdding.lib.displays.toColumn
import me.owdding.lib.displays.toRow
import me.owdding.lib.displays.withTooltip as withDisplayTooltip
import me.owdding.lib.extensions.ItemUtils.createSkull
import me.owdding.lib.extensions.rightPad
import me.owdding.lib.extensions.round
Expand All @@ -18,6 +23,7 @@ import me.owdding.skyblockpv.utils.LayoutUtils.asScrollable
import me.owdding.skyblockpv.utils.LayoutUtils.centerHorizontally
import me.owdding.skyblockpv.utils.Utils
import me.owdding.skyblockpv.utils.Utils.append
import me.owdding.skyblockpv.utils.Utils.asTranslated
import me.owdding.skyblockpv.utils.Utils.fixBase64Padding
import me.owdding.skyblockpv.utils.components.CarouselWidget
import me.owdding.skyblockpv.utils.components.PvLayouts
Expand All @@ -26,6 +32,7 @@ import me.owdding.skyblockpv.utils.theme.PvColors
import net.minecraft.core.component.DataComponents
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import tech.thatgravyboat.skyblockapi.utils.builders.TooltipBuilder
import tech.thatgravyboat.skyblockapi.utils.extentions.toFormattedString
import tech.thatgravyboat.skyblockapi.utils.text.Text
import tech.thatgravyboat.skyblockapi.utils.text.TextStyle.color
Expand All @@ -43,6 +50,7 @@ class BestiaryScreen(gameProfile: GameProfile, profile: SkyBlockProfile? = null)
.filter { mobId -> BestiaryCodecs.allMobs.none { it == mobId } }
.distinct()

val overview = getOverview()
val categories = getCategories()
val inventories = categories.values.toList()
val icons = categories.keys.toList()
Expand All @@ -57,6 +65,7 @@ class BestiaryScreen(gameProfile: GameProfile, profile: SkyBlockProfile? = null)

widget(
PvLayouts.vertical(5) {
widget(overview.asWidget().centerHorizontally(uiWidth))
widget(buttonContainer.centerHorizontally(uiWidth))
widget(carousel!!.centerHorizontally(uiWidth))
}.asScrollable(uiWidth, uiHeight),
Expand All @@ -66,11 +75,76 @@ class BestiaryScreen(gameProfile: GameProfile, profile: SkyBlockProfile? = null)
}
}

private fun getAllMobs(): List<BestiaryMobEntry> = BestiaryCodecs.data.categories.values.flatMap {
Either.unwrap(
it.mapBoth(
{ it.mobs },
{ it.subcategories.values.flatMap { it.mobs } },
),
)
}

private fun getOverview(): Display {
val allMobs = getAllMobs()
val tiers = allMobs.map { it.getTiers() }
val unlocked = tiers.sumOf { it.first }
val possible = tiers.sumOf { it.second }
val maxed = tiers.count { it.first >= it.second && it.second > 0 }

val major = unlocked / 10
val minor = unlocked % 10
val level = "$major.$minor"
val isMaxed = unlocked >= possible && possible > 0
val progress = if (isMaxed) 1.0f else (minor.toFloat() / 10f)
val percent = if (possible == 0) 100.0 else (unlocked.toDouble() / possible.toDouble() * 100.0).round()

val tooltip = TooltipBuilder().apply {
add("screens.bestiary.level".asTranslated(level))
add("screens.bestiary.tiers".asTranslated(unlocked, possible))
add("screens.bestiary.progress".asTranslated(percent))
add("screens.bestiary.mobs_maxed".asTranslated(maxed, allMobs.size))
if (!isMaxed) {
add("screens.bestiary.next_milestone".asTranslated(minor))
}
}.build()

val bar = listOf(
ExtraDisplays.progress(progress, isMaxed, 100),
ExtraDisplays.text("screens.bestiary.milestone_progress".asTranslated(minor)),
).toRow(4, Alignment.CENTER)

val content = listOf(
ExtraDisplays.text("screens.bestiary.level".asTranslated(level)),
bar,
).toColumn(2, Alignment.CENTER)

return listOf(
Displays.item(Items.WRITABLE_BOOK.defaultInstance),
content,
).toRow(6, Alignment.CENTER).withDisplayTooltip(tooltip)
}

private fun ItemStack.withCategoryTooltip(name: String, mobs: List<BestiaryMobEntry>): ItemStack {
val tiers = mobs.map { it.getTiers() }
val current = tiers.sumOf { it.first }
val max = tiers.sumOf { it.second }
val maxed = tiers.count { it.first >= it.second && it.second > 0 }

val percent = if (max == 0) 100.0 else (current.toDouble() / max.toDouble() * 100.0).round()

return withTooltip {
add(name)
add("screens.bestiary.tiers".asTranslated(current, max))
add("screens.bestiary.progress".asTranslated(percent))
add("screens.bestiary.mobs_maxed".asTranslated(maxed, mobs.size))
}
}

private fun getCategories(): Map<ItemStack, Display> = BestiaryCodecs.data.categories.map { (_, v) ->
Either.unwrap(
v.mapBoth(
{ it.icon.getItem(it.name) to it.getCategory() }, // Simple
{ it.icon.getItem(it.name) to it.getCategory() }, // Complex
{ it.icon.getItem(it.name).withCategoryTooltip(it.name, it.mobs) to it.getCategory() }, // Simple
{ it.icon.getItem(it.name).withCategoryTooltip(it.name, it.subcategories.values.flatMap { it.mobs }) to it.getCategory() }, // Complex
),
)
}.toMap()
Expand All @@ -90,7 +164,7 @@ class BestiaryScreen(gameProfile: GameProfile, profile: SkyBlockProfile? = null)
)
}

private fun BestiaryMobEntry.getItem(): Display {
private fun BestiaryMobEntry.resolveBracket(): Pair<Long, List<Int>> {
val kills = profile.bestiaryData.filter { mobs.contains(it.mobId) }.sumOf { it.kills }

val fullBracket = if (bracketType != null) {
Expand All @@ -104,11 +178,17 @@ class BestiaryScreen(gameProfile: GameProfile, profile: SkyBlockProfile? = null)
BestiaryCodecs.data.brackets[bracket] ?: emptyList()
}

val tiers = if (fullBracket.isEmpty()) {
emptyList()
} else {
fullBracket.takeWhile { it < cap } + cap
}
val tiers = if (fullBracket.isEmpty()) emptyList() else fullBracket.takeWhile { it < cap } + cap
return kills to tiers
}

private fun BestiaryMobEntry.getTiers(): Pair<Int, Int> {
val (kills, tiers) = resolveBracket()
return tiers.count { kills >= it } to tiers.size
}

private fun BestiaryMobEntry.getItem(): Display {
val (kills, tiers) = resolveBracket()
val maxLevel = tiers.size
val requiredKills = tiers.lastOrNull() ?: 0
val currentLevel = tiers.indexOfLast { kills >= it } + 1
Expand Down
Loading