Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Armor Stack Decay Timer #2538

Open
wants to merge 7 commits into
base: beta
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package at.hannibal2.skyhanni.config.features.combat;

import at.hannibal2.skyhanni.config.FeatureToggle;
import at.hannibal2.skyhanni.config.core.config.Position;
import com.google.gson.annotations.Expose;
import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean;
import io.github.notenoughupdates.moulconfig.annotations.ConfigLink;
import io.github.notenoughupdates.moulconfig.annotations.ConfigOption;

public class ArmorStackDisplayConfig {
@Expose
@ConfigOption(name = "Enable", desc = "Enable the armor stack display feature.")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please explain a bit more what this feature does. (include crimson armor names maybe, or their ability names)

@ConfigEditorBoolean
@FeatureToggle
public boolean enabled = true;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please make this default diabled


@Expose
@ConfigOption(name = "Single Line Display", desc = "Show the overlay in a single line.")
@ConfigEditorBoolean
@FeatureToggle
public boolean showInSingleLine = true;

@Expose
@ConfigOption(name = "Show Armor Stack", desc = "Display the current number of stacks for armors, such as Crimson, Terror, Aurora, etc.")
@ConfigEditorBoolean
@FeatureToggle
public boolean armorStackDisplay = true;

@Expose
@ConfigOption(name = "Show Armor Stack Type", desc = "Display the type of armor stack, such as 'Dominus', 'Hydra Strike', etc.")
@ConfigEditorBoolean
@FeatureToggle
public boolean armorStackType = false;

@Expose
@ConfigOption(name = "Show Stack Decay Timer", desc = "Display a timer that shows when the armor stack will decay.")
@ConfigEditorBoolean
@FeatureToggle
public boolean armorStackDecayTimer = true;

@Expose
@ConfigOption(name = "Max Stack Only", desc = "Display the decay timer only for the 10th stack.")
@ConfigEditorBoolean
@FeatureToggle
public boolean maxStackOnly = false;

@Expose
@ConfigLink(owner = ArmorStackDisplayConfig.class, field = "enabled")
public Position position = new Position(50, -210, 1.4f);
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ public class CombatConfig {
public QuiverConfig quiverConfig = new QuiverConfig();

@Expose
@ConfigOption(name = "Armor Stack Display", desc = "")
@ConfigOption(name = "Armor Stack", desc = "")
@Accordion
// TODO rename to armor stack display
public StackDisplayConfig stackDisplayConfig = new StackDisplayConfig();
public ArmorStackDisplayConfig armorStackDisplayConfig = new ArmorStackDisplayConfig();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove the suffix "Config" from the variable name (not the class name)


@Expose
@ConfigOption(name = "Summonings", desc = "")
Expand Down

This file was deleted.

142 changes: 132 additions & 10 deletions src/main/java/at/hannibal2/skyhanni/features/combat/ArmorStackDisplay.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,162 @@ package at.hannibal2.skyhanni.features.combat
import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.events.ActionBarUpdateEvent
import at.hannibal2.skyhanni.events.GuiRenderEvent
import at.hannibal2.skyhanni.events.LorenzTickEvent
import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent
import at.hannibal2.skyhanni.events.PlaySoundEvent
import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
import at.hannibal2.skyhanni.utils.InventoryUtils
import at.hannibal2.skyhanni.utils.ItemUtils.getLore
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.RegexUtils.findMatcher
import at.hannibal2.skyhanni.utils.RenderUtils.renderString
import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings
import at.hannibal2.skyhanni.utils.SimpleTimeMark
import at.hannibal2.skyhanni.utils.TimeUtils.format
import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import kotlin.time.Duration.Companion.milliseconds

@SkyHanniModule
object ArmorStackDisplay {
private val config get() = SkyHanniMod.feature.combat.stackDisplayConfig
private var display = ""
private val config get() = SkyHanniMod.feature.combat.armorStackDisplayConfig
private var stackCount = 0
private var stackSymbol = ""
private var stackType = ""
private var armorPieceCount = 0
private var display = listOf<String>()
private var stackDecayTimeCurrent = SimpleTimeMark.farPast()

/**
* REGEX-TEST: §66,171/4,422❤ §6§l10ᝐ§r §a1,295§a❈ Defense §b525/1,355✎ §3400ʬ
* REGEX-TEST: §66,171/4,422❤ §65ᝐ §b-150 Mana (§6Wither Impact§b) §b1,016/1,355✎ §3400ʬ
*/
private val armorStackPattern by RepoPattern.pattern(
private val stackPattern by RepoPattern.pattern(
"combat.armorstack.actionbar",
" (?:§6|§6§l)(?<stack>\\d+[ᝐ⁑|҉Ѫ⚶])"
" (?:§6|§6§l)(?<stack>\\d+)(?<symbol>[ᝐ⁑|҉Ѫ⚶])",
)

/**
* REGEX-TEST: §7Health: §a+205, §7Defense: §a+55, §7Intelligence: §a+125, §7Combat Wisdom: §a+0.75, §8[§8⚔§8] §8[§8⚔§8], , §bArachno Resistance II, §7Grants §a+3❈ Defense §7against §aspiders§7., §bVeteran I, §7Grants §3+0.75☯ Combat Wisdom§7., , §6Tiered Bonus: Arcane Vision (2/4), §7Gives you the ability to see the runic, §7affinity of enemies., §7, §7Using the proper §bRune §7when casting spells, §7from §bRunic Items §7grants 1 stack of §6Arcane, §6Vision Ѫ§7., §7, §7Each §6Arcane Vision Ѫ §7stack grants you §c+2%, §c§7damage on your §bRunic Spells§7., §7, §7At §c10 §7stacks, the spells also explode on hit., §7, §7Lose 1 stack after §c4s §7of not gaining a stack., , §7§8This item can be reforged!, §6§lLEGENDARY LEGGINGS
*/
private val armorStackTierBonus by RepoPattern.pattern(
"combat.armorstack.armor",
"§6Tiered Bonus: (?<type>.*) \\((?<amount>\\d)\\/4\\)"
)

@SubscribeEvent
fun onActionBar(event: ActionBarUpdateEvent) {
if (!isEnabled()) return
val stacks = armorStackPattern.findMatcher(event.actionBar) {
"§6§l" + group("stack")
} ?: ""
display = stacks

stackPattern.findMatcher(event.actionBar) {
updateStack(group("stack").toInt(), group("symbol"))
} ?: resetStack()

if (config.armorStackDisplay) event.changeActionBar(event.actionBar.replace(Regex("$stackPattern"), "").trim())
}

@SubscribeEvent
fun onPlaySound(event: PlaySoundEvent) {
if (!isEnabled() && !config.armorStackDecayTimer) return
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think the AND here is wrong, a OR makes more sense to me

if (event.soundName in listOf("tile.piston.out", "tile.piston.in") &&
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please move the list into a member of the class so that we dont need to recreate it each time

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

additionally, a set is probably better than a list here?

event.pitch == 1.0f && event.volume == 3.0f) {
resetDecayTime()
}
}

@SubscribeEvent
fun onWorldChange(event: LorenzWorldChangeEvent) {
if (!isEnabled()) return
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the check here can go

resetStack()
}

@SubscribeEvent
fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) {
if (isEnabled()) {
config.position.renderStrings(display, posLabel = "Armor Stack Display")
}
}

@SubscribeEvent
fun onTick(event: LorenzTickEvent) {
if (!isEnabled()) return
config.position.renderString(display, posLabel = "Armor Stack Display")
display = drawDisplay()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a check so that this only happens every second tick (10 times a second, not 20 times a second). Can be done via event.isMod(2)

}

private fun drawDisplay(): List<String> {
if (stackCount == 0 || armorPieceCount < 3) return emptyList()
val displaySingleLine = config.showInSingleLine
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the config variables here can all be removed/inlined (not the isMaxStack one)

val showStack = config.armorStackDisplay
val showTimer = config.armorStackDecayTimer
val maxStackOnly = config.maxStackOnly
val isMaxStack = stackCount == 10

val decayTimeString = if (showTimer) {
val remainingTime = stackDecayTimeCurrent.timeUntil().coerceAtLeast(0.milliseconds)
remainingTime.format(showMilliSeconds = true, showSmallerUnits = true)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im not enitrely sure, but i think showSmallerUnits can be kept as default false here

} else ""

val colorCode = when {
isMaxStack && maxStackOnly -> "§b"
isMaxStack -> "§9"
else -> "§b"
}

if (displaySingleLine) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can move the two returns below to this if block directly

return listOf(buildString {
if (showStack) {
append("§6")
if (config.armorStackType) append("$stackType: ")
append("§l$stackCount$stackSymbol ")
}

if (showTimer && (!maxStackOnly || isMaxStack)) {
append("$colorCode($decayTimeString)")

}
})
} else {
return buildList {
if (showStack) {
add(buildString {
append("§6")
if (config.armorStackType) append("$stackType: ")
append("§l$stackCount$stackSymbol ")
})
}

if (showTimer && (!maxStackOnly || isMaxStack)) {
add("$colorCode$decayTimeString")
}
}
}
}

private fun resetDecayTime() {
armorPieceCount = InventoryUtils.getArmor().firstNotNullOfOrNull { armor ->
val lore = armor?.getLore().toString()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont like the getLore().toString() workaround here. i think we have another matcher utils function that works with a list and uses the first/last directly

armorStackTierBonus.findMatcher(lore) { stackType = group("type"); group("amount") }
?.toInt()
} ?: 0


val stackDecayTime = when (armorPieceCount) {
2 -> 4000
3 -> 7000
4 -> 10000
else -> 0
}.milliseconds
stackDecayTimeCurrent = SimpleTimeMark.now() + stackDecayTime
}

private fun resetStack() {
stackCount = 0
stackSymbol = ""
}

private fun updateStack(newStackCount: Int, newStackSymbol: String) {
if (stackCount != newStackCount && config.armorStackDecayTimer) resetDecayTime()
stackCount = newStackCount
stackSymbol = newStackSymbol
}

fun isEnabled() = LorenzUtils.inSkyBlock && config.enabled
Expand Down
Loading