From 49b9f58f24902928b7f023e507550aa15c3dd681 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Mon, 17 Nov 2025 20:14:17 +0100 Subject: [PATCH 01/18] feat: init score calc Signed-off-by: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> --- .../mortem/features/ScoreCalculator.kt | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt new file mode 100644 index 0000000..6d04e0f --- /dev/null +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt @@ -0,0 +1,102 @@ +package me.owdding.mortem.features + +import tech.thatgravyboat.skyblockapi.api.area.dungeon.DungeonFloor +import tech.thatgravyboat.skyblockapi.api.data.Perk +import kotlin.math.floor +import kotlin.math.roundToInt +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +/* + +// --- SKILL --- max 100 +The Skill score ranges from 20 to 100, with 20 being the lowest score achievable. The Skill Score is calculated as such: +Skill=20+⌊80*(CompletedRoomsTotalRooms)⌋−(10*FailedPuzzles)−DeathPenalty +Each death 2, except first death with spirit pet + +// --- EXPLORATION --- max 100 +The Exploration Score depends on the percentage of dungeon completed, along with the percentage of secrets achieved. It is calculated as such: +Explore=⌊60*(CompletedRooms/TotalRooms)⌋+⌊(40*SecretPercentFound/SecretPercentNeeded)⌋ +Where the percentage of needed secrets is: +30%,On Floor 1 +40%,On Floor 2 +50%,On Floor 3 +60%,On Floor 4 +70%,On Floor 5 +85%,On Floor 6 +100%,On Floor 7 and Master Mode + + */ + +object ScoreCalculator { + val requirements = mapOf( + DungeonFloor.E to Requirements(0.3,600), // TODO + DungeonFloor.F1 to Requirements(0.3,600), + DungeonFloor.F2 to Requirements(0.4,600), + DungeonFloor.F3 to Requirements(0.5,600), + DungeonFloor.F4 to Requirements(0.6,720), + DungeonFloor.F5 to Requirements(0.7,600), + DungeonFloor.F6 to Requirements(0.85,720), + DungeonFloor.F7 to Requirements(1.0,840), + DungeonFloor.M1 to Requirements(1.0, 480), + DungeonFloor.M2 to Requirements(1.0, 480), + DungeonFloor.M3 to Requirements(1.0, 480), + DungeonFloor.M4 to Requirements(1.0, 480), + DungeonFloor.M5 to Requirements(1.0, 480), + DungeonFloor.M6 to Requirements(1.0, 600), + DungeonFloor.M7 to Requirements(1.0, 840), + ) + private val speedDecreasePercentage = mapOf( + 0.0..0.2 to 0.02, + 0.2..0.4 to 0.04, + 0.4..0.5 to 0.05, + 0.5..0.6 to 0.06, + 0.6..Double.MAX_VALUE to 0.07, + ) + + private var mimicKilled = false + private var cryptsKilled = 0 + + fun getScore(time: Duration, floor: DungeonFloor): Int { + val req = requirements[floor] ?: return 0 + return listOf( + getSkillScore(), + getExplorationScore(), + getSpeedScore(time, req), + getBonusScore(), + ).sum() + } + + private fun getSkillScore(): Int { + return 0 + } + + private fun getExplorationScore(): Int { + return 0 + } + + private fun getSpeedScore(time: Duration, req: Requirements): Int { + if (time <= req.speedTime) return 100 + + val percentOver = (time / req.speedTime) - 1 + val lost = speedDecreasePercentage.mapNotNull { (range, step) -> + if (percentOver < range.start) return@mapNotNull null + val delta = (percentOver - range.start).coerceAtMost(range.endInclusive - range.start) + delta / step + } + return 100 - floor(lost.sum()).roundToInt() + } + + private fun getBonusScore(): Int = buildList { + if (Perk.EZPZ.active) add(10) + if (mimicKilled) add(2) + add(cryptsKilled.coerceAtMost(5)) + }.sum() + + data class Requirements( + val secretPercentNeeded: Double, + val speedTime: Duration, + ) { + constructor(secretPercentNeeded: Double, speedTime: Int) : this(secretPercentNeeded, speedTime.seconds) + } +} From 020665fe572d5fa3ed44003a945b021a20bd074f Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Mon, 17 Nov 2025 23:12:55 +0100 Subject: [PATCH 02/18] feat: regex parsing from tablist --- .../mortem/features/ScoreCalculator.kt | 95 ++++++++++++++++--- 1 file changed, 83 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt index 6d04e0f..da4cada 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt @@ -2,6 +2,19 @@ package me.owdding.mortem.features import tech.thatgravyboat.skyblockapi.api.area.dungeon.DungeonFloor import tech.thatgravyboat.skyblockapi.api.data.Perk +import tech.thatgravyboat.skyblockapi.api.events.base.Subscription +import tech.thatgravyboat.skyblockapi.api.events.base.predicates.OnlyIn +import tech.thatgravyboat.skyblockapi.api.events.base.predicates.OnlyWidget +import tech.thatgravyboat.skyblockapi.api.events.chat.ChatReceivedEvent +import tech.thatgravyboat.skyblockapi.api.events.hypixel.ServerChangeEvent +import tech.thatgravyboat.skyblockapi.api.events.info.TabWidget +import tech.thatgravyboat.skyblockapi.api.events.info.TabWidgetChangeEvent +import tech.thatgravyboat.skyblockapi.api.events.location.ServerDisconnectEvent +import tech.thatgravyboat.skyblockapi.api.location.SkyBlockIsland +import tech.thatgravyboat.skyblockapi.utils.extentions.toFloatValue +import tech.thatgravyboat.skyblockapi.utils.extentions.toIntValue +import tech.thatgravyboat.skyblockapi.utils.regex.RegexUtils.anyMatch +import tech.thatgravyboat.skyblockapi.utils.regex.matchWhen import kotlin.math.floor import kotlin.math.roundToInt import kotlin.time.Duration @@ -17,19 +30,35 @@ Each death 2, except first death with spirit pet // --- EXPLORATION --- max 100 The Exploration Score depends on the percentage of dungeon completed, along with the percentage of secrets achieved. It is calculated as such: Explore=⌊60*(CompletedRooms/TotalRooms)⌋+⌊(40*SecretPercentFound/SecretPercentNeeded)⌋ -Where the percentage of needed secrets is: -30%,On Floor 1 -40%,On Floor 2 -50%,On Floor 3 -60%,On Floor 4 -70%,On Floor 5 -85%,On Floor 6 -100%,On Floor 7 and Master Mode + + +Discoveries: 4 + Secrets Found: 4 + Crypts: 0 + +Dungeon: Catacombs + Opened Rooms: 34 + Completed Rooms: 16 + Secrets Found: 7.8% + Time: 06m 39s + +Puzzles: (3) + Quiz: [✖] () + Three Weirdos: [✔] + ???: [✦] */ object ScoreCalculator { - val requirements = mapOf( + // + // --Chat-- + private val mimicKilledRegex = ".*(\$SKYTILS-DUNGEON-SCORE-MIMIC\$|Mimic [Dd]ead!|Mimic Killed!)$".toRegex() + // -- Tab-- + private val cryptsRegex = " Crypts: (?\\d+)".toRegex() + private val secretPercentageRegex = " Secrets Found: (?[\\d.]+)%".toRegex() + // + + private val requirements = mapOf( DungeonFloor.E to Requirements(0.3,600), // TODO DungeonFloor.F1 to Requirements(0.3,600), DungeonFloor.F2 to Requirements(0.4,600), @@ -56,12 +85,13 @@ object ScoreCalculator { private var mimicKilled = false private var cryptsKilled = 0 + private var secretPercentage = 0f fun getScore(time: Duration, floor: DungeonFloor): Int { val req = requirements[floor] ?: return 0 return listOf( getSkillScore(), - getExplorationScore(), + getExplorationScore(req), getSpeedScore(time, req), getBonusScore(), ).sum() @@ -71,8 +101,10 @@ object ScoreCalculator { return 0 } - private fun getExplorationScore(): Int { - return 0 + private fun getExplorationScore(req: Requirements): Int { + val roomsScore = 0 + val secretsScore = floor((40 * secretPercentage / req.secretPercentNeeded)).roundToInt() + return roomsScore + secretsScore } private fun getSpeedScore(time: Duration, req: Requirements): Int { @@ -88,6 +120,7 @@ object ScoreCalculator { } private fun getBonusScore(): Int = buildList { + // TODO: prince maybe if (Perk.EZPZ.active) add(10) if (mimicKilled) add(2) add(cryptsKilled.coerceAtMost(5)) @@ -99,4 +132,42 @@ object ScoreCalculator { ) { constructor(secretPercentNeeded: Double, speedTime: Int) : this(secretPercentNeeded, speedTime.seconds) } + + @Subscription(ServerChangeEvent::class, ServerDisconnectEvent::class) + fun reset() { + mimicKilled = false + cryptsKilled = 0 + } + + @Subscription + @OnlyIn(SkyBlockIsland.THE_CATACOMBS) + fun onChat(event: ChatReceivedEvent.Pre) { + matchWhen(event.text) { + case(mimicKilledRegex) { + mimicKilled = true + } + } + } + + @Subscription + @OnlyWidget(TabWidget.DISCOVERIES) + fun onDiscoveriesWidget(event: TabWidgetChangeEvent) { + cryptsRegex.anyMatch(event.new, "amount") { (amount) -> + cryptsKilled = amount.toIntValue() + } + } + + @Subscription + @OnlyWidget(TabWidget.AREA) + fun onAreaWidget(event: TabWidgetChangeEvent) { + secretPercentageRegex.anyMatch(event.new, "percentage") { (percentage) -> + this.secretPercentage == percentage.toFloatValue() / 100f + } + } + + @Subscription + @OnlyWidget(TabWidget.PUZZLES) + fun onPuzzlesWidget(event: TabWidgetChangeEvent) { + + } } From a804d2c578854f38e926a75ca6e6b7479f4a1da7 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Tue, 18 Nov 2025 10:45:04 +0100 Subject: [PATCH 03/18] feat: finish score calc Signed-off-by: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> --- .../mortem/features/ScoreCalculator.kt | 58 +++++++++++++------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt index da4cada..63bb720 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt @@ -7,6 +7,7 @@ import tech.thatgravyboat.skyblockapi.api.events.base.predicates.OnlyIn import tech.thatgravyboat.skyblockapi.api.events.base.predicates.OnlyWidget import tech.thatgravyboat.skyblockapi.api.events.chat.ChatReceivedEvent import tech.thatgravyboat.skyblockapi.api.events.hypixel.ServerChangeEvent +import tech.thatgravyboat.skyblockapi.api.events.info.ScoreboardUpdateEvent import tech.thatgravyboat.skyblockapi.api.events.info.TabWidget import tech.thatgravyboat.skyblockapi.api.events.info.TabWidgetChangeEvent import tech.thatgravyboat.skyblockapi.api.events.location.ServerDisconnectEvent @@ -21,17 +22,6 @@ import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds /* - -// --- SKILL --- max 100 -The Skill score ranges from 20 to 100, with 20 being the lowest score achievable. The Skill Score is calculated as such: -Skill=20+⌊80*(CompletedRoomsTotalRooms)⌋−(10*FailedPuzzles)−DeathPenalty -Each death 2, except first death with spirit pet - -// --- EXPLORATION --- max 100 -The Exploration Score depends on the percentage of dungeon completed, along with the percentage of secrets achieved. It is calculated as such: -Explore=⌊60*(CompletedRooms/TotalRooms)⌋+⌊(40*SecretPercentFound/SecretPercentNeeded)⌋ - - Discoveries: 4 Secrets Found: 4 Crypts: 0 @@ -46,20 +36,27 @@ Puzzles: (3) Quiz: [✖] () Three Weirdos: [✔] ???: [✦] - */ +// TODO +// Killing Mimic +// Spirit Pet in Death +// Prince Kill +// Entrace req object ScoreCalculator { // // --Chat-- private val mimicKilledRegex = ".*(\$SKYTILS-DUNGEON-SCORE-MIMIC\$|Mimic [Dd]ead!|Mimic Killed!)$".toRegex() + // --Scoreboard-- + private val clearedPercentageRegex = "\\s*Cleared: (?[\\d,.]+)% \\((?[\\d.]+)\\)".toRegex() // -- Tab-- private val cryptsRegex = " Crypts: (?\\d+)".toRegex() private val secretPercentageRegex = " Secrets Found: (?[\\d.]+)%".toRegex() + private val puzzleRegex = " [\\w\\s]+: \\[[✖✦]](?: \\(.*\\))?".toRegex() // private val requirements = mapOf( - DungeonFloor.E to Requirements(0.3,600), // TODO + DungeonFloor.E to Requirements(0.3,600), DungeonFloor.F1 to Requirements(0.3,600), DungeonFloor.F2 to Requirements(0.4,600), DungeonFloor.F3 to Requirements(0.5,600), @@ -83,9 +80,12 @@ object ScoreCalculator { 0.6..Double.MAX_VALUE to 0.07, ) + private var deaths = 0 + private var secretPercentage = 0f + private var clearedPercentage = 0f private var mimicKilled = false private var cryptsKilled = 0 - private var secretPercentage = 0f + private var failedPuzzles = 0 fun getScore(time: Duration, floor: DungeonFloor): Int { val req = requirements[floor] ?: return 0 @@ -98,11 +98,15 @@ object ScoreCalculator { } private fun getSkillScore(): Int { - return 0 + val roomsScore = floor((80 * clearedPercentage)).roundToInt() + val puzzlePenalty = 10 * failedPuzzles + val deathPenalty = 2 * deaths + + return 20 + roomsScore - puzzlePenalty - deathPenalty } private fun getExplorationScore(req: Requirements): Int { - val roomsScore = 0 + val roomsScore = floor(60 * clearedPercentage).roundToInt() val secretsScore = floor((40 * secretPercentage / req.secretPercentNeeded)).roundToInt() return roomsScore + secretsScore } @@ -120,7 +124,6 @@ object ScoreCalculator { } private fun getBonusScore(): Int = buildList { - // TODO: prince maybe if (Perk.EZPZ.active) add(10) if (mimicKilled) add(2) add(cryptsKilled.coerceAtMost(5)) @@ -135,8 +138,12 @@ object ScoreCalculator { @Subscription(ServerChangeEvent::class, ServerDisconnectEvent::class) fun reset() { + deaths = 0 + secretPercentage = 0f + clearedPercentage = 0f mimicKilled = false cryptsKilled = 0 + failedPuzzles = 0 } @Subscription @@ -149,6 +156,13 @@ object ScoreCalculator { } } + @Subscription + fun onScoreboard(event: ScoreboardUpdateEvent) { + clearedPercentageRegex.anyMatch(event.new, "percentage") { (percentage) -> + clearedPercentage = percentage.toFloatValue() / 100f + } + } + @Subscription @OnlyWidget(TabWidget.DISCOVERIES) fun onDiscoveriesWidget(event: TabWidgetChangeEvent) { @@ -161,13 +175,21 @@ object ScoreCalculator { @OnlyWidget(TabWidget.AREA) fun onAreaWidget(event: TabWidgetChangeEvent) { secretPercentageRegex.anyMatch(event.new, "percentage") { (percentage) -> - this.secretPercentage == percentage.toFloatValue() / 100f + this.secretPercentage = percentage.toFloatValue() / 100f } } @Subscription @OnlyWidget(TabWidget.PUZZLES) fun onPuzzlesWidget(event: TabWidgetChangeEvent) { + failedPuzzles = event.new.count { puzzleRegex.matches(it) } + } + @Subscription + @OnlyWidget(TabWidget.TEAM_DEATHS) + fun onTeamDeathsWidget(event: TabWidgetChangeEvent) { + TabWidget.TEAM_DEATHS.regex.anyMatch(event.new, "amount") { (amount) -> + this.deaths = amount.toIntValue() + } } } From f66e8db7eaf40f4895db8598ef5803b190fafe85 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Tue, 18 Nov 2025 11:10:07 +0100 Subject: [PATCH 04/18] feat: score overlay Signed-off-by: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> --- .../mortem/config/category/OverlayConfig.kt | 9 +++ .../mortem/features/ScoreCalculator.kt | 43 +++++++++-- .../owdding/mortem/features/ScoreDisplay.kt | 71 +++++++++++++++++++ .../mortem/utils/colors/MortemColors.kt | 2 +- 4 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt diff --git a/src/main/kotlin/me/owdding/mortem/config/category/OverlayConfig.kt b/src/main/kotlin/me/owdding/mortem/config/category/OverlayConfig.kt index b205036..34525b8 100644 --- a/src/main/kotlin/me/owdding/mortem/config/category/OverlayConfig.kt +++ b/src/main/kotlin/me/owdding/mortem/config/category/OverlayConfig.kt @@ -23,10 +23,19 @@ object OverlayConfig : CategoryKt("overlays") { var dungeonBreakerShowWhenHolding by boolean(false) { translation = "$translation.dungeonbreaker_show_when_holding" } + + init { + separator("$translation.score_separator") + } + + var scoreOverlay by boolean(true) { + translation = "$translation.score_overlay" + } } object OverlayPositions : CategoryKt("overlaysPositions") { override val hidden: Boolean = true val dungeonBreaker by obj(ConfigPosition(100, 200)) + val score by obj(ConfigPosition(10, 500) ) } diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt index 63bb720..f5cf7bc 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt @@ -1,5 +1,8 @@ package me.owdding.mortem.features +import net.minecraft.ChatFormatting +import net.minecraft.network.chat.Component +import tech.thatgravyboat.skyblockapi.api.area.dungeon.DungeonAPI import tech.thatgravyboat.skyblockapi.api.area.dungeon.DungeonFloor import tech.thatgravyboat.skyblockapi.api.data.Perk import tech.thatgravyboat.skyblockapi.api.events.base.Subscription @@ -16,6 +19,8 @@ import tech.thatgravyboat.skyblockapi.utils.extentions.toFloatValue import tech.thatgravyboat.skyblockapi.utils.extentions.toIntValue import tech.thatgravyboat.skyblockapi.utils.regex.RegexUtils.anyMatch import tech.thatgravyboat.skyblockapi.utils.regex.matchWhen +import tech.thatgravyboat.skyblockapi.utils.text.Text +import tech.thatgravyboat.skyblockapi.utils.text.TextColor import kotlin.math.floor import kotlin.math.roundToInt import kotlin.time.Duration @@ -87,14 +92,15 @@ object ScoreCalculator { private var cryptsKilled = 0 private var failedPuzzles = 0 - fun getScore(time: Duration, floor: DungeonFloor): Int { - val req = requirements[floor] ?: return 0 - return listOf( + fun getScore() = DungeonAPI.dungeonFloor?.let { getScore(DungeonAPI.time, it) } + fun getScore(time: Duration, floor: DungeonFloor): Score { + val req = requirements[floor] ?: return Score.ZERO + return Score( getSkillScore(), getExplorationScore(req), getSpeedScore(time, req), getBonusScore(), - ).sum() + ) } private fun getSkillScore(): Int { @@ -129,13 +135,40 @@ object ScoreCalculator { add(cryptsKilled.coerceAtMost(5)) }.sum() - data class Requirements( + data class Score( + val skill: Int, + val exploration: Int, + val speed: Int, + val bonus: Int, + ) { + val total = skill + exploration + speed + bonus + val rank = Rank.getRank(total) + + companion object { + val ZERO = Score(0,0,0,0) + } + } + + private data class Requirements( val secretPercentNeeded: Double, val speedTime: Duration, ) { constructor(secretPercentNeeded: Double, speedTime: Int) : this(secretPercentNeeded, speedTime.seconds) } + enum class Rank(val minScore: Int, val component: Component) { + D(0, Text.of("D").withColor(TextColor.RED)), + C(100, Text.of("C").withColor(TextColor.BLUE)), + B(160, Text.of("B").withColor(TextColor.GREEN)), + A(230, Text.of("A").withColor(TextColor.DARK_PURPLE)), + S(270, Text.of("S").withColor(TextColor.YELLOW)), + S_PLUS(300, Text.of("S+").withColor(TextColor.GOLD).withStyle(ChatFormatting.BOLD)); + + companion object { + fun getRank(score: Int) = entries.lastOrNull { score >= it.minScore } ?: D + } + } + @Subscription(ServerChangeEvent::class, ServerDisconnectEvent::class) fun reset() { deaths = 0 diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt new file mode 100644 index 0000000..659c580 --- /dev/null +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt @@ -0,0 +1,71 @@ +package me.owdding.mortem.features + +import me.owdding.ktmodules.Module +import me.owdding.lib.builder.ComponentFactory +import me.owdding.lib.overlays.Position +import me.owdding.mortem.config.category.OverlayConfig +import me.owdding.mortem.config.category.OverlayPositions +import me.owdding.mortem.utils.CachedValue +import me.owdding.mortem.utils.MortemOverlay +import me.owdding.mortem.utils.Overlay +import me.owdding.mortem.utils.colors.CatppuccinColors +import me.owdding.mortem.utils.colors.MortemColors +import me.owdding.mortem.utils.ticks +import net.minecraft.client.gui.GuiGraphics +import net.minecraft.network.chat.Component +import tech.thatgravyboat.skyblockapi.api.location.SkyBlockIsland +import tech.thatgravyboat.skyblockapi.helpers.McFont +import tech.thatgravyboat.skyblockapi.platform.drawString +import tech.thatgravyboat.skyblockapi.utils.text.Text +import tech.thatgravyboat.skyblockapi.utils.text.TextProperties.width +import tech.thatgravyboat.skyblockapi.utils.text.TextStyle.color +import tech.thatgravyboat.skyblockapi.utils.text.TextUtils.splitLines + +@Module +@Overlay +object ScoreDisplay : MortemOverlay { + + override val name: Component = Text.of("Score Display") + override val enabled: Boolean get() = OverlayConfig.scoreOverlay && SkyBlockIsland.THE_CATACOMBS.inIsland() + override val position: Position = OverlayPositions.score + override val bounds: Pair + get() = display?.let { + it.width to it.splitLines().size * McFont.height + } ?: (0 to 0) + + + private val display by CachedValue(2.ticks) { + val score = ScoreCalculator.getScore() ?: return@CachedValue null + + ComponentFactory.multiline { + string("Score: ") { + color = MortemColors.BASE_TEXT + append("${score.total}") { color = MortemColors.HIGHLIGHT } + append("(") { color = MortemColors.SEPARATOR } + append(score.rank.component) + append(")") { color = MortemColors.SEPARATOR } + } + string(" - Skill: ") { + color = MortemColors.BASE_TEXT + append("${score.skill}") { color = CatppuccinColors.Mocha.pink } + } + string(" - Exploration: ") { + color = MortemColors.BASE_TEXT + append("${score.exploration}") { color = CatppuccinColors.Mocha.yellow } + } + string(" - Speed: ") { + color = MortemColors.BASE_TEXT + append("${score.speed}") { color = CatppuccinColors.Mocha.green } + } + string(" - Bonus: ") { + color = MortemColors.BASE_TEXT + append("${score.bonus}") { color = CatppuccinColors.Mocha.blue } + } + + } + } + + override fun render(graphics: GuiGraphics, mouseX: Int, mouseY: Int, partialTicks: Float) { + display?.let { graphics.drawString(it, 0, 0) } + } +} diff --git a/src/main/kotlin/me/owdding/mortem/utils/colors/MortemColors.kt b/src/main/kotlin/me/owdding/mortem/utils/colors/MortemColors.kt index d0134e6..efdf8c6 100644 --- a/src/main/kotlin/me/owdding/mortem/utils/colors/MortemColors.kt +++ b/src/main/kotlin/me/owdding/mortem/utils/colors/MortemColors.kt @@ -3,5 +3,5 @@ package me.owdding.mortem.utils.colors object MortemColors { const val BASE_TEXT = 0xcdd6f4 const val SEPARATOR = 0x585b70 - const val HIGHLIGHT = 0xcba6f7 + const val HIGHLIGHT = CatppuccinColors.Mocha.mauve } From c53f8ae330feba07352157bb26ec1389ae27a06b Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Tue, 18 Nov 2025 15:50:08 +0100 Subject: [PATCH 05/18] fixes Signed-off-by: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> --- .../owdding/mortem/features/ScoreCalculator.kt | 2 ++ .../me/owdding/mortem/features/ScoreDisplay.kt | 17 ++++++----------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt index f5cf7bc..b09baa5 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt @@ -1,5 +1,6 @@ package me.owdding.mortem.features +import me.owdding.ktmodules.Module import net.minecraft.ChatFormatting import net.minecraft.network.chat.Component import tech.thatgravyboat.skyblockapi.api.area.dungeon.DungeonAPI @@ -48,6 +49,7 @@ Puzzles: (3) // Spirit Pet in Death // Prince Kill // Entrace req +@Module object ScoreCalculator { // // --Chat-- diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt index 659c580..980bce9 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt @@ -1,7 +1,7 @@ package me.owdding.mortem.features import me.owdding.ktmodules.Module -import me.owdding.lib.builder.ComponentFactory +import me.owdding.lib.builder.DisplayFactory import me.owdding.lib.overlays.Position import me.owdding.mortem.config.category.OverlayConfig import me.owdding.mortem.config.category.OverlayPositions @@ -14,12 +14,9 @@ import me.owdding.mortem.utils.ticks import net.minecraft.client.gui.GuiGraphics import net.minecraft.network.chat.Component import tech.thatgravyboat.skyblockapi.api.location.SkyBlockIsland -import tech.thatgravyboat.skyblockapi.helpers.McFont -import tech.thatgravyboat.skyblockapi.platform.drawString import tech.thatgravyboat.skyblockapi.utils.text.Text -import tech.thatgravyboat.skyblockapi.utils.text.TextProperties.width +import tech.thatgravyboat.skyblockapi.utils.text.TextBuilder.append import tech.thatgravyboat.skyblockapi.utils.text.TextStyle.color -import tech.thatgravyboat.skyblockapi.utils.text.TextUtils.splitLines @Module @Overlay @@ -29,18 +26,16 @@ object ScoreDisplay : MortemOverlay { override val enabled: Boolean get() = OverlayConfig.scoreOverlay && SkyBlockIsland.THE_CATACOMBS.inIsland() override val position: Position = OverlayPositions.score override val bounds: Pair - get() = display?.let { - it.width to it.splitLines().size * McFont.height - } ?: (0 to 0) + get() = display?.let { it.getWidth() to it.getHeight() } ?: (0 to 0) private val display by CachedValue(2.ticks) { val score = ScoreCalculator.getScore() ?: return@CachedValue null - ComponentFactory.multiline { + DisplayFactory.vertical { string("Score: ") { color = MortemColors.BASE_TEXT - append("${score.total}") { color = MortemColors.HIGHLIGHT } + append("${score.total} ") { color = MortemColors.HIGHLIGHT } append("(") { color = MortemColors.SEPARATOR } append(score.rank.component) append(")") { color = MortemColors.SEPARATOR } @@ -66,6 +61,6 @@ object ScoreDisplay : MortemOverlay { } override fun render(graphics: GuiGraphics, mouseX: Int, mouseY: Int, partialTicks: Float) { - display?.let { graphics.drawString(it, 0, 0) } + display?.render(graphics, mouseX, mouseY, partialTicks) } } From 3cdedf61b70c760a413adbb113f57d35c3a0bf68 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Tue, 18 Nov 2025 16:38:03 +0100 Subject: [PATCH 06/18] fix: exploration score Signed-off-by: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> --- src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt index b09baa5..1df6c10 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt @@ -115,7 +115,7 @@ object ScoreCalculator { private fun getExplorationScore(req: Requirements): Int { val roomsScore = floor(60 * clearedPercentage).roundToInt() - val secretsScore = floor((40 * secretPercentage / req.secretPercentNeeded)).roundToInt() + val secretsScore = floor((40 * (secretPercentage / req.secretPercentNeeded).coerceAtMost(1.0))).roundToInt() return roomsScore + secretsScore } From 391a4565fd7a685bfe4d5cf7e94245dfd5cfe852 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Tue, 18 Nov 2025 16:38:18 +0100 Subject: [PATCH 07/18] feat: init display modes Signed-off-by: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> --- .../mortem/config/category/OverlayConfig.kt | 11 ++++ .../owdding/mortem/features/ScoreDisplay.kt | 65 ++++++++++++------- 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/me/owdding/mortem/config/category/OverlayConfig.kt b/src/main/kotlin/me/owdding/mortem/config/category/OverlayConfig.kt index 34525b8..5e9be1d 100644 --- a/src/main/kotlin/me/owdding/mortem/config/category/OverlayConfig.kt +++ b/src/main/kotlin/me/owdding/mortem/config/category/OverlayConfig.kt @@ -1,5 +1,6 @@ package me.owdding.mortem.config.category +import com.teamresourceful.resourcefulconfig.api.types.info.Translatable import com.teamresourceful.resourcefulconfigkt.api.CategoryKt import me.owdding.lib.overlays.ConfigPosition import me.owdding.mortem.config.separator @@ -31,6 +32,16 @@ object OverlayConfig : CategoryKt("overlays") { var scoreOverlay by boolean(true) { translation = "$translation.score_overlay" } + + var displayMode by enum(DisplayMode.DETAILED) { + translation = "$translation.score_display_mode" + } +} + +enum class DisplayMode : Translatable { + DETAILED, COMPACT, SHORT; + + override fun getTranslationKey() = "mortem.config.overlays.display_mode.$name".lowercase() } object OverlayPositions : CategoryKt("overlaysPositions") { diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt index 980bce9..693677b 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt @@ -3,6 +3,7 @@ package me.owdding.mortem.features import me.owdding.ktmodules.Module import me.owdding.lib.builder.DisplayFactory import me.owdding.lib.overlays.Position +import me.owdding.mortem.config.category.DisplayMode import me.owdding.mortem.config.category.OverlayConfig import me.owdding.mortem.config.category.OverlayPositions import me.owdding.mortem.utils.CachedValue @@ -14,6 +15,7 @@ import me.owdding.mortem.utils.ticks import net.minecraft.client.gui.GuiGraphics import net.minecraft.network.chat.Component import tech.thatgravyboat.skyblockapi.api.location.SkyBlockIsland +import tech.thatgravyboat.skyblockapi.helpers.McFont import tech.thatgravyboat.skyblockapi.utils.text.Text import tech.thatgravyboat.skyblockapi.utils.text.TextBuilder.append import tech.thatgravyboat.skyblockapi.utils.text.TextStyle.color @@ -32,31 +34,46 @@ object ScoreDisplay : MortemOverlay { private val display by CachedValue(2.ticks) { val score = ScoreCalculator.getScore() ?: return@CachedValue null - DisplayFactory.vertical { - string("Score: ") { - color = MortemColors.BASE_TEXT - append("${score.total} ") { color = MortemColors.HIGHLIGHT } - append("(") { color = MortemColors.SEPARATOR } - append(score.rank.component) - append(")") { color = MortemColors.SEPARATOR } - } - string(" - Skill: ") { - color = MortemColors.BASE_TEXT - append("${score.skill}") { color = CatppuccinColors.Mocha.pink } - } - string(" - Exploration: ") { - color = MortemColors.BASE_TEXT - append("${score.exploration}") { color = CatppuccinColors.Mocha.yellow } - } - string(" - Speed: ") { - color = MortemColors.BASE_TEXT - append("${score.speed}") { color = CatppuccinColors.Mocha.green } - } - string(" - Bonus: ") { - color = MortemColors.BASE_TEXT - append("${score.bonus}") { color = CatppuccinColors.Mocha.blue } - } + when (OverlayConfig.displayMode) { + DisplayMode.DETAILED -> getDetailed(score) + DisplayMode.COMPACT -> getCompact(score) + DisplayMode.SHORT -> getShort(score) + } + } + + private fun getDetailed(score: ScoreCalculator.Score) = DisplayFactory.vertical { + display(getCompact(score)) + spacer(McFont.height) + string("TODO MORE INFO") + } + + private fun getCompact(score: ScoreCalculator.Score) = DisplayFactory.horizontal { + display(getShort(score)) + string(" - Skill: ") { + color = MortemColors.BASE_TEXT + append("${score.skill}") { color = CatppuccinColors.Mocha.pink } + } + string(" - Exploration: ") { + color = MortemColors.BASE_TEXT + append("${score.exploration}") { color = CatppuccinColors.Mocha.yellow } + } + string(" - Speed: ") { + color = MortemColors.BASE_TEXT + append("${score.speed}") { color = CatppuccinColors.Mocha.green } + } + string(" - Bonus: ") { + color = MortemColors.BASE_TEXT + append("${score.bonus}") { color = CatppuccinColors.Mocha.blue } + } + } + private fun getShort(score: ScoreCalculator.Score) = DisplayFactory.horizontal { + string("Score: ") { + color = MortemColors.BASE_TEXT + append("${score.total} ") { color = MortemColors.HIGHLIGHT } + append("(") { color = MortemColors.SEPARATOR } + append(score.rank.component) + append(")") { color = MortemColors.SEPARATOR } } } From f472108927082c89f0d30982149fec9c09fc2003 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Tue, 18 Nov 2025 16:43:36 +0100 Subject: [PATCH 08/18] fix: rendering Signed-off-by: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> --- src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt index 693677b..8697067 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt @@ -78,6 +78,6 @@ object ScoreDisplay : MortemOverlay { } override fun render(graphics: GuiGraphics, mouseX: Int, mouseY: Int, partialTicks: Float) { - display?.render(graphics, mouseX, mouseY, partialTicks) + display?.render(graphics) } } From 6c585c2153c6b2d069c29af777009a748afba792 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Tue, 18 Nov 2025 17:09:00 +0100 Subject: [PATCH 09/18] fix: display Signed-off-by: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> --- src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt index 8697067..493ce66 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreDisplay.kt @@ -47,7 +47,7 @@ object ScoreDisplay : MortemOverlay { string("TODO MORE INFO") } - private fun getCompact(score: ScoreCalculator.Score) = DisplayFactory.horizontal { + private fun getCompact(score: ScoreCalculator.Score) = DisplayFactory.vertical { display(getShort(score)) string(" - Skill: ") { color = MortemColors.BASE_TEXT @@ -67,7 +67,7 @@ object ScoreDisplay : MortemOverlay { } } - private fun getShort(score: ScoreCalculator.Score) = DisplayFactory.horizontal { + private fun getShort(score: ScoreCalculator.Score) = DisplayFactory.vertical { string("Score: ") { color = MortemColors.BASE_TEXT append("${score.total} ") { color = MortemColors.HIGHLIGHT } From 9b870a7b21d2042e0dc3346e33f401bc8e82ace8 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Tue, 18 Nov 2025 23:19:15 +0100 Subject: [PATCH 10/18] rename --- .../mortem/features/ScoreCalculator.kt | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt index 1df6c10..973d7f1 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt @@ -16,6 +16,7 @@ import tech.thatgravyboat.skyblockapi.api.events.info.TabWidget import tech.thatgravyboat.skyblockapi.api.events.info.TabWidgetChangeEvent import tech.thatgravyboat.skyblockapi.api.events.location.ServerDisconnectEvent import tech.thatgravyboat.skyblockapi.api.location.SkyBlockIsland +import tech.thatgravyboat.skyblockapi.utils.extentions.enumMapOf import tech.thatgravyboat.skyblockapi.utils.extentions.toFloatValue import tech.thatgravyboat.skyblockapi.utils.extentions.toIntValue import tech.thatgravyboat.skyblockapi.utils.regex.RegexUtils.anyMatch @@ -62,15 +63,15 @@ object ScoreCalculator { private val puzzleRegex = " [\\w\\s]+: \\[[✖✦]](?: \\(.*\\))?".toRegex() // - private val requirements = mapOf( - DungeonFloor.E to Requirements(0.3,600), - DungeonFloor.F1 to Requirements(0.3,600), - DungeonFloor.F2 to Requirements(0.4,600), - DungeonFloor.F3 to Requirements(0.5,600), - DungeonFloor.F4 to Requirements(0.6,720), - DungeonFloor.F5 to Requirements(0.7,600), - DungeonFloor.F6 to Requirements(0.85,720), - DungeonFloor.F7 to Requirements(1.0,840), + private val requirements = enumMapOf( + DungeonFloor.E to Requirements(0.3, 600), + DungeonFloor.F1 to Requirements(0.3, 600), + DungeonFloor.F2 to Requirements(0.4, 600), + DungeonFloor.F3 to Requirements(0.5, 600), + DungeonFloor.F4 to Requirements(0.6, 720), + DungeonFloor.F5 to Requirements(0.7, 600), + DungeonFloor.F6 to Requirements(0.85, 720), + DungeonFloor.F7 to Requirements(1.0, 840), DungeonFloor.M1 to Requirements(1.0, 480), DungeonFloor.M2 to Requirements(1.0, 480), DungeonFloor.M3 to Requirements(1.0, 480), @@ -89,7 +90,7 @@ object ScoreCalculator { private var deaths = 0 private var secretPercentage = 0f - private var clearedPercentage = 0f + private var roomsClearedPercentage = 0f private var mimicKilled = false private var cryptsKilled = 0 private var failedPuzzles = 0 @@ -106,7 +107,7 @@ object ScoreCalculator { } private fun getSkillScore(): Int { - val roomsScore = floor((80 * clearedPercentage)).roundToInt() + val roomsScore = floor((80 * roomsClearedPercentage)).roundToInt() val puzzlePenalty = 10 * failedPuzzles val deathPenalty = 2 * deaths @@ -114,7 +115,7 @@ object ScoreCalculator { } private fun getExplorationScore(req: Requirements): Int { - val roomsScore = floor(60 * clearedPercentage).roundToInt() + val roomsScore = floor(60 * roomsClearedPercentage).roundToInt() val secretsScore = floor((40 * (secretPercentage / req.secretPercentNeeded).coerceAtMost(1.0))).roundToInt() return roomsScore + secretsScore } @@ -175,7 +176,7 @@ object ScoreCalculator { fun reset() { deaths = 0 secretPercentage = 0f - clearedPercentage = 0f + roomsClearedPercentage = 0f mimicKilled = false cryptsKilled = 0 failedPuzzles = 0 @@ -194,7 +195,7 @@ object ScoreCalculator { @Subscription fun onScoreboard(event: ScoreboardUpdateEvent) { clearedPercentageRegex.anyMatch(event.new, "percentage") { (percentage) -> - clearedPercentage = percentage.toFloatValue() / 100f + roomsClearedPercentage = percentage.toFloatValue() / 100f } } From 2e55b72a36219e6fc6080a0a7210331328513905 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Thu, 20 Nov 2025 10:15:18 +0100 Subject: [PATCH 11/18] feat: maybe mimic kill Signed-off-by: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> --- .../mortem/mixins/LivingEntityMixin.java | 19 +++++++++++++++++++ .../me/owdding/mortem/events/EntityEvents.kt | 10 ++++++++++ .../mortem/features/ScoreCalculator.kt | 17 +++++++++++++++++ src/main/resources/mortem.mixins.json | 5 ++++- 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/main/java/me/owdding/mortem/mixins/LivingEntityMixin.java create mode 100644 src/main/kotlin/me/owdding/mortem/events/EntityEvents.kt diff --git a/src/main/java/me/owdding/mortem/mixins/LivingEntityMixin.java b/src/main/java/me/owdding/mortem/mixins/LivingEntityMixin.java new file mode 100644 index 0000000..64cbec1 --- /dev/null +++ b/src/main/java/me/owdding/mortem/mixins/LivingEntityMixin.java @@ -0,0 +1,19 @@ +package me.owdding.mortem.mixins; + +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import me.owdding.mortem.events.EntityDeathEvent; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.LivingEntity; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(LivingEntity.class) +public class LivingEntityMixin { + + @WrapMethod(method = "die") + private void onDieWrap(DamageSource damageSource, Operation original) { + new EntityDeathEvent((LivingEntity) (Object) this, damageSource); + original.call(damageSource); + } + +} diff --git a/src/main/kotlin/me/owdding/mortem/events/EntityEvents.kt b/src/main/kotlin/me/owdding/mortem/events/EntityEvents.kt new file mode 100644 index 0000000..60d9ef6 --- /dev/null +++ b/src/main/kotlin/me/owdding/mortem/events/EntityEvents.kt @@ -0,0 +1,10 @@ +package me.owdding.mortem.events + +import net.minecraft.world.damagesource.DamageSource +import net.minecraft.world.entity.LivingEntity +import tech.thatgravyboat.skyblockapi.api.events.base.SkyBlockEvent + +data class EntityDeathEvent( + val entity: LivingEntity, + val damageSource: DamageSource, +) : SkyBlockEvent() diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt index 973d7f1..8c0b9bf 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt @@ -1,8 +1,10 @@ package me.owdding.mortem.features import me.owdding.ktmodules.Module +import me.owdding.mortem.events.EntityDeathEvent import net.minecraft.ChatFormatting import net.minecraft.network.chat.Component +import net.minecraft.world.entity.monster.Zombie import tech.thatgravyboat.skyblockapi.api.area.dungeon.DungeonAPI import tech.thatgravyboat.skyblockapi.api.area.dungeon.DungeonFloor import tech.thatgravyboat.skyblockapi.api.data.Perk @@ -16,12 +18,14 @@ import tech.thatgravyboat.skyblockapi.api.events.info.TabWidget import tech.thatgravyboat.skyblockapi.api.events.info.TabWidgetChangeEvent import tech.thatgravyboat.skyblockapi.api.events.location.ServerDisconnectEvent import tech.thatgravyboat.skyblockapi.api.location.SkyBlockIsland +import tech.thatgravyboat.skyblockapi.helpers.McClient import tech.thatgravyboat.skyblockapi.utils.extentions.enumMapOf import tech.thatgravyboat.skyblockapi.utils.extentions.toFloatValue import tech.thatgravyboat.skyblockapi.utils.extentions.toIntValue import tech.thatgravyboat.skyblockapi.utils.regex.RegexUtils.anyMatch import tech.thatgravyboat.skyblockapi.utils.regex.matchWhen import tech.thatgravyboat.skyblockapi.utils.text.Text +import tech.thatgravyboat.skyblockapi.utils.text.Text.send import tech.thatgravyboat.skyblockapi.utils.text.TextColor import kotlin.math.floor import kotlin.math.roundToInt @@ -182,6 +186,19 @@ object ScoreCalculator { failedPuzzles = 0 } + @Subscription + @OnlyIn(SkyBlockIsland.THE_CATACOMBS) + fun onEntityDeath(event: EntityDeathEvent) { + if (event.entity !is Zombie && !event.entity.isBaby) return + + Text.of("mmic died yippie").send() + McClient.runNextTick { + if (!mimicKilled) return@runNextTick + McClient.sendCommand("pc Mimic Killed!") + mimicKilled = true + } + } + @Subscription @OnlyIn(SkyBlockIsland.THE_CATACOMBS) fun onChat(event: ChatReceivedEvent.Pre) { diff --git a/src/main/resources/mortem.mixins.json b/src/main/resources/mortem.mixins.json index 28b7ac7..23c0462 100644 --- a/src/main/resources/mortem.mixins.json +++ b/src/main/resources/mortem.mixins.json @@ -14,5 +14,8 @@ }, "mixinextras": { "minVersion": "0.5.0" - } + }, + "mixins": [ + "LivingEntityMixin" + ] } From 46cb177b6e142fe0a620b1a2722c44b1a0e43b66 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Thu, 20 Nov 2025 22:38:45 +0100 Subject: [PATCH 12/18] floor check for mimic --- .../kotlin/me/owdding/mortem/features/ScoreCalculator.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt index 8c0b9bf..6a0c51c 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt @@ -50,7 +50,6 @@ Puzzles: (3) */ // TODO -// Killing Mimic // Spirit Pet in Death // Prince Kill // Entrace req @@ -176,6 +175,8 @@ object ScoreCalculator { } } + private fun isMimicFloor() = DungeonAPI.dungeonFloor in listOf(DungeonFloor.F6, DungeonFloor.F7, DungeonFloor.M6, DungeonFloor.M7) + @Subscription(ServerChangeEvent::class, ServerDisconnectEvent::class) fun reset() { deaths = 0 @@ -189,7 +190,7 @@ object ScoreCalculator { @Subscription @OnlyIn(SkyBlockIsland.THE_CATACOMBS) fun onEntityDeath(event: EntityDeathEvent) { - if (event.entity !is Zombie && !event.entity.isBaby) return + if (event.entity !is Zombie && !event.entity.isBaby && !isMimicFloor()) return Text.of("mmic died yippie").send() McClient.runNextTick { @@ -204,7 +205,7 @@ object ScoreCalculator { fun onChat(event: ChatReceivedEvent.Pre) { matchWhen(event.text) { case(mimicKilledRegex) { - mimicKilled = true + if (isMimicFloor()) mimicKilled = true } } } From ba82f73644862e590a954f332dc97ace55771a22 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Thu, 20 Nov 2025 23:11:44 +0100 Subject: [PATCH 13/18] fix event posting --- src/main/java/me/owdding/mortem/mixins/LivingEntityMixin.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/owdding/mortem/mixins/LivingEntityMixin.java b/src/main/java/me/owdding/mortem/mixins/LivingEntityMixin.java index 64cbec1..e4e24db 100644 --- a/src/main/java/me/owdding/mortem/mixins/LivingEntityMixin.java +++ b/src/main/java/me/owdding/mortem/mixins/LivingEntityMixin.java @@ -6,13 +6,14 @@ import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.LivingEntity; import org.spongepowered.asm.mixin.Mixin; +import tech.thatgravyboat.skyblockapi.api.SkyBlockAPI; @Mixin(LivingEntity.class) public class LivingEntityMixin { @WrapMethod(method = "die") private void onDieWrap(DamageSource damageSource, Operation original) { - new EntityDeathEvent((LivingEntity) (Object) this, damageSource); + new EntityDeathEvent((LivingEntity) (Object) this, damageSource).post(SkyBlockAPI.getEventBus()); original.call(damageSource); } From a297f2fe076a3904365dca7ab2b1f8d19bb62d45 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Thu, 20 Nov 2025 23:17:19 +0100 Subject: [PATCH 14/18] fix: mimic if check --- src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt index 6a0c51c..eefbfc6 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt @@ -190,8 +190,7 @@ object ScoreCalculator { @Subscription @OnlyIn(SkyBlockIsland.THE_CATACOMBS) fun onEntityDeath(event: EntityDeathEvent) { - if (event.entity !is Zombie && !event.entity.isBaby && !isMimicFloor()) return - + if (event.entity !is Zombie || !event.entity.isBaby || !isMimicFloor()) return Text.of("mmic died yippie").send() McClient.runNextTick { if (!mimicKilled) return@runNextTick From 16fe842b36b2e13b4f99a2a616ef66d89b4fa272 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Thu, 20 Nov 2025 23:18:55 +0100 Subject: [PATCH 15/18] fix: another mimic thing --- src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt index eefbfc6..160ca9a 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt @@ -193,7 +193,7 @@ object ScoreCalculator { if (event.entity !is Zombie || !event.entity.isBaby || !isMimicFloor()) return Text.of("mmic died yippie").send() McClient.runNextTick { - if (!mimicKilled) return@runNextTick + if (mimicKilled) return@runNextTick McClient.sendCommand("pc Mimic Killed!") mimicKilled = true } From e3e769f7a3bf1f354fb257b4fb760a57394356e2 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Thu, 20 Nov 2025 23:28:46 +0100 Subject: [PATCH 16/18] fix: failed puzzle parsing --- src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt index 160ca9a..84339ac 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt @@ -63,7 +63,7 @@ object ScoreCalculator { // -- Tab-- private val cryptsRegex = " Crypts: (?\\d+)".toRegex() private val secretPercentageRegex = " Secrets Found: (?[\\d.]+)%".toRegex() - private val puzzleRegex = " [\\w\\s]+: \\[[✖✦]](?: \\(.*\\))?".toRegex() + private val puzzleRegex = " [\\w\\s?]+: \\[[✖✦]](?: \\(.*\\))?".toRegex() // private val requirements = enumMapOf( @@ -191,7 +191,6 @@ object ScoreCalculator { @OnlyIn(SkyBlockIsland.THE_CATACOMBS) fun onEntityDeath(event: EntityDeathEvent) { if (event.entity !is Zombie || !event.entity.isBaby || !isMimicFloor()) return - Text.of("mmic died yippie").send() McClient.runNextTick { if (mimicKilled) return@runNextTick McClient.sendCommand("pc Mimic Killed!") From 7c6a3575a1c2228afff4f27ed23688176facc296 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Thu, 20 Nov 2025 23:44:09 +0100 Subject: [PATCH 17/18] at least 20 score --- src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt index 84339ac..db7f8e3 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt @@ -114,7 +114,7 @@ object ScoreCalculator { val puzzlePenalty = 10 * failedPuzzles val deathPenalty = 2 * deaths - return 20 + roomsScore - puzzlePenalty - deathPenalty + return 20 + (roomsScore - puzzlePenalty - deathPenalty).coerceAtLeast(0) } private fun getExplorationScore(req: Requirements): Int { From e0f9d21b3fa8c1ffdfb9f33978d24d87ce27c747 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Thu, 20 Nov 2025 23:54:37 +0100 Subject: [PATCH 18/18] dying --- .../kotlin/me/owdding/mortem/features/ScoreCalculator.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt index db7f8e3..c0e72eb 100644 --- a/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt +++ b/src/main/kotlin/me/owdding/mortem/features/ScoreCalculator.kt @@ -110,7 +110,7 @@ object ScoreCalculator { } private fun getSkillScore(): Int { - val roomsScore = floor((80 * roomsClearedPercentage)).roundToInt() + val roomsScore = floor((80 * roomsClearedPercentage)).toInt() val puzzlePenalty = 10 * failedPuzzles val deathPenalty = 2 * deaths @@ -118,8 +118,8 @@ object ScoreCalculator { } private fun getExplorationScore(req: Requirements): Int { - val roomsScore = floor(60 * roomsClearedPercentage).roundToInt() - val secretsScore = floor((40 * (secretPercentage / req.secretPercentNeeded).coerceAtMost(1.0))).roundToInt() + val roomsScore = floor(60 * roomsClearedPercentage).toInt() + val secretsScore = floor((40 * (secretPercentage / req.secretPercentNeeded).coerceAtMost(1.0))).toInt() return roomsScore + secretsScore } @@ -132,7 +132,7 @@ object ScoreCalculator { val delta = (percentOver - range.start).coerceAtMost(range.endInclusive - range.start) delta / step } - return 100 - floor(lost.sum()).roundToInt() + return 100 - floor(lost.sum()).toInt() } private fun getBonusScore(): Int = buildList {