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: More info on chocolate upgrades #1594

Merged
merged 7 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ import at.hannibal2.skyhanni.features.event.chocolatefactory.ChocolateFactoryInv
import at.hannibal2.skyhanni.features.event.chocolatefactory.ChocolateFactoryShortcut
import at.hannibal2.skyhanni.features.event.chocolatefactory.ChocolateFactoryStats
import at.hannibal2.skyhanni.features.event.chocolatefactory.ChocolateFactoryTimeTowerManager
import at.hannibal2.skyhanni.features.event.chocolatefactory.ChocolateFactoryTooltip
import at.hannibal2.skyhanni.features.event.chocolatefactory.HoppityCollectionStats
import at.hannibal2.skyhanni.features.event.chocolatefactory.HoppityEggLocator
import at.hannibal2.skyhanni.features.event.chocolatefactory.HoppityEggsManager
Expand Down Expand Up @@ -633,6 +634,7 @@ class SkyHanniMod {
loadModule(ChocolateFactoryStats)
loadModule(FactoryItemTooltipFeatures)
loadModule(ChocolateFactoryTimeTowerManager)
loadModule(ChocolateFactoryTooltip)
loadModule(HoppityNpc)
loadModule(HoppityEggsManager)
loadModule(HoppityEggLocator)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ public class ChocolateFactoryConfig {
@ConfigEditorSlider(minValue = 0, maxValue = 20, minStep = 1)
public int barnCapacityThreshold = 6;

@Expose
@ConfigOption(name = "Extra Tooltip Stats", desc = "Shows extra information about upgrades in the tooltip.")
@ConfigEditorBoolean
@FeatureToggle
public boolean extraTooltipStats = true;

@Expose
@ConfigOption(name = "Hoppity Collection Stats", desc = "Shows info about your hoppity rabbit collection.")
@ConfigEditorBoolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ public static class ChocolateFactoryStorage {
@Expose
public int currentTimeTowerUses = -1;

@Expose
public int timeTowerCooldown = 8;

@Expose
public int maxTimeTowerUses = 3;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ data class HoppityEggLocationsJson(
@Expose val prestigeIndex: Int,
@Expose val milestoneIndex: Int,
@Expose val leaderboardIndex: Int,
@Expose val handCookieIndex: Int,
@Expose val timeTowerIndex: Int,
@Expose val shrineIndex: Int,
@Expose val coachRabbitIndex: Int,
@Expose val maxRabbits: Int,
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package at.hannibal2.skyhanni.features.event.chocolatefactory
import at.hannibal2.skyhanni.features.event.chocolatefactory.ChocolateFactoryAPI.profileStorage
import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators
import at.hannibal2.skyhanni.utils.SimpleTimeMark
import at.hannibal2.skyhanni.utils.TimeUtils.format
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

Expand All @@ -12,29 +13,49 @@ enum class ChocolateAmount(val chocolate: () -> Long) {
ALL_TIME({ profileStorage?.chocolateAllTime ?: 0 }),
;

val formatted get(): String = chocolate().addSeparators()
val formatted get(): String = (chocolate() + chocolateSinceUpdate()).addSeparators()

fun timeUntilGoal(goal: Long): Duration {
fun formattedTimeUntilGoal(goal: Long): String {
val time = timeUntilGoal(goal)
return when {
time.isInfinite() -> "§cNever"
time.isNegative() -> "§aNow"
else -> "§6${time.format()}"
}
}

private fun timeUntilGoal(goal: Long): Duration {
val profileStorage = ChocolateFactoryAPI.profileStorage ?: return Duration.ZERO

val updatedAgo = SimpleTimeMark(profileStorage.lastDataSave).passedSince().inWholeSeconds

val baseMultiplier = profileStorage.rawChocolateMultiplier
val baseChocolatePerSecond = profileStorage.rawChocPerSecond
val rawChocolatePerSecond = profileStorage.rawChocPerSecond
val timeTowerMultiplier = baseMultiplier + profileStorage.timeTowerLevel * 0.1

var needed = goal - chocolate()
val secondsUntilTowerExpires = ChocolateFactoryTimeTowerManager.timeTowerActiveDuration().inWholeSeconds

val timeTowerChocPerSecond = baseChocolatePerSecond * timeTowerMultiplier
val timeTowerChocPerSecond = rawChocolatePerSecond * timeTowerMultiplier

val secondsAtRate = needed / timeTowerChocPerSecond
if (secondsAtRate < secondsUntilTowerExpires) {
return secondsAtRate.seconds - updatedAgo.seconds
}

needed -= (secondsUntilTowerExpires * timeTowerChocPerSecond).toLong()
val chocPerSecond = baseChocolatePerSecond * baseMultiplier
return (needed / chocPerSecond + secondsUntilTowerExpires).seconds - updatedAgo.seconds
val basePerSecond = rawChocolatePerSecond * baseMultiplier
return (needed / basePerSecond + secondsUntilTowerExpires).seconds - updatedAgo.seconds
}

companion object {
fun chocolateSinceUpdate(): Long {
val lastUpdate = SimpleTimeMark(profileStorage?.lastDataSave ?: return 0)
val currentTime = SimpleTimeMark.now()
val secondsSinceUpdate = (currentTime - lastUpdate).inWholeSeconds

val perSecond = ChocolateFactoryAPI.chocolatePerSecond
return (perSecond * secondsSinceUpdate).toLong()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.config.features.event.ChocolateFactoryConfig
import at.hannibal2.skyhanni.config.storage.ProfileSpecificStorage.ChocolateFactoryStorage
import at.hannibal2.skyhanni.data.ProfileStorageData
import at.hannibal2.skyhanni.data.jsonobjects.repo.DisabledFeaturesJson
import at.hannibal2.skyhanni.data.jsonobjects.repo.HoppityEggLocationsJson
import at.hannibal2.skyhanni.events.InventoryCloseEvent
import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent
Expand Down Expand Up @@ -107,10 +106,13 @@ object ChocolateFactoryAPI {
var barnIndex = 34
private var infoIndex = 13
private var productionInfoIndex = 45
private var prestigeIndex = 28
var prestigeIndex = 28
var milestoneIndex = 53
private var leaderboardIndex = 51
var handCookieIndex = 38
var timeTowerIndex = 39
var shrineIndex = 41
var coachRabbitIndex = 42
var maxRabbits = 395

var inChocolateFactory = false
Expand Down Expand Up @@ -174,7 +176,7 @@ object ChocolateFactoryAPI {
}

val lore = item.getLore()
val upgradeCost = lore.getUpgradeCost() ?: continue
val upgradeCost = getChocolateUpgradeCost(lore) ?: continue

val canAfford = upgradeCost <= ChocolateAmount.CURRENT.chocolate()
if (canAfford) upgradeableSlots.add(slotIndex)
Expand Down Expand Up @@ -316,14 +318,17 @@ object ChocolateFactoryAPI {
prestigeIndex = data.prestigeIndex
milestoneIndex = data.milestoneIndex
leaderboardIndex = data.leaderboardIndex
handCookieIndex = data.handCookieIndex
timeTowerIndex = data.timeTowerIndex
shrineIndex = data.shrineIndex
coachRabbitIndex = data.coachRabbitIndex
maxRabbits = data.maxRabbits

val disabledFeatures = event.getConstant<DisabledFeaturesJson>("DisabledFeatures")
ChocolateFactoryTooltip.updateIgnoredSlots()
}

private fun List<String>.getUpgradeCost(): Long? {
val nextLine = this.nextAfter({ UtilsPatterns.costLinePattern.matches(it) }) ?: return null
fun getChocolateUpgradeCost(lore: List<String>): Long? {
val nextLine = lore.nextAfter({ UtilsPatterns.costLinePattern.matches(it) }) ?: return null
return chocolateAmountPattern.matchMatcher(nextLine.removeColor()) {
group("amount").formatLong()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ package at.hannibal2.skyhanni.features.event.chocolatefactory

import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator
import at.hannibal2.skyhanni.events.GuiRenderEvent
import at.hannibal2.skyhanni.events.SecondPassedEvent
import at.hannibal2.skyhanni.utils.ClipboardUtils
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators
import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables
import at.hannibal2.skyhanni.utils.StringUtils.removeColor
import at.hannibal2.skyhanni.utils.TimeUtils.format
import at.hannibal2.skyhanni.utils.renderables.Renderable
import com.google.gson.JsonPrimitive
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import kotlin.time.Duration

object ChocolateFactoryStats {

Expand All @@ -20,6 +19,13 @@ object ChocolateFactoryStats {

private var display = listOf<Renderable>()

@SubscribeEvent
fun onSecondPassed(event: SecondPassedEvent) {
if (!LorenzUtils.inSkyBlock) return
if (!ChocolateFactoryAPI.chocolateFactoryPaused) return
updateDisplay()
}

@SubscribeEvent
fun onBackgroundDraw(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) {
if (!ChocolateFactoryAPI.inChocolateFactory && !ChocolateFactoryAPI.chocolateFactoryPaused) return
Expand All @@ -43,14 +49,7 @@ object ChocolateFactoryStats {
"§6${ChocolateFactoryTimeTowerManager.timeTowerCharges()}"
}

val timeUntilPrestige = ChocolateAmount.PRESTIGE.timeUntilGoal(ChocolateFactoryAPI.chocolateForPrestige)

// todo once TimeUtils.formatDuration() is no longer used add custom formatting for infinite
val prestigeEstimate = if (timeUntilPrestige == Duration.INFINITE) {
"§cNever"
} else {
"§6${timeUntilPrestige.format()}"
}
val prestigeEstimate = ChocolateAmount.PRESTIGE.formattedTimeUntilGoal(ChocolateFactoryAPI.chocolateForPrestige)

val text = formatList(buildList {
add("§6§lChocolate Factory Stats")
Expand Down Expand Up @@ -78,18 +77,6 @@ object ChocolateFactoryStats {
add("§eRaw Per Second: §6${profileStorage.rawChocPerSecond.addSeparators()}")
})

// TODO keep counting, we dont want pauses
// val firstElement = displayText.firstOrNull { it.isNotEmpty() } ?: return
//
// if (ChocolateFactoryAPI.chocolateFactoryPaused) {
// val leftMargin = (firstElement.width() - "§f(§cPaused§f)".width()) / 2
// val spaceWidth = " ".width()
// displayText.add(0, "${" ".repeat(leftMargin / spaceWidth)}§f(§cPaused§f)")
// } else {
// displayText.add(0, "")
// }
// displayList = displayText.map(Renderable::string).toMutableList()

display = listOf(Renderable.clickAndHover(
Renderable.verticalContainer(text.map(Renderable::string)),
tips = listOf("§bCopy to Clipboard!"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import at.hannibal2.skyhanni.utils.SoundUtils
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import kotlin.time.Duration
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds

Expand All @@ -37,8 +38,7 @@ object ChocolateFactoryTimeTowerManager {
if (nextCharge.isInPast() && !nextCharge.isFarPast() && currentCharges() < maxCharges()) {
profileStorage.currentTimeTowerUses++

// todo in future once have Einstein rabbit account for that
val nextTimeTower = SimpleTimeMark(profileStorage.nextTimeTower) + 8.hours
val nextTimeTower = SimpleTimeMark(profileStorage.nextTimeTower) + (profileStorage.timeTowerCooldown).hours
profileStorage.nextTimeTower = nextTimeTower.toMillis()

if (!config.timeTowerWarning) return
Expand Down Expand Up @@ -90,11 +90,20 @@ object ChocolateFactoryTimeTowerManager {

fun timeTowerFull() = currentCharges() >= maxCharges()

fun timeTowerActive() = profileStorage?.currentTimeTowerEnds != 0L
fun timeTowerActive(): Boolean {
val currentTime = profileStorage?.lastDataSave ?: 0
val endTime = profileStorage?.currentTimeTowerEnds ?: 0

return endTime > currentTime
}

fun timeTowerActiveDuration(): Duration {
if (!timeTowerActive()) return Duration.ZERO
return SimpleTimeMark(profileStorage?.currentTimeTowerEnds ?: 0).timeUntil()
val currentTime = profileStorage?.lastDataSave ?: 0
val endTime = profileStorage?.currentTimeTowerEnds ?: 0

val duration = endTime - currentTime
return duration.milliseconds
}

@SubscribeEvent
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package at.hannibal2.skyhanni.features.event.chocolatefactory

import at.hannibal2.skyhanni.events.LorenzToolTipEvent
import at.hannibal2.skyhanni.features.event.chocolatefactory.ChocolateFactoryAPI.profileStorage
import at.hannibal2.skyhanni.utils.LorenzUtils.round
import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators
import net.minecraftforge.fml.common.eventhandler.EventPriority
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent

object ChocolateFactoryTooltip {

private val config get() = ChocolateFactoryAPI.config

private var ignoredSlotIndexes = listOf<Int>()

fun updateIgnoredSlots() {
ignoredSlotIndexes = listOf(
ChocolateFactoryAPI.prestigeIndex,
ChocolateFactoryAPI.handCookieIndex,
ChocolateFactoryAPI.shrineIndex,
ChocolateFactoryAPI.barnIndex,
)
}

@SubscribeEvent(priority = EventPriority.HIGH)
fun onTooltip(event: LorenzToolTipEvent) {
if (!ChocolateFactoryAPI.inChocolateFactory) return
if (!config.extraTooltipStats) return

val slotIndex = event.slot.slotNumber
if (slotIndex == ChocolateFactoryAPI.prestigeIndex) return
if (slotIndex !in ChocolateFactoryAPI.otherUpgradeSlots && slotIndex !in ChocolateFactoryAPI.rabbitSlots) return

val upgradeCost = ChocolateFactoryAPI.getChocolateUpgradeCost(event.toolTip) ?: return

event.toolTip.add("§8§m-----------------")
val timeToUpgrade = ChocolateAmount.CURRENT.formattedTimeUntilGoal(upgradeCost)

event.toolTip.add("§7Time until upgrade: §e$timeToUpgrade")

if (slotIndex in ignoredSlotIndexes) return

val averageChocolate = averageChocPerSecond().round(2)

val newAverageChocolate = when (slotIndex) {
in ChocolateFactoryAPI.rabbitSlots -> {
val chocolateIncrease = ChocolateFactoryAPI.rabbitSlots[slotIndex] ?: 0
averageChocPerSecond(rawPerSecondIncrease = chocolateIncrease)
}

ChocolateFactoryAPI.timeTowerIndex -> averageChocPerSecond(timeTowerLevelIncrease = 1)
ChocolateFactoryAPI.coachRabbitIndex -> averageChocPerSecond(baseMultiplierIncrease = 0.01)
else -> averageChocolate
}.round(2)

val extra = (newAverageChocolate - averageChocolate).round(2)
val ratioForUpgrade = (upgradeCost / extra).round(2)

event.toolTip.add("§7Extra: §6$extra §7choc/s")
event.toolTip.add("§7Effective Cost: §6${ratioForUpgrade.addSeparators()}")

if (slotIndex == ChocolateFactoryAPI.timeTowerIndex) {
event.toolTip.add("§7One charge will give: §6${chocPerTimeTower().addSeparators()}")
}
}

private fun averageChocPerSecond(
baseMultiplierIncrease: Double = 0.0,
rawPerSecondIncrease: Int = 0,
timeTowerLevelIncrease: Int = 0,
): Double {
val profileStorage = profileStorage ?: return 0.0

val baseMultiplier = profileStorage.chocolateMultiplier + baseMultiplierIncrease
val rawPerSecond = profileStorage.rawChocPerSecond + rawPerSecondIncrease
val timeTowerLevel = profileStorage.timeTowerLevel + timeTowerLevelIncrease

val timeTowerCooldown = profileStorage.timeTowerCooldown

val basePerSecond = rawPerSecond * baseMultiplier
val towerCalc = (rawPerSecond * timeTowerLevel * .1) / timeTowerCooldown

return basePerSecond + towerCalc
}

private fun chocPerTimeTower(): Int {
val profileStorage = profileStorage ?: return 0
val amountPerSecond = profileStorage.rawChocPerSecond * profileStorage.timeTowerLevel * .1
val amountPerHour = amountPerSecond * 60 * 60
return amountPerHour.toInt()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ class HoppityCollectionStats {
}

val rarity = rabbitRarity ?: continue

if (itemName == "§dEinstein" && found) {
ChocolateFactoryAPI.profileStorage?.timeTowerCooldown = 7
}

val duplicates = duplicatesFound.coerceAtLeast(0)
loggedRabbits[itemName] = RabbitCollectionInfo(rarity, found, duplicates)
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/at/hannibal2/skyhanni/utils/UtilsPatterns.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ object UtilsPatterns {
)
val costLinePattern by patternGroup.pattern(
"item.cost.line",
"§7Cost"
"(?:§5§o)?§7Cost"
)

val timeAmountPattern by patternGroup.pattern(
Expand Down
Loading