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 {