diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/RiftAreasConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/RiftAreasConfig.java index 9db3e9f5c1ea..b7cb04aeee96 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/RiftAreasConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/RiftAreasConfig.java @@ -4,6 +4,7 @@ import at.hannibal2.skyhanni.config.features.rift.area.dreadfarm.DreadfarmConfig; import at.hannibal2.skyhanni.config.features.rift.area.livingcave.LivingCaveConfig; import at.hannibal2.skyhanni.config.features.rift.area.mirrorverse.MirrorVerseConfig; +import at.hannibal2.skyhanni.config.features.rift.area.mountaintop.MountaintopConfig; import at.hannibal2.skyhanni.config.features.rift.area.stillgorechateau.StillgoreChateauConfig; import at.hannibal2.skyhanni.config.features.rift.area.westvillage.WestVillageConfig; import at.hannibal2.skyhanni.config.features.rift.area.wyldwoods.WyldWoodsConfig; @@ -53,8 +54,8 @@ public class RiftAreasConfig { @Accordion public StillgoreChateauConfig stillgoreChateau = new StillgoreChateauConfig(); -// @Expose -// @ConfigOption(name = "Mountaintop", desc = "") -// @Accordion -// public MountaintopConfig mountaintop = new MountaintopConfig(); + @Expose + @ConfigOption(name = "Mountaintop", desc = "") + @Accordion + public MountaintopConfig mountaintop = new MountaintopConfig(); } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/mountaintop/MountaintopConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/mountaintop/MountaintopConfig.java new file mode 100644 index 000000000000..c056120361e0 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/mountaintop/MountaintopConfig.java @@ -0,0 +1,15 @@ +package at.hannibal2.skyhanni.config.features.rift.area.mountaintop; + +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.Accordion; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class MountaintopConfig { + + @Expose + @ConfigOption(name = "Timite", desc = "") + @Accordion + public TimiteConfig timite = new TimiteConfig(); + +} + diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/mountaintop/TimiteConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/mountaintop/TimiteConfig.java new file mode 100644 index 000000000000..bf3fc88cfa69 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/rift/area/mountaintop/TimiteConfig.java @@ -0,0 +1,33 @@ +package at.hannibal2.skyhanni.config.features.rift.area.mountaintop; + +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 TimiteConfig { + + @Expose + @ConfigOption(name = "Timite Timer", desc = "Count down the time until Timite evolves with the time gun.") + @ConfigEditorBoolean + public boolean timiteTimer = true; + + @Expose + @ConfigOption(name = "Timite Expiry Timer", desc = "Count down the time until Timite/Obsolite expires.") + @ConfigEditorBoolean + public boolean timiteExpiryTimer = true; + + @Expose + @ConfigOption(name = "Timite Tracker", desc = "Tracks collected Timite ores and shows mote profit") + @ConfigEditorBoolean + public boolean timiteTracker = false; + + @Expose + @ConfigLink(owner = TimiteConfig.class, field = "timiteTimer") + public Position timerPos = new Position(421, -220, false, true); + + @Expose + @ConfigLink(owner = TimiteConfig.class, field = "timiteTracker") + public Position trackerPos = new Position(-201, -220, false, true); +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java index 44e4fd6dfd65..d3df7460e86a 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java +++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java @@ -40,6 +40,8 @@ import at.hannibal2.skyhanni.features.mining.powdertracker.PowderTracker; import at.hannibal2.skyhanni.features.misc.DraconicSacrificeTracker; import at.hannibal2.skyhanni.features.misc.trevor.TrevorTracker; +import at.hannibal2.skyhanni.features.rift.area.mountaintop.TimiteHelper; +import at.hannibal2.skyhanni.features.rift.area.mountaintop.TimiteTracker; import at.hannibal2.skyhanni.features.rift.area.westvillage.VerminTracker; import at.hannibal2.skyhanni.features.rift.area.westvillage.kloon.KloonTerminal; import at.hannibal2.skyhanni.features.skillprogress.SkillType; @@ -885,4 +887,7 @@ public int hashCode() { ); } } + + @Expose + public TimiteTracker.Data timiteHelperTracker = new TimiteTracker.Data(); } diff --git a/src/main/java/at/hannibal2/skyhanni/features/rift/RiftAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/rift/RiftAPI.kt index 00405c9ff5bf..e601f3978ac8 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/rift/RiftAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/rift/RiftAPI.kt @@ -52,4 +52,9 @@ object RiftAPI { fun inStillgoreChateau() = LorenzUtils.skyBlockArea.let { it == "Stillgore Château" || it == "Oubliette" } fun inDreadfarm() = LorenzUtils.skyBlockArea == "Dreadfarm" fun inWestVillage() = LorenzUtils.skyBlockArea.let { it == "West Village" || it == "Infested House" } + fun inMountainTop() = when (LorenzUtils.skyBlockArea) { + "Continuum", "The Mountaintop", "Trial Grounds", "Time-Torn Isles", + "Wizardman Bureau", "Wizard Brawl", "Walk of Fame", "Time Chamber" -> true + else -> false + } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/rift/area/mountaintop/TimiteHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/rift/area/mountaintop/TimiteHelper.kt new file mode 100644 index 000000000000..46abcd545e5f --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/rift/area/mountaintop/TimiteHelper.kt @@ -0,0 +1,143 @@ +package at.hannibal2.skyhanni.features.rift.area.mountaintop + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.event.HandleEvent +import at.hannibal2.skyhanni.data.ClickType +import at.hannibal2.skyhanni.events.BlockClickEvent +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent +import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent +import at.hannibal2.skyhanni.events.SecondPassedEvent +import at.hannibal2.skyhanni.features.rift.RiftAPI +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.BlockUtils.getBlockAt +import at.hannibal2.skyhanni.utils.BlockUtils.getBlockStateAt +import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.LocationUtils +import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer +import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName +import at.hannibal2.skyhanni.utils.RenderUtils.drawDynamicText +import at.hannibal2.skyhanni.utils.RenderUtils.renderString +import at.hannibal2.skyhanni.utils.SimpleTimeMark +import at.hannibal2.skyhanni.utils.TimeUtils.format +import at.hannibal2.skyhanni.utils.toLorenzVec +import net.minecraft.block.BlockStainedGlassPane +import net.minecraft.block.state.IBlockState +import net.minecraft.init.Blocks +import net.minecraft.item.EnumDyeColor +import net.minecraft.util.BlockPos +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds + +@SkyHanniModule +object TimiteHelper { + + private val TIME_GUN = "TIME_GUN".toInternalName() + private var holdingClick = SimpleTimeMark.farPast() + private var lastClick = SimpleTimeMark.farPast() + private val config get() = SkyHanniMod.feature.rift.area.mountaintop.timite + private var currentPos: LorenzVec? = null + private var currentBlockState: IBlockState? = null + private var doubleTimeShooting = false + + @HandleEvent + fun onBlockHit(event: BlockClickEvent) { + if (!isEnabled()) return + if (InventoryUtils.itemInHandId != TIME_GUN) return + if (event.clickType != ClickType.RIGHT_CLICK) return + if (event.position != currentPos || currentBlockState != event.getBlockState) { + lastClick = SimpleTimeMark.farPast() + + if (event.position == currentPos && currentBlockState != event.getBlockState) { + timiteLocations[event.position] = SimpleTimeMark.now() + doubleTimeShooting = true + } else { + doubleTimeShooting = false + } + } + currentPos = event.position + currentBlockState = event.getBlockState + if (event.getBlockState.block != Blocks.stained_glass_pane) return + val color = event.getBlockState.getValue(BlockStainedGlassPane.COLOR) + if (color != EnumDyeColor.BLUE && color != EnumDyeColor.LIGHT_BLUE) return + if (lastClick + 300.milliseconds > SimpleTimeMark.now()) { + lastClick = SimpleTimeMark.now() + return + } + lastClick = SimpleTimeMark.now() + holdingClick = SimpleTimeMark.now() + } + + @SubscribeEvent + fun onGuiRender(event: GuiRenderEvent.GuiOverlayRenderEvent) { + if (!isEnabled()) return + if (InventoryUtils.itemInHandId != TIME_GUN) return + if (lastClick + 400.milliseconds < SimpleTimeMark.now()) { + holdingClick = SimpleTimeMark.farPast() + doubleTimeShooting = false + } + if (holdingClick.isFarPast()) return + + if ((currentBlockState?.block ?: return) != Blocks.stained_glass_pane) return + // this works for me but idk if ive just tuned it for my ping only + val time = if (doubleTimeShooting) 1800 else 2000 + val timeLeft = holdingClick + time.milliseconds + if (!timeLeft.isInPast()) { + val formattedTime = timeLeft.timeUntil().format(showMilliSeconds = true) + config.timerPos.renderString("§b$formattedTime", 0, 0, "Timite Helper") + } + } + + private val timiteLocations = mutableMapOf() + + @SubscribeEvent + fun onSecondPassed(event: SecondPassedEvent) { + val location = LocationUtils.playerLocation() + val from = location.add(-15, -15, -15).toBlockPos() + val to = location.add(15, 15, 15).toBlockPos() + + for (pos in BlockPos.getAllInBox(from, to)) { + val loc = pos.toLorenzVec() + if (loc.getBlockAt() == Blocks.stained_glass_pane && loc.distanceToPlayer() <= 15) { + val color = loc.getBlockStateAt().getValue(BlockStainedGlassPane.COLOR) + if (color != EnumDyeColor.BLUE && color != EnumDyeColor.LIGHT_BLUE) continue + if (timiteLocations[loc] == null) timiteLocations[loc] = SimpleTimeMark.now() + } + } + val iterator = timiteLocations.entries.iterator() + while (iterator.hasNext()) { + val entry = iterator.next() + if (entry.key.getBlockAt() == Blocks.air) { + iterator.remove() + } else if (entry.key.getBlockAt() == Blocks.stained_glass_pane) { + val color = entry.key.getBlockStateAt().getValue(BlockStainedGlassPane.COLOR) + if (color == EnumDyeColor.LIGHT_BLUE) { + iterator.remove() + } + } + } + + + } + + @SubscribeEvent + fun onBlockRender(event: LorenzRenderWorldEvent) { + if (!RiftAPI.inMountainTop() || !config.timiteExpiryTimer) return + + for (timiteLocation in timiteLocations.entries) { + val timeLeft = timiteLocation.value + 31.seconds + if (timeLeft.timeUntil() < 6.seconds) { + event.drawDynamicText(timiteLocation.key, "§c${timeLeft.timeUntil().format()}", 1.5) + } + } + } + + @SubscribeEvent + fun onWorldChange(event: LorenzWorldChangeEvent) = timiteLocations.clear() + + + private fun isEnabled() = RiftAPI.inMountainTop() && config.timiteTimer + +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/rift/area/mountaintop/TimiteTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/rift/area/mountaintop/TimiteTracker.kt new file mode 100644 index 000000000000..7b88522e26fa --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/rift/area/mountaintop/TimiteTracker.kt @@ -0,0 +1,144 @@ +package at.hannibal2.skyhanni.features.rift.area.mountaintop + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.event.HandleEvent +import at.hannibal2.skyhanni.config.commands.CommandCategory +import at.hannibal2.skyhanni.config.commands.CommandRegistrationEvent +import at.hannibal2.skyhanni.data.ItemAddManager +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.ItemAddEvent +import at.hannibal2.skyhanni.features.rift.RiftAPI +import at.hannibal2.skyhanni.features.rift.RiftAPI.motesNpcPrice +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.CollectionUtils.addSearchString +import at.hannibal2.skyhanni.utils.ItemUtils +import at.hannibal2.skyhanni.utils.NEUInternalName +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName +import at.hannibal2.skyhanni.utils.NEUItems +import at.hannibal2.skyhanni.utils.NEUItems.getItemStack +import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat +import at.hannibal2.skyhanni.utils.TimeUtils.format +import at.hannibal2.skyhanni.utils.renderables.Renderable +import at.hannibal2.skyhanni.utils.renderables.Searchable +import at.hannibal2.skyhanni.utils.renderables.toSearchable +import at.hannibal2.skyhanni.utils.tracker.ItemTrackerData +import at.hannibal2.skyhanni.utils.tracker.SkyHanniItemTracker +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration.Companion.seconds + +@SkyHanniModule +object TimiteTracker { + + private val config get() = SkyHanniMod.feature.rift.area.mountaintop.timite + private val HIGHLITE = "HIGHLITE".toInternalName() + + + class Data : ItemTrackerData() { + override fun resetItems() { + "detekt ur a stupid fucker" + } + + override fun getDescription(timesGained: Long): List { + return emptyList() + } + + override fun getCoinName(item: TrackedItem): String { + return "§5Motes" + } + + override fun getCoinDescription(item: TrackedItem): List { + return emptyList() + } + + override fun getCustomPricePer(internalName: NEUInternalName): Double { + return internalName.getItemStack().motesNpcPrice() ?: 0.0 + } + + fun getTime(): Int { + this.items["TIMITE".toInternalName()]?.let { + return it.totalAmount.toInt() * 2 + } + return 0 + } + + } + + private fun drawDisplay(data: Data): List = buildList { + addSearchString("§9§lTimite Tracker") + val profit = tracker.drawItems(data, { true }, this) + + + val highliteRecipe = NEUItems.getRecipes(HIGHLITE).singleOrNull() + if (highliteRecipe != null) { + var craftableAmount = 0 + + for (neededItem in ItemUtils.neededItems(highliteRecipe)) { + if (neededItem.key in validItems) { + data.items[neededItem.key]?.let { + val amountCanCraft = it.totalAmount.toInt() / neededItem.value + if (craftableAmount == 0 || amountCanCraft < craftableAmount) { + craftableAmount = amountCanCraft + } + } + } + } + val stack = HIGHLITE.getItemStack() + val motes = stack.motesNpcPrice()?.times(craftableAmount)?.shortFormat() ?: "0" + if (craftableAmount > 0) { + add( + Renderable.string( + " §7${craftableAmount.shortFormat()}x ${stack.displayName} Craftable§7: §5$motes motes" + ).toSearchable() + ) + } + } + + add(Renderable.string("§aTime§7: §a${data.getTime().seconds.format()}ф").toSearchable()) + + + add( + Renderable.string( + "§dTotal Profit§7: §5${profit.toInt().shortFormat()} Motes" + ).toSearchable() + ) + + } + + private val tracker = + SkyHanniItemTracker("Timite Tracker", { Data() }, { it.timiteHelperTracker }) { + drawDisplay(it) + } + + private val validItems = listOf( + "TIMITE".toInternalName(), + "YOUNGITE".toInternalName(), + "OBSOLITE".toInternalName(), + ) + + @HandleEvent + fun onItem(event: ItemAddEvent) { + + if (validItems.contains(event.internalName)) { + tracker.addItem(event.internalName, event.amount, event.source == ItemAddManager.Source.COMMAND) + } + } + + @SubscribeEvent + fun onRender(event: GuiRenderEvent) { + if (!isEnabled()) return + + tracker.renderDisplay(config.trackerPos) + } + + @HandleEvent + fun onCommandRegistration(event: CommandRegistrationEvent) { + event.register("shresettimitetracker") { + description = "Resets the Timite Tracker." + category = CommandCategory.USERS_RESET + callback { tracker.resetCommand() } + } + } + + private fun isEnabled() = RiftAPI.inMountainTop() && config.timiteTracker + +}