aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/at/hannibal2')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/Features.java4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/Storage.java29
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt15
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/Bazaar.java5
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/GhostCounter.java324
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/Misc.java89
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/bazaar/BazaarApi.kt53
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt11
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/pages/OverviewPage.kt23
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/pages/UpgradePage.kt7
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt6
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/inventory/SackDisplay.kt8
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/inventory/SkyBlockLevelGuideHelper.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/misc/CityProjectFeatures.kt7
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/misc/GhostCounter.kt647
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt155
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/CombatUtils.kt120
18 files changed, 1415 insertions, 94 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
index 082ff7f7c..aaa3231f6 100644
--- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
+++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
@@ -42,6 +42,7 @@ import at.hannibal2.skyhanni.features.minion.MinionCollectLogic
import at.hannibal2.skyhanni.features.minion.MinionFeatures
import at.hannibal2.skyhanni.features.misc.*
import at.hannibal2.skyhanni.features.misc.discordrpc.DiscordRPCManager
+import at.hannibal2.skyhanni.features.misc.GhostCounter
import at.hannibal2.skyhanni.features.misc.items.EstimatedItemValue
import at.hannibal2.skyhanni.features.misc.items.EstimatedWardrobePrice
import at.hannibal2.skyhanni.features.misc.tabcomplete.PlayerTabComplete
@@ -219,7 +220,7 @@ class SkyHanniMod {
loadModule(BarnFishingTimer())
loadModule(CrimsonIsleReputationHelper(this))
loadModule(SharkFishCounter())
- loadModule(SkyBlockLevelGuideHelper())
+ loadModule(SkyblockLevelGuideHelper())
loadModule(OdgerWaypoint())
loadModule(TiaRelayHelper())
loadModule(TiaRelayWaypoints())
@@ -297,6 +298,7 @@ class SkyHanniMod {
loadModule(QuickModMenuSwitch)
loadModule(ShowItemUuid())
loadModule(FrozenTreasureTracker())
+ loadModule(GhostCounter)
init()
diff --git a/src/main/java/at/hannibal2/skyhanni/config/Features.java b/src/main/java/at/hannibal2/skyhanni/config/Features.java
index 9a65ead70..d80195e71 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/Features.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/Features.java
@@ -116,6 +116,10 @@ public class Features extends Config {
public Garden garden = new Garden();
@Expose
+ @Category(name = "Ghost Counter", desc = "Ghost Counter settings.")
+ public GhostCounter ghostCounter = new GhostCounter();
+
+ @Expose
@Category(name = "Misc", desc = "Settings without a category.")
public Misc misc = new Misc();
diff --git a/src/main/java/at/hannibal2/skyhanni/config/Storage.java b/src/main/java/at/hannibal2/skyhanni/config/Storage.java
index f853d4a8d..0a63e5928 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/Storage.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/Storage.java
@@ -5,6 +5,7 @@ import at.hannibal2.skyhanni.features.garden.CropAccessory;
import at.hannibal2.skyhanni.features.garden.CropType;
import at.hannibal2.skyhanni.features.garden.fortuneguide.FarmingItems;
import at.hannibal2.skyhanni.features.garden.visitor.VisitorReward;
+import at.hannibal2.skyhanni.features.misc.GhostCounter.Option;
import at.hannibal2.skyhanni.utils.LorenzVec;
import com.google.gson.annotations.Expose;
import net.minecraft.item.ItemStack;
@@ -204,6 +205,33 @@ public class Storage {
}
@Expose
+ public GhostCounter ghostCounter = new GhostCounter();
+
+ public static class GhostCounter {
+
+ @Expose
+ public Map<Option, Double> data = new HashMap<>();
+
+ @Expose
+ public boolean ctDataImported = false;
+
+ @Expose
+ public double bestiaryNextLevel = 0;
+
+ @Expose
+ public double bestiaryCurrentKill = 0;
+
+ @Expose
+ public double bestiaryKillNeeded = 0;
+
+ @Expose
+ public double totalMF = 0;
+
+ }
+
+ public long nextCityProjectParticipationTime = 0L;
+
+ @Expose
public Map<String, SlayerProfitList> slayerProfitData = new HashMap<>();
public static class SlayerProfitList {
@@ -231,6 +259,5 @@ public class Storage {
public boolean hidden;
}
}
-
}
} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt
index d49ddf345..ebcb72d28 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt
+++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt
@@ -20,6 +20,7 @@ import at.hannibal2.skyhanni.features.garden.fortuneguide.FFGuideGUI
import at.hannibal2.skyhanni.features.minion.MinionFeatures
import at.hannibal2.skyhanni.features.misc.CityProjectFeatures
import at.hannibal2.skyhanni.features.misc.CollectionCounter
+import at.hannibal2.skyhanni.features.misc.GhostCounter
import at.hannibal2.skyhanni.features.misc.MarkedPlayerManager
import at.hannibal2.skyhanni.features.misc.discordrpc.DiscordRPCManager
import at.hannibal2.skyhanni.features.slayer.SlayerItemProfitTracker
@@ -51,7 +52,7 @@ object Commands {
// main commands
registerCommand("sh", openMainMenu)
registerCommand("skyhanni", openMainMenu)
-
+
registerCommand("ff") { openFortuneGuide() }
// for users - regular commands
@@ -65,6 +66,7 @@ object Commands {
registerCommand("shcropstartlocation") { GardenStartLocation.setLocationCommand() }
registerCommand("shstopcityprojectreminder") { CityProjectFeatures.disable() }
registerCommand("shclearslayerprofits") { SlayerItemProfitTracker.clearProfitCommand(it) }
+ registerCommand("shimportghostcounterdata") { GhostCounter.importCTGhostCounterData() }
registerCommand("shclearfarmingitems") { clearFarmingItems() }
// for users - fix bugs
@@ -100,8 +102,9 @@ object Commands {
registerCommand("shcopyerror") { CopyErrorCommand.command(it) }
}
+
@JvmStatic
- fun openFortuneGuide() {
+ fun openFortuneGuide() {
if (!LorenzUtils.inSkyBlock) {
LorenzUtils.chat("§cJoin Skyblock to open the fortune guide!")
} else {
@@ -122,9 +125,9 @@ object Commands {
}
private fun createCommand(function: (Array<String>) -> Unit) =
- object : ProcessCommandRunnable() {
- override fun processCommand(sender: ICommandSender?, args: Array<out String>) {
- function(args.asList().toTypedArray())
+ object : ProcessCommandRunnable() {
+ override fun processCommand(sender: ICommandSender?, args: Array<out String>) {
+ function(args.asList().toTypedArray())
+ }
}
- }
} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/Bazaar.java b/src/main/java/at/hannibal2/skyhanni/config/features/Bazaar.java
index bfc1fdd90..f357e76fd 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/features/Bazaar.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/Bazaar.java
@@ -8,6 +8,11 @@ import io.github.moulberry.moulconfig.annotations.ConfigOption;
public class Bazaar {
@Expose
+ @ConfigOption(name = "Purchase Helper", desc = "Highlights the item you are trying to buy in the Bazaar.")
+ @ConfigEditorBoolean
+ public boolean purchaseHelper = true;
+
+ @Expose
@ConfigOption(name = "Order Helper", desc = "Show visual hints inside the Bazaar Manage Order view when items are ready to pickup or outbid.")
@ConfigEditorBoolean
public boolean orderHelper = false;
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/GhostCounter.java b/src/main/java/at/hannibal2/skyhanni/config/features/GhostCounter.java
new file mode 100644
index 000000000..955253f96
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/GhostCounter.java
@@ -0,0 +1,324 @@
+package at.hannibal2.skyhanni.config.features;
+
+import at.hannibal2.skyhanni.config.core.config.Position;
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.moulconfig.annotations.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class GhostCounter {
+
+ @Expose
+ @ConfigOption(name = "Enabled", desc = "Enable ghost counter.")
+ @ConfigEditorBoolean
+ public boolean enabled = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Display Text",
+ desc = "Drag text to change the appearance of the overlay."
+ )
+ @ConfigEditorDraggableList(
+ exampleText = {
+ "§6Ghosts Counter",
+ " §bGhost Killed: 42",
+ " §bSorrow: 6",
+ " §bGhost since Sorrow: 1",
+ " §bGhosts/Sorrow: 5",
+ " §bVolta: 6",
+ " §bPlasma: 8",
+ " §bGhostly Boots: 1",
+ " §bBag Of Cash: 4",
+ " §bAvg Magic Find: 271",
+ " §bScavenger Coins: 15,000",
+ " §bKill Combo: 14",
+ " §bHighest Kill Combo: 96",
+ " §bSkill XP Gained: 145,648",
+ " §bBestiary 1: 0/10",
+ " §bXP/h: 810,410",
+ " §bKills/h: 420",
+ " §bETA: 14d",
+ " §bMoney/h: 13,420,069"
+ }
+ )
+ public List<Integer> ghostDisplayText = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4, 9, 10, 11, 12));
+
+ @ConfigOption(name = "Text Formatting", desc = "")
+ @Accordion
+ @Expose
+ public TextFormatting textFormatting = new TextFormatting();
+
+ public static class TextFormatting {
+
+ @ConfigOption(name = "§eText Formatting Info", desc = "§e%session% §ris §e§lalways §rreplaced with\n" +
+ "§7the count for your current session.\n" +
+ "§7Reset when restarting the game.\n" +
+ "§7You can use §e&Z §7color code to use SBA chroma")
+ @ConfigEditorInfoText
+ public boolean formatInfo = false;
+
+ @ConfigOption(name = "Reset Formatting", desc = "Reset formatting to default text.")
+ @ConfigEditorButton(buttonText = "Reset")
+ public Runnable resetFormatting = at.hannibal2.skyhanni.features.misc.GhostCounter.INSTANCE::resetFormatting;
+
+ @ConfigOption(name = "Export Formatting", desc = "Export current formatting to clipboard.")
+ @ConfigEditorButton(buttonText = "Export")
+ public Runnable exportFormatting = at.hannibal2.skyhanni.features.misc.GhostCounter.INSTANCE::exportFormatting;
+
+ @ConfigOption(name = "Import Formatting", desc = "Import formatting from clipboard.")
+ @ConfigEditorButton(buttonText = "Import")
+ public Runnable importFormatting = at.hannibal2.skyhanni.features.misc.GhostCounter.INSTANCE::importFormatting;
+
+ @Expose
+ @ConfigOption(name = "Title", desc = "Title Line.")
+ @ConfigEditorText
+ public String titleFormat = "&6Ghost Counter";
+
+ @Expose
+ @ConfigOption(name = "Ghost Killed", desc = "Ghost Killed line.\n§e%value% §ris replaced with\n" +
+ "Ghost Killed.\n" +
+ "§e%session% §7is replaced with Ghost killed")
+ @ConfigEditorText
+ public String ghostKilledFormat = " &6Ghost Killed: &b%value% &7(%session%)";
+
+ @Expose
+ @ConfigOption(name = "Sorrows", desc = "Sorrows drop line.\n" +
+ "§e%value% §7is replaced with\nsorrows dropped.")
+ @ConfigEditorText
+ public String sorrowsFormat = " &6Sorrow: &b%value% &7(%session%)";
+
+ @Expose
+ @ConfigOption(name = "Ghost Since Sorrow", desc = "Ghost Since Sorrow line.\n" +
+ "§e%value% §7is replaced with\nGhost since last sorrow drop.")
+ @ConfigEditorText
+ public String ghostSinceSorrowFormat = " &6Ghost since Sorrow: &b%value%";
+
+ @Expose
+ @ConfigOption(name = "Ghost Kill Per Sorrow", desc = "Ghost Kill Per Sorrow line.\n" +
+ "§e%value% §7is replaced with\naverage ghost kill per sorrow drop.")
+ @ConfigEditorText
+ public String ghostKillPerSorrowFormat = " &6Ghosts/Sorrow: &b%value%";
+
+ @Expose
+ @ConfigOption(name = "Voltas", desc = "Voltas drop line.\n" +
+ "§e%value% §7is replaced with\nvoltas dropped.")
+ @ConfigEditorText
+ public String voltasFormat = " &6Voltas: &b%value% &7(%session%)";
+
+ @Expose
+ @ConfigOption(name = "Plasmas", desc = "Plasmas drop line.\n" +
+ "§e%value% §7is replaced with\nplasmas dropped.")
+ @ConfigEditorText
+ public String plasmasFormat = " &6Plasmas: &b%value% &7(%session%)";
+
+ @Expose
+ @ConfigOption(name = "Ghostly Boots", desc = "Ghostly Boots drop line.\n" +
+ "§e%value% §7is replaced with\nGhostly Boots dropped.")
+ @ConfigEditorText
+ public String ghostlyBootsFormat = " &6Ghostly Boots: &b%value% &7(%session%)";
+
+ @Expose
+ @ConfigOption(name = "Bag Of Cash", desc = "Bag Of Cash drop line.\n" +
+ "§e%value% §7is replaced with\nBag Of Cash dropped.")
+ @ConfigEditorText
+ public String bagOfCashFormat = " &6Bag Of Cash: &b%value% &7(%session%)";
+
+ @Expose
+ @ConfigOption(name = "Average Magic Find", desc = "Average Magic Find line.\n" +
+ "§e%value% §7is replaced with\nAverage Magic Find.")
+ @ConfigEditorText
+ public String avgMagicFindFormat = " &6Avg Magic Find: &b%value%";
+
+ @Expose
+ @ConfigOption(name = "Scavenger Coins", desc = "Scavenger Coins line.\n" +
+ "§e%value% §7is replaced with\nCoins earned from kill ghosts.\nInclude: Scavenger Enchant, Scavenger Talismans, Kill Combo.")
+ @ConfigEditorText
+ public String scavengerCoinsFormat = " &6Scavenger Coins: &b%value% &7(%session%)";
+
+ @Expose
+ @ConfigOption(name = "Kill Combo", desc = "Kill Combo line.\n" +
+ "§e%value% §7is replaced with\nYour current kill combo.")
+ @ConfigEditorText
+ public String killComboFormat = " &6Kill Combo: &b%value%";
+
+ @Expose
+ @ConfigOption(name = "Highest Kill Combo", desc = "Highest Kill Combo line.\n" +
+ "§e%value% §7is replaced with\nYour current highest kill combo.")
+ @ConfigEditorText
+ public String highestKillComboFormat = " &6Highest Kill Combo: &b%value% &7(%session%)";
+
+ @Expose
+ @ConfigOption(name = "Skill XP Gained", desc = "Skill XP Gained line.\n" +
+ "§e%value% §7is replaced with\nSkill XP Gained from killing Ghosts.")
+ @ConfigEditorText
+ public String skillXPGainFormat = " &6Skill XP Gained: &b%value% &7(%session%)";
+
+ @ConfigOption(name = "Bestiary Formatting", desc = "")
+ @Accordion
+ @Expose
+ public BestiaryFormatting bestiaryFormatting = new BestiaryFormatting();
+
+ public static class BestiaryFormatting {
+
+ @Expose
+ @ConfigOption(name = "Bestiary", desc = "Bestiary Progress line.\n§e%value% §7is replaced with\n" +
+ "Your current progress to next level.\n" +
+ "§e%currentLevel% &7is replaced with your current bestiary level\n" +
+ "§e%nextLevel% §7is replaced with your current bestiary level +1.\n" +
+ "§e%value% §7is replaced with one of the text below.")
+ @ConfigEditorText
+ public String base = " &6Bestiary %currentLevel%->%nextLevel%: &b%value%";
+
+ @Expose
+ @ConfigOption(name = "No Data", desc = "Text to show when you need to open the\nBestiary Menu to gather data.")
+ @ConfigEditorText
+ public String openMenu = "§cOpen Bestiary Menu !";
+
+ @Expose
+ @ConfigOption(name = "Maxed", desc = "Text to show when your bestiary for ghost is at max level.\n" +
+ "§e%currentKill% §7is replaced with your current total kill.")
+ @ConfigEditorText
+ public String maxed = "%currentKill% (&c&lMaxed!)";
+
+ @Expose
+ @ConfigOption(name = "Progress to Max", desc = "Text to show progress when the §eMaxed Bestiary §7option is §aON\n" +
+ "§e%currentKill% §7is replaced with your current total kill.")
+ @ConfigEditorText
+ public String showMax_progress = "%currentKill%/3M (%percentNumber%%)";
+
+ @Expose
+ @ConfigOption(name = "Progress", desc = "Text to show progress when the §eMaxed Bestiary§7 option is §cOFF\n" +
+ "§e%currentKill% §7is replaced with how many kill you have to the next level.\n" +
+ "§e%killNeeded% §7is replaced with how many kill you need to reach the next level.")
+ @ConfigEditorText
+ public String progress = "%currentKill%/%killNeeded%";
+ }
+
+
+ @ConfigOption(name = "XP Per Hour Formatting", desc = "")
+ @Accordion
+ @Expose
+ public XPHourFormatting xpHourFormatting = new XPHourFormatting();
+
+ public static class XPHourFormatting {
+
+ @Expose
+ @ConfigOption(name = "XP/h", desc = "XP Per Hour line.\n" +
+ "§e%value% §7is replaced with one of the text below.")
+ @ConfigEditorText
+ public String base = " &6XP/h: &b%value%";
+
+ @Expose
+ @ConfigOption(name = "No Data", desc = "XP Per Hour line.\n§e%value% §7is replaced with\nEstimated amount of combat xp you gain per hour.")
+ @ConfigEditorText
+ public String noData = "&bN/A";
+
+ @Expose
+ @ConfigOption(name = "Paused", desc = "Text displayed next to the time \n" +
+ "when you are doing nothing for a given amount of seconds")
+ @ConfigEditorText
+ public String paused = "&c(PAUSED)";
+ }
+
+
+ @ConfigOption(name = "ETA Formatting", desc = "")
+ @Accordion
+ @Expose
+ public ETAFormatting etaFormatting = new ETAFormatting();
+
+ public static class ETAFormatting {
+ @Expose
+ @ConfigOption(name = "ETA to next level", desc = "ETA To Next Level Line.\n" +
+ "§e%value% §7is replaced with one of the text below.")
+ @ConfigEditorText
+ public String base = " &6ETA: &b%value%";
+
+ @Expose
+ @ConfigOption(name = "Maxed!", desc = "So you really maxed ghost bestiary ?")
+ @ConfigEditorText
+ public String maxed = "&c&lMAXED!";
+
+ @Expose
+ @ConfigOption(name = "No Data", desc = "Start killing some ghosts !")
+ @ConfigEditorText
+ public String noData = "&bN/A";
+
+ @Expose
+ @ConfigOption(name = "Progress", desc = "Text to show progress to next level.")
+ @ConfigEditorText
+ public String progress = "&b%value%";
+
+ @Expose
+ @ConfigOption(name = "Paused", desc = "Text displayed next to the time \n" +
+ "when you are doing nothing for a given amount of seconds")
+ @ConfigEditorText
+ public String paused = "&c(PAUSED)";
+ }
+
+ @ConfigOption(name = "Kill Per Hour Formatting", desc = "")
+ @Expose
+ @Accordion
+ public KillHourFormatting killHourFormatting = new KillHourFormatting();
+
+ public static class KillHourFormatting {
+ @Expose
+ @ConfigOption(name = "Kill/h", desc = "Kill Per Hour line.\n§e%value% §7is replaced with\nEstimated kills per hour you get.")
+ @ConfigEditorText
+ public String base = " &6Kill/h: &b%value%";
+
+ @Expose
+ @ConfigOption(name = "No Data", desc = "Start killing some ghosts !")
+ @ConfigEditorText
+ public String noData = "&bN/A";
+
+ @Expose
+ @ConfigOption(name = "Paused", desc = "Text displayed next to the time \n" +
+ "when you are doing nothing for a given amount of seconds")
+ @ConfigEditorText
+ public String paused = "&c(PAUSED)";
+ }
+
+ @Expose
+ @ConfigOption(name = "Money Per Hour", desc = "Money Per Hour.\n§e%value% §7is replaced with\nEstimated money you get per hour\n" +
+ "Calculated with your kill per hour and your average magic find.")
+ @ConfigEditorText
+ public String moneyHourFormat = " &6$/h: &b%value%";
+ }
+
+ @Expose
+ @ConfigOption(name = "Extra space", desc = "Space between each line of text.")
+ @ConfigEditorSlider(
+ minValue = -5,
+ maxValue = 10,
+ minStep = 1)
+ public int extraSpace = 1;
+
+ @Expose
+ @ConfigOption(name = "Pause Timer", desc = "How many seconds does it wait before pausing.")
+ @ConfigEditorSlider(
+ minValue = 1,
+ maxValue = 20,
+ minStep = 1
+ )
+ public int pauseTimer = 3;
+
+ @Expose
+ @ConfigOption(name = "Show only in The Mist", desc = "Show the overlay only when you are in The Mist.")
+ @ConfigEditorBoolean
+ public boolean onlyOnMist = true;
+
+ @Expose
+ @ConfigOption(name = "Maxed Bestiary", desc = "Show progress to max bestiary instead of next level.")
+ @ConfigEditorBoolean
+ public boolean showMax = false;
+
+ @ConfigOption(name = "Reset", desc = "Reset the counter.")
+ @ConfigEditorButton(buttonText = "Reset")
+ public Runnable resetCounter = at.hannibal2.skyhanni.features.misc.GhostCounter.INSTANCE::reset;
+
+ @Expose
+ public Position position = new Position(50, 50, false, true);
+
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/Misc.java b/src/main/java/at/hannibal2/skyhanni/config/features/Misc.java
index f5a08521d..f0d5b7d7b 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/features/Misc.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/Misc.java
@@ -1,10 +1,13 @@
package at.hannibal2.skyhanni.config.features;
-import at.hannibal2.skyhanni.config.core.config.Position;
-import com.google.gson.annotations.Expose;
+import at.hannibal2.skyhanni.config.core.config.*;
+import com.google.gson.annotations.*;
import io.github.moulberry.moulconfig.annotations.*;
-import io.github.moulberry.moulconfig.observer.Property;
-import org.lwjgl.input.Keyboard;
+import io.github.moulberry.moulconfig.observer.*;
+import org.lwjgl.input.*;
+
+import java.util.ArrayList;
+import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
@@ -263,38 +266,38 @@ public class Misc {
@Expose
@ConfigOption(name = "First Line", desc = "Decide what to show in the first line.")
@ConfigEditorDropdown(values = {
- "Nothing",
- "Location",
- "Purse",
- "Bits",
- "Stats",
- "Held Item",
- "Skyblock Date",
- "Profile (Fruit)",
- "Slayer",
- "Custom",
- "Dynamic",
- "Crop Milestone",
- "Current Pet"
+ "Nothing",
+ "Location",
+ "Purse",
+ "Bits",
+ "Stats",
+ "Held Item",
+ "Skyblock Date",
+ "Profile",
+ "Slayer",
+ "Custom",
+ "Dynamic",
+ "Crop Milestone",
+ "Current Pet"
})
public Property<Integer> firstLine = Property.of(0);
@Expose
@ConfigOption(name = "Second Line", desc = "Decide what to show in the second line.")
@ConfigEditorDropdown(values = {
- "Nothing",
- "Location",
- "Purse",
- "Bits",
- "Stats",
- "Held Item",
- "Skyblock Date",
- "Profile (Fruit)",
- "Slayer",
- "Custom",
- "Dynamic",
- "Crop Milestone",
- "Current Pet"
+ "Nothing",
+ "Location",
+ "Purse",
+ "Bits",
+ "Stats",
+ "Held Item",
+ "Skyblock Date",
+ "Profile",
+ "Slayer",
+ "Custom",
+ "Dynamic",
+ "Crop Milestone",
+ "Current Pet"
})
public Property<Integer> secondLine = Property.of(0);
@@ -304,20 +307,20 @@ public class Misc {
public Property<String> customText = Property.of("");
@Expose
- @ConfigOption(name = "Dynamic", desc = "\"Dynamic\" above shows your Crop Milestone or Slayer progress while doing those, but this if you're doing neither.")
+ @ConfigOption(name = "Dynamic", desc = "\"Dynamic\" above shows your Crop Milestone, Slayer progress, or Stacking enchantment when possible, but this if you're doing none of them.")
@ConfigEditorDropdown(values = {
- "Nothing",
- "Location",
- "Purse",
- "Bits",
- "Stats",
- "Held Item",
- "Skyblock Date",
- "Profile (Fruit)",
- "Slayer",
- "Custom",
- "Crop Milestone",
- "Current Pet"
+ "Nothing",
+ "Location",
+ "Purse",
+ "Bits",
+ "Stats",
+ "Held Item",
+ "Skyblock Date",
+ "Profile",
+ "Slayer",
+ "Custom",
+ "Crop Milestone",
+ "Current Pet"
})
public Property<Integer> auto = Property.of(0);
}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/bazaar/BazaarApi.kt b/src/main/java/at/hannibal2/skyhanni/features/bazaar/BazaarApi.kt
index 85267240e..899001e75 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/bazaar/BazaarApi.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/bazaar/BazaarApi.kt
@@ -1,12 +1,21 @@
package at.hannibal2.skyhanni.features.bazaar
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.events.GuiContainerEvent
import at.hannibal2.skyhanni.events.InventoryCloseEvent
import at.hannibal2.skyhanni.events.InventoryOpenEvent
+import at.hannibal2.skyhanni.events.LorenzChatEvent
import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName
import at.hannibal2.skyhanni.utils.ItemUtils.getLore
import at.hannibal2.skyhanni.utils.ItemUtils.name
+import at.hannibal2.skyhanni.utils.LorenzColor
+import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.NEUItems
+import at.hannibal2.skyhanni.utils.OSUtils
+import at.hannibal2.skyhanni.utils.RenderUtils.highlight
import at.hannibal2.skyhanni.utils.StringUtils.removeColor
+import net.minecraft.client.gui.inventory.GuiChest
+import net.minecraft.inventory.ContainerChest
import net.minecraft.item.ItemStack
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.TickEvent
@@ -17,6 +26,7 @@ class BazaarApi {
companion object {
val holder = BazaarDataHolder()
var inBazaarInventory = false
+ private var currentSearchedItem = ""
fun getBazaarDataByName(name: String): BazaarData? =
NEUItems.getInternalNameOrNull(name)?.let { getBazaarDataByInternalName(it) }
@@ -32,6 +42,16 @@ class BazaarApi {
fun isBazaarItem(internalName: String): Boolean {
return NEUItems.manager.auctionManager.getBazaarInfo(internalName) != null
}
+
+ fun searchForBazaarItem(displayName: String, amount: Int = -1) {
+ if (!LorenzUtils.inSkyBlock) return
+ if (NEUItems.neuHasFocus()) return
+ if (LorenzUtils.noTradeMode) return
+ if (LorenzUtils.inDungeons || LorenzUtils.inKuudraFight) return
+ LorenzUtils.sendCommandToServer("bz ${displayName.removeColor()}")
+ if (amount != -1) OSUtils.copyToClipboard(amount.toString())
+ currentSearchedItem = displayName.removeColor()
+ }
}
@SubscribeEvent
@@ -39,7 +59,6 @@ class BazaarApi {
inBazaarInventory = checkIfInBazaar(event)
}
-
@SubscribeEvent
fun onTick(event: TickEvent.ClientTickEvent) {
if (event.phase != TickEvent.Phase.START) return
@@ -50,6 +69,38 @@ class BazaarApi {
}
}
+ @SubscribeEvent
+ fun onBackgroundDrawn(event: GuiContainerEvent.BackgroundDrawnEvent) {
+ if (!LorenzUtils.inSkyBlock) return
+ if (!inBazaarInventory) return
+ if (!SkyHanniMod.feature.bazaar.purchaseHelper) return
+ if (currentSearchedItem == "") return
+
+ if (event.gui !is GuiChest) return
+ val guiChest = event.gui
+ val chest = guiChest.inventorySlots as ContainerChest
+
+ for (slot in chest.inventorySlots) {
+ if (slot == null) continue
+ val stack = slot.stack ?: continue
+
+ if (chest.inventorySlots.indexOf(slot) !in 9..44) {
+ continue
+ }
+
+ if (stack.displayName.removeColor() == currentSearchedItem) {
+ slot highlight LorenzColor.GREEN
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onChat(event: LorenzChatEvent) {
+ if ("\\[Bazaar] (Buy Order Setup!|Bought).*$currentSearchedItem.*".toRegex().matches(event.message.removeColor())) {
+ currentSearchedItem = ""
+ }
+ }
+
private fun checkIfInBazaar(event: InventoryOpenEvent): Boolean {
val returnItem = event.inventorySize - 5
for ((slot, item) in event.inventoryItems) {
diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt
index 241f6cbcd..5c67ea67e 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt
@@ -3,19 +3,23 @@ package at.hannibal2.skyhanni.features.garden.composter
import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.data.model.ComposterUpgrade
import at.hannibal2.skyhanni.events.*
+import at.hannibal2.skyhanni.features.bazaar.BazaarApi
import at.hannibal2.skyhanni.features.garden.GardenAPI
import at.hannibal2.skyhanni.features.garden.composter.ComposterAPI.getLevel
-import at.hannibal2.skyhanni.utils.*
import at.hannibal2.skyhanni.utils.ItemUtils.name
+import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.LorenzUtils.addAsSingletonList
import at.hannibal2.skyhanni.utils.LorenzUtils.addSelector
import at.hannibal2.skyhanni.utils.LorenzUtils.round
import at.hannibal2.skyhanni.utils.LorenzUtils.sortedDesc
+import at.hannibal2.skyhanni.utils.NEUItems
+import at.hannibal2.skyhanni.utils.NumberUtil
import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators
import at.hannibal2.skyhanni.utils.NumberUtil.romanToDecimalIfNeeded
import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems
import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher
import at.hannibal2.skyhanni.utils.StringUtils.removeColor
+import at.hannibal2.skyhanni.utils.TimeUtils
import at.hannibal2.skyhanni.utils.jsonobjects.GardenJson
import at.hannibal2.skyhanni.utils.renderables.Renderable
import io.github.moulberry.notenoughupdates.NotEnoughUpdates
@@ -389,10 +393,9 @@ class ComposterOverlay {
val name = itemName.substring(0, 2) + selected + rawItemName
list.add(Renderable.link("$name§r §8x${itemsNeeded.addSeparators()} §7(§6$format§7)") {
onClick(internalName)
- if (LorenzUtils.isControlKeyDown() && !LorenzUtils.noTradeMode) {
+ if (LorenzUtils.isControlKeyDown()) {
inInventory = false
- LorenzUtils.sendCommandToServer("bz $rawItemName")
- OSUtils.copyToClipboard("${itemsNeeded.toInt()}")
+ BazaarApi.searchForBazaarItem(itemName, itemsNeeded.toInt())
}
})
bigList.add(list)
diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/pages/OverviewPage.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/pages/OverviewPage.kt
index fcf0096a1..32578e647 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/pages/OverviewPage.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/pages/OverviewPage.kt
@@ -67,6 +67,8 @@ class OverviewPage: FFGuideGUI.FFGuidePage() {
else -> FFStats.armorTotalFF
}
+ var word = if (currentArmor == 0) "Armor" else "Piece"
+
line = if (currentArmor == 0) "§7§2Total fortune from your armor\n§2Select a piece for more info"
else "§7§2Total fortune from your\n${armorItem.getItem().displayName}"
var value = if (currentArmor == 0) {
@@ -84,7 +86,7 @@ class OverviewPage: FFGuideGUI.FFGuidePage() {
else -> 78.75
}
}
- GuiRenderUtils.drawFarmingBar("§2Total Armor Fortune", line, armorFF[FFTypes.TOTAL] ?: 0, value,
+ GuiRenderUtils.drawFarmingBar("§2Total $word Fortune", line, armorFF[FFTypes.TOTAL] ?: 0, value,
FFGuideGUI.guiLeft + 135, FFGuideGUI.guiTop + 30, 90, mouseX, mouseY, FFGuideGUI.tooltipToDisplay)
line = if (currentArmor == 0) "§7§2The base fortune from your armor\n§2Select a piece for more info"
@@ -97,7 +99,7 @@ class OverviewPage: FFGuideGUI.FFGuidePage() {
else {
if (FFStats.usingSpeedBoots) 60 else 30
}
- GuiRenderUtils.drawFarmingBar("§2Base Armor Fortune", line, armorFF[FFTypes.BASE] ?: 0,
+ GuiRenderUtils.drawFarmingBar("§2Base $word Fortune", line, armorFF[FFTypes.BASE] ?: 0,
value, FFGuideGUI.guiLeft + 135,
FFGuideGUI.guiTop + 55, 90, mouseX, mouseY, FFGuideGUI.tooltipToDisplay)
@@ -106,6 +108,7 @@ class OverviewPage: FFGuideGUI.FFGuidePage() {
value = if (FFStats.usingSpeedBoots) {
when (currentArmor) {
0 -> 50
+ 4 -> 0
else -> 16.67
}
} else {
@@ -115,7 +118,7 @@ class OverviewPage: FFGuideGUI.FFGuidePage() {
}
}
- GuiRenderUtils.drawFarmingBar("§2Armor Ability", line, armorFF[FFTypes.ABILITY] ?: 0,
+ GuiRenderUtils.drawFarmingBar("§2$word Ability", line, armorFF[FFTypes.ABILITY] ?: 0,
value, FFGuideGUI.guiLeft + 135,
FFGuideGUI.guiTop + 80, 90, mouseX, mouseY, FFGuideGUI.tooltipToDisplay)
@@ -126,7 +129,7 @@ class OverviewPage: FFGuideGUI.FFGuidePage() {
} else if (currentArmor == 4) {
if (FFStats.usingSpeedBoots) 25 else 30
} else 30
- GuiRenderUtils.drawFarmingBar("§2Armor Reforge", line, armorFF[FFTypes.REFORGE] ?: 0,
+ GuiRenderUtils.drawFarmingBar("§2$word Reforge", line, armorFF[FFTypes.REFORGE] ?: 0,
value, FFGuideGUI.guiLeft + 135,
FFGuideGUI.guiTop + 105, 90, mouseX, mouseY, FFGuideGUI.tooltipToDisplay)
@@ -149,6 +152,8 @@ class OverviewPage: FFGuideGUI.FFGuidePage() {
GuiRenderUtils.drawFarmingBar("§2Pet Item", line, currentPet[FFTypes.PET_ITEM] ?: 0, 60, FFGuideGUI.guiLeft + 185,
FFGuideGUI.guiTop + 155, 70, mouseX, mouseY, FFGuideGUI.tooltipToDisplay)
+ word = if (currentEquipment == 0) "Equipment" else "Piece"
+
val equipmentItem = when (currentEquipment) {
1 -> FarmingItems.NECKLACE
2 -> FarmingItems.CLOAK
@@ -166,31 +171,31 @@ class OverviewPage: FFGuideGUI.FFGuidePage() {
line = if (currentEquipment == 0) "§7§2Total fortune from all your equipment\n§2Select a piece for more info"
else "§7§2Total fortune from your\n${equipmentItem.getItem().displayName}"
- GuiRenderUtils.drawFarmingBar("§2Total Equipment Fortune", line, equipmentFF[FFTypes.TOTAL] ?: 0,
+ GuiRenderUtils.drawFarmingBar("§2Total $word Fortune", line, equipmentFF[FFTypes.TOTAL] ?: 0,
if (currentEquipment == 0) 198 else 49.5,
FFGuideGUI.guiLeft + 255, FFGuideGUI.guiTop + 30, 90, mouseX, mouseY, FFGuideGUI.tooltipToDisplay)
line = if (currentEquipment == 0) "§7§2The base fortune from all your equipment\n§2Select a piece for more info"
else "§7§2Total base fortune from your\n${equipmentItem.getItem().displayName}"
- GuiRenderUtils.drawFarmingBar("§2Equipment Base Fortune", line, equipmentFF[FFTypes.BASE] ?: 0,
+ GuiRenderUtils.drawFarmingBar("§2$word Base Fortune", line, equipmentFF[FFTypes.BASE] ?: 0,
if (currentEquipment == 0) 20 else 5,
FFGuideGUI.guiLeft + 255, FFGuideGUI.guiTop + 55, 90, mouseX, mouseY, FFGuideGUI.tooltipToDisplay)
line = if (currentEquipment == 0) "§7§2The fortune from all of your equipment's abilities\n§2Select a piece for more info"
else "§7§2Total ability fortune from your\n${equipmentItem.getItem().displayName}"
- GuiRenderUtils.drawFarmingBar("§2Equipment Ability", line, equipmentFF[FFTypes.ABILITY] ?: 0,
+ GuiRenderUtils.drawFarmingBar("§2$word Ability", line, equipmentFF[FFTypes.ABILITY] ?: 0,
if (currentEquipment == 0) 60 else 15,
FFGuideGUI.guiLeft + 255, FFGuideGUI.guiTop + 80, 90, mouseX, mouseY, FFGuideGUI.tooltipToDisplay)
line = if (currentEquipment == 0) "§7§2The fortune from all of your equipment's reforges\n§2Select a piece for more info"
else "§7§2Total reforge fortune from your\n${equipmentItem.getItem().displayName}"
- GuiRenderUtils.drawFarmingBar("§2Equipment Reforge", line, equipmentFF[FFTypes.REFORGE] ?: 0,
+ GuiRenderUtils.drawFarmingBar("§2$word Reforge", line, equipmentFF[FFTypes.REFORGE] ?: 0,
if (currentEquipment == 0) 40 else 10,
FFGuideGUI.guiLeft + 255, FFGuideGUI.guiTop + 105, 90, mouseX, mouseY, FFGuideGUI.tooltipToDisplay)
line = if (currentEquipment == 0) "§7§2The fortune from all of your equipment's enchantments\n§2Select a piece for more info"
else "§7§2Total enchantment fortune from your\n${equipmentItem.getItem().displayName}"
- GuiRenderUtils.drawFarmingBar("§2Equipment Enchantment", line, equipmentFF[FFTypes.GREEN_THUMB] ?: 0,
+ GuiRenderUtils.drawFarmingBar("§2$word Enchantment", line, equipmentFF[FFTypes.GREEN_THUMB] ?: 0,
if (currentEquipment == 0) 78 else 19.5,
FFGuideGUI.guiLeft + 255, FFGuideGUI.guiTop + 130, 90, mouseX, mouseY, FFGuideGUI.tooltipToDisplay)
}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/pages/UpgradePage.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/pages/UpgradePage.kt
index 36f67eab6..e04c0dc54 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/pages/UpgradePage.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/pages/UpgradePage.kt
@@ -1,13 +1,12 @@
package at.hannibal2.skyhanni.features.garden.fortuneguide.pages
+import at.hannibal2.skyhanni.features.bazaar.BazaarApi
import at.hannibal2.skyhanni.features.garden.fortuneguide.FFGuideGUI
import at.hannibal2.skyhanni.features.garden.fortuneguide.FortuneUpgrades
import at.hannibal2.skyhanni.utils.GuiRenderUtils
import at.hannibal2.skyhanni.utils.ItemUtils.nameWithEnchantment
-import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.NEUItems
import at.hannibal2.skyhanni.utils.NumberUtil
-import at.hannibal2.skyhanni.utils.StringUtils.removeColor
import net.minecraft.client.renderer.GlStateManager
import net.minecraft.util.MathHelper
import java.text.DecimalFormat
@@ -38,9 +37,7 @@ class UpgradePage: FFGuideGUI.FFGuidePage() {
var formattedUpgrade = upgradeItem.nameWithEnchantment ?: return
if (adjustedY + 25 * index - 5 < FFGuideGUI.lastClickedHeight && FFGuideGUI.lastClickedHeight < adjustedY + 25 * index + 10) {
FFGuideGUI.lastClickedHeight = 0
- if (!NEUItems.neuHasFocus() && !LorenzUtils.noTradeMode) {
- LorenzUtils.sendCommandToServer("bz ${formattedUpgrade.removeColor()}")
- }
+ BazaarApi.searchForBazaarItem(formattedUpgrade, upgrade.itemQuantity)
}
if (upgrade.itemQuantity != 1) {
formattedUpgrade = "$formattedUpgrade §fx${upgrade.itemQuantity}"
diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt
index 973f122d5..f7fedd18c 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt
@@ -4,6 +4,7 @@ import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.data.IslandType
import at.hannibal2.skyhanni.data.TitleUtils
import at.hannibal2.skyhanni.events.*
+import at.hannibal2.skyhanni.features.bazaar.BazaarApi
import at.hannibal2.skyhanni.features.garden.CropType.Companion.getByNameOrNull
import at.hannibal2.skyhanni.features.garden.GardenAPI
import at.hannibal2.skyhanni.features.garden.farming.GardenCropSpeed.getSpeed
@@ -175,9 +176,8 @@ class GardenVisitorFeatures {
list.add(Renderable.optionalLink("$name §ex${amount.addSeparators()}", {
if (Minecraft.getMinecraft().currentScreen is GuiEditSign) {
LorenzUtils.setTextIntoSign("$amount")
- } else if (!NEUItems.neuHasFocus() && !LorenzUtils.noTradeMode) {
- LorenzUtils.sendCommandToServer("bz ${name.removeColor()}")
- OSUtils.copyToClipboard("$amount")
+ } else {
+ BazaarApi.searchForBazaarItem(name, amount)
}
}) { GardenAPI.inGarden() && !NEUItems.neuHasFocus() })
diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/SackDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/SackDisplay.kt
index 6f5678bc8..acb7d6b67 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/inventory/SackDisplay.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/SackDisplay.kt
@@ -186,9 +186,7 @@ class SackDisplay {
add(itemStack)
if (!isTrophySack)
add(Renderable.optionalLink("${itemName.replace("§k", "")}: ", {
- if (!NEUItems.neuHasFocus() && !LorenzUtils.noTradeMode) {
- LorenzUtils.sendCommandToServer("bz ${itemName.removeColor()}")
- }
+ BazaarApi.searchForBazaarItem(itemName)
}) { !NEUItems.neuHasFocus() })
else
add("${itemName.replace("§k", "")}: ")
@@ -254,9 +252,7 @@ class SackDisplay {
add(" §7- ")
add(NEUItems.getItemStack(internalName))
add(Renderable.optionalLink("$name: ", {
- if (!NEUItems.neuHasFocus() && !LorenzUtils.noTradeMode) {
- LorenzUtils.sendCommandToServer("bz ${name.removeColor().dropLast(1)}")
- }
+ BazaarApi.searchForBazaarItem(name.dropLast(1))
}) { !NEUItems.neuHasFocus() })
add(" ($rough-§a$flawed-§9$fine-§5$flawless)")
val price = (roughprice + flawedprice + fineprice + flawlessprice)
diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/SkyBlockLevelGuideHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/SkyBlockLevelGuideHelper.kt
index 60c1a28de..16df062f8 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/inventory/SkyBlockLevelGuideHelper.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/SkyBlockLevelGuideHelper.kt
@@ -11,7 +11,7 @@ import net.minecraft.client.gui.inventory.GuiChest
import net.minecraft.inventory.ContainerChest
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
-class SkyBlockLevelGuideHelper {
+class SkyblockLevelGuideHelper {
@SubscribeEvent
fun onBackgroundDrawn(event: GuiContainerEvent.BackgroundDrawnEvent) {
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/CityProjectFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/CityProjectFeatures.kt
index dee222aa2..d8d18ec6d 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/misc/CityProjectFeatures.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/CityProjectFeatures.kt
@@ -6,6 +6,7 @@ import at.hannibal2.skyhanni.events.GuiContainerEvent
import at.hannibal2.skyhanni.events.GuiRenderEvent
import at.hannibal2.skyhanni.events.InventoryCloseEvent
import at.hannibal2.skyhanni.events.InventoryOpenEvent
+import at.hannibal2.skyhanni.features.bazaar.BazaarApi
import at.hannibal2.skyhanni.features.garden.contest.FarmingContestAPI
import at.hannibal2.skyhanni.utils.*
import at.hannibal2.skyhanni.utils.ItemUtils.getLore
@@ -15,7 +16,6 @@ import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators
import at.hannibal2.skyhanni.utils.RenderUtils.highlight
import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems
import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher
-import at.hannibal2.skyhanni.utils.StringUtils.removeColor
import at.hannibal2.skyhanni.utils.renderables.Renderable
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.inventory.GuiChest
@@ -136,9 +136,8 @@ class CityProjectFeatures {
list.add(Renderable.optionalLink("$name §ex${amount.addSeparators()}", {
if (Minecraft.getMinecraft().currentScreen is GuiEditSign) {
LorenzUtils.setTextIntoSign("$amount")
- } else if (!NEUItems.neuHasFocus() && !LorenzUtils.noTradeMode) {
- LorenzUtils.sendCommandToServer("bz ${name.removeColor()}")
- OSUtils.copyToClipboard("$amount")
+ } else {
+ BazaarApi.searchForBazaarItem(name, amount)
}
}) { inInventory && !NEUItems.neuHasFocus() })
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/GhostCounter.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/GhostCounter.kt
new file mode 100644
index 000000000..0be9f0655
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/GhostCounter.kt
@@ -0,0 +1,647 @@
+package at.hannibal2.skyhanni.features.misc
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.config.ConfigManager
+import at.hannibal2.skyhanni.data.IslandType
+import at.hannibal2.skyhanni.data.ProfileStorageData
+import at.hannibal2.skyhanni.events.*
+import at.hannibal2.skyhanni.features.bazaar.BazaarApi
+import at.hannibal2.skyhanni.features.misc.GhostCounter.Option.*
+import at.hannibal2.skyhanni.utils.CombatUtils._isKilling
+import at.hannibal2.skyhanni.utils.CombatUtils.calculateETA
+import at.hannibal2.skyhanni.utils.CombatUtils.calculateXP
+import at.hannibal2.skyhanni.utils.CombatUtils.interp
+import at.hannibal2.skyhanni.utils.CombatUtils.isKilling
+import at.hannibal2.skyhanni.utils.CombatUtils.killGainHour
+import at.hannibal2.skyhanni.utils.CombatUtils.killGainHourLast
+import at.hannibal2.skyhanni.utils.CombatUtils.lastKillUpdate
+import at.hannibal2.skyhanni.utils.CombatUtils.lastUpdate
+import at.hannibal2.skyhanni.utils.CombatUtils.xpGainHour
+import at.hannibal2.skyhanni.utils.CombatUtils.xpGainHourLast
+import at.hannibal2.skyhanni.utils.ItemUtils.getLore
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzUtils.addAsSingletonList
+import at.hannibal2.skyhanni.utils.LorenzUtils.chat
+import at.hannibal2.skyhanni.utils.LorenzUtils.clickableChat
+import at.hannibal2.skyhanni.utils.NumberUtil
+import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators
+import at.hannibal2.skyhanni.utils.NumberUtil.formatNumber
+import at.hannibal2.skyhanni.utils.NumberUtil.roundToPrecision
+import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems
+import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher
+import at.hannibal2.skyhanni.utils.StringUtils.removeColor
+import com.google.gson.JsonArray
+import com.google.gson.JsonParser
+import com.google.gson.JsonPrimitive
+import io.github.moulberry.notenoughupdates.util.Utils
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import net.minecraftforge.fml.common.gameevent.TickEvent
+import java.awt.Toolkit
+import java.awt.datatransfer.DataFlavor
+import java.awt.datatransfer.StringSelection
+import java.io.File
+import java.io.FileReader
+import java.nio.charset.StandardCharsets
+import java.text.NumberFormat
+import java.util.*
+import java.util.regex.Pattern
+import kotlin.math.roundToInt
+import kotlin.math.roundToLong
+
+object GhostCounter {
+
+ val config get() = SkyHanniMod.feature.ghostCounter
+ val hidden get() = ProfileStorageData.profileSpecific?.ghostCounter
+ private var display = listOf<List<Any>>()
+ private var ghostCounterV3File = File("." + File.separator + "config" + File.separator + "ChatTriggers" + File.separator + "modules" + File.separator + "GhostCounterV3" + File.separator + ".persistantData.json")
+ private val skillXPPattern = ".*§3\\+(?<gained>.*) .* \\((?<total>.*)\\/(?<current>.*)\\).*".toPattern()
+ private val killComboExpiredPattern = "§cYour Kill Combo has expired! You reached a (?<combo>.*) Kill Combo!".toPattern()
+ private val ghostXPPattern = "(?<current>\\d+(?:\\.\\d+)?(?:,\\d+)?[kK]?)\\/(?<total>\\d+(?:\\.\\d+)?(?:,\\d+)?[kKmM]?)".toPattern()
+ private val bestiaryPattern = "BESTIARY Ghost .*➜(?<newLevel>.*)".toPattern()
+ private val format = NumberFormat.getIntegerInstance()
+ private const val exportPrefix = "gc/"
+ private var tick = 0
+ private var lastXp: String = "0"
+ private var gain: Int = 0
+ private var num: Double = 0.0
+ private var inMist = false
+ private var notifyCTModule = true
+ var bestiaryCurrentKill = 0
+ private var killETA = ""
+ private var session = mutableMapOf(
+ KILLS to 0.0,
+ SORROWCOUNT to 0.0,
+ VOLTACOUNT to 0.0,
+ PLASMACOUNT to 0.0,
+ GHOSTLYBOOTS to 0.0,
+ BAGOFCASH to 0.0,
+ TOTALDROPS to 0.0,
+ SCAVENGERCOINS to 0.0,
+ MAXKILLCOMBO to 0.0,
+ SKILLXPGAINED to 0.0
+ )
+ val bestiaryData = mutableMapOf<Int, Int>().apply {
+ val commonValue = 100_000
+ for (i in 1..46) {
+ this[i] = when (i) {
+ 1 -> 10
+ 2 -> 15
+ 3 -> 75
+ 4 -> 150
+ 5 -> 250
+ 6 -> 500
+ 7 -> 1_500
+ 8 -> 2_500
+ 9 -> 5_000
+ 10 -> 15_000
+ 11 -> 25_000
+ 12 -> 50_000
+ else -> commonValue
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) {
+ if (!isEnabled()) return
+ if (config.onlyOnMist && !inMist) return
+ config.position.renderStringsAndItems(display,
+ extraSpace = config.extraSpace,
+ posLabel = "Ghost Counter")
+ }
+
+ private fun formatDisplay(map: List<List<Any>>): List<List<Any>> {
+ val newList = mutableListOf<List<Any>>()
+ for (index in config.ghostDisplayText) {
+ newList.add(map[index])
+ }
+ return newList
+ }
+
+ fun update() {
+ display = formatDisplay(drawDisplay())
+ }
+
+ private fun drawDisplay() = buildList<List<Any>> {
+ val value: Int = when (SORROWCOUNT.get()) {
+ 0.0 -> 0
+ else -> "${((((KILLS.get() / SORROWCOUNT.get()) + Math.ulp(1.0)) * 100) / 100).roundToInt()}".toInt()
+ }
+ val mgc = when (TOTALDROPS.get()) {
+ 0.0 -> "0"
+ else -> "${((((hidden?.totalMF!! / TOTALDROPS.get()) + Math.ulp(1.0)) * 100) / 100).roundToPrecision(2)}"
+ }
+
+ val xpHourFormatting = config.textFormatting.xpHourFormatting
+ val xp: String
+ val xpInterp: Float
+ if (xpGainHourLast == xpGainHour && xpGainHour <= 0) {
+ xp = xpHourFormatting.noData
+ } else {
+ xpInterp = interp(xpGainHour, xpGainHourLast, lastUpdate)
+ xp = "${format.format(xpInterp)} ${if (isKilling) "" else xpHourFormatting.paused}"
+ }
+
+ val killHourFormatting = config.textFormatting.killHourFormatting
+ val killh: String
+ var killInterp: Long = 0
+ if (killGainHourLast == killGainHour && killGainHour <= 0) {
+ killh = killHourFormatting.noData
+ } else {
+ killInterp = interp(killGainHour.toFloat(), killGainHourLast.toFloat(), lastKillUpdate).toLong()
+ killh = "${format.format(killInterp)} ${if (_isKilling) "" else killHourFormatting.paused}"
+ }
+
+
+ val bestiaryFormatting = config.textFormatting.bestiaryFormatting
+ val currentKill = hidden?.bestiaryCurrentKill?.toInt() ?: 0
+ val killNeeded = hidden?.bestiaryKillNeeded?.toInt() ?: 0
+ val nextLevel = hidden?.bestiaryNextLevel?.toInt() ?: 0
+ val bestiary = if (config.showMax) {
+ when (nextLevel) {
+ -1 -> bestiaryFormatting.maxed
+ in 1..46 -> {
+ val sum = bestiaryData.filterKeys { it <= nextLevel - 1 }.values.sum()
+ val cKill = sum + currentKill
+ bestiaryCurrentKill = cKill
+ bestiaryFormatting.showMax_progress
+ }
+
+ else -> bestiaryFormatting.openMenu
+ }
+ } else {
+ when (nextLevel) {
+ -1 -> bestiaryFormatting.maxed
+ in 1..46 -> bestiaryFormatting.progress
+ else -> bestiaryFormatting.openMenu
+ }
+ }
+
+ val etaFormatting = config.textFormatting.etaFormatting
+ val remaining: Int = when (config.showMax) {
+ true -> 3_000_000 - bestiaryCurrentKill
+ false -> killNeeded - currentKill
+ }
+
+ val eta = if (remaining < 0) {
+ etaFormatting.maxed
+ } else {
+ if (killGainHour < 1) {
+ etaFormatting.noData
+ } else {
+ killETA = Utils.prettyTime(remaining.toLong() * 1000 * 60 * 60 / killInterp)
+ etaFormatting.progress + if (_isKilling) "" else etaFormatting.paused
+ }
+ }
+
+ addAsSingletonList(Utils.chromaStringByColourCode(config.textFormatting.titleFormat.replace("&", "§")))
+ addAsSingletonList(config.textFormatting.ghostKilledFormat.formatText(KILLS.getInt(), KILLS.getInt(true)))
+ addAsSingletonList(config.textFormatting.sorrowsFormat.formatText(SORROWCOUNT.getInt(), SORROWCOUNT.getInt(true)))
+ addAsSingletonList(config.textFormatting.ghostSinceSorrowFormat.formatText(GHOSTSINCESORROW.getInt()))
+ addAsSingletonList(config.textFormatting.ghostKillPerSorrowFormat.formatText(value))
+ addAsSingletonList(config.textFormatting.voltasFormat.formatText(VOLTACOUNT.getInt(), VOLTACOUNT.getInt(true)))
+ addAsSingletonList(config.textFormatting.plasmasFormat.formatText(PLASMACOUNT.getInt(), PLASMACOUNT.getInt(true)))
+ addAsSingletonList(config.textFormatting.ghostlyBootsFormat.formatText(GHOSTLYBOOTS.getInt(), GHOSTLYBOOTS.getInt(true)))
+ addAsSingletonList(config.textFormatting.bagOfCashFormat.formatText(BAGOFCASH.getInt(), BAGOFCASH.getInt(true)))
+ addAsSingletonList(config.textFormatting.avgMagicFindFormat.formatText(mgc))
+ addAsSingletonList(config.textFormatting.scavengerCoinsFormat.formatText(SCAVENGERCOINS.getInt(), SCAVENGERCOINS.getInt(true)))
+ addAsSingletonList(config.textFormatting.killComboFormat.formatText(KILLCOMBO.getInt(), MAXKILLCOMBO.getInt(true)))
+ addAsSingletonList(config.textFormatting.highestKillComboFormat.formatText(MAXKILLCOMBO.getInt(), MAXKILLCOMBO.getInt(true)))
+ addAsSingletonList(config.textFormatting.skillXPGainFormat.formatText(SKILLXPGAINED.get(), SKILLXPGAINED.get(true)))
+ addAsSingletonList(bestiaryFormatting.base.formatText(bestiary).formatBestiary(currentKill, killNeeded))
+ addAsSingletonList(xpHourFormatting.base.formatText(xp))
+ addAsSingletonList(killHourFormatting.base.formatText(killh))
+ addAsSingletonList(etaFormatting.base.formatText(eta).formatText(killETA))
+
+ /*
+ I'm very not sure about all that
+ */
+ val rate = 0.12 * (1 + (mgc.toDouble()/100))
+ val price = (BazaarApi.getBazaarDataByInternalName("SORROW")?.sellPrice ?: 0).toLong()
+ val final: String = (killInterp * price * (rate/100)).toLong().addSeparators()
+ addAsSingletonList(config.textFormatting.moneyHourFormat.formatText(final))
+ }
+
+
+ // Part of this was taken from GhostCounterV3 CT module
+ // maybe replace this with a SkillXpGainEvent ?
+ @SubscribeEvent
+ fun onActionBar(event: LorenzActionBarEvent) {
+ if (!isEnabled()) return
+ skillXPPattern.matchMatcher(event.message) {
+ val gained = group("gained").formatNumber().toDouble()
+ val total = group("total")
+ if (total != lastXp) {
+ val res = total.replace("\\D".toRegex(), "")
+ gain = (res.toLong() - lastXp.toLong()).toDouble().roundToInt()
+ num = (gain.toDouble() / gained)
+ if (gained in 150.0..450.0) {
+ if (lastXp != "0") {
+ if (num >= 0) {
+ KILLS.add(num)
+ KILLS.add(num, true)
+ GHOSTSINCESORROW.add(num)
+ KILLCOMBO.add(num)
+ SKILLXPGAINED.add(gained * num.roundToLong())
+ SKILLXPGAINED.add(gained * num.roundToLong(), true)
+ hidden?.bestiaryCurrentKill = hidden?.bestiaryCurrentKill?.plus(num) ?: num
+ }
+ }
+ }
+ lastXp = res
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onChat(event: LorenzChatEvent) {
+ if (!isEnabled()) return
+ if (LorenzUtils.skyBlockIsland != IslandType.DWARVEN_MINES) return
+ for (opt in Option.values()) {
+ val pattern = opt.pattern ?: continue
+ pattern.matchMatcher(event.message) {
+ when (opt) {
+ SORROWCOUNT, VOLTACOUNT, PLASMACOUNT, GHOSTLYBOOTS -> {
+ opt.add(1.0)
+ opt.add(1.0, true)
+ hidden?.totalMF = hidden?.totalMF?.plus(group("mf").substring(4).toDouble())
+ ?: group("mf").substring(4).toDouble()
+ TOTALDROPS.add(1.0)
+ update()
+ }
+
+ BAGOFCASH -> {
+ BAGOFCASH.add(1.0)
+ BAGOFCASH.add(1.0, true)
+ update()
+ }
+
+ KILLCOMBOCOINS -> {
+ KILLCOMBOCOINS.set(KILLCOMBOCOINS.get() + group("coin").toDouble())
+ update()
+ }
+
+ else -> {}
+ }
+ }
+
+ }
+ killComboExpiredPattern.matchMatcher(event.message) {
+ if (KILLCOMBO.getInt() > MAXKILLCOMBO.getInt()) {
+ MAXKILLCOMBO.set(group("combo").toDouble())
+ }
+ if (KILLCOMBO.getInt() > MAXKILLCOMBO.getInt(true)) {
+ MAXKILLCOMBO.set(group("combo").toDouble(), true)
+ }
+ KILLCOMBOCOINS.set(0.0)
+ KILLCOMBO.set(0.0)
+ update()
+ }
+ //replace with BestiaryLevelUpEvent ?
+ bestiaryPattern.matchMatcher(event.message.removeColor()) {
+ val currentLevel = group("newLevel").toInt()
+
+ when (val nextLevel = if (currentLevel >= 46) 47 else currentLevel + 1) {
+ 47 -> {
+ hidden?.bestiaryNextLevel = -1.0
+ hidden?.bestiaryCurrentKill = 3_000_000.0
+ hidden?.bestiaryKillNeeded = 0.0
+ }
+
+ else -> {
+ val killNeeded: Int = bestiaryData[nextLevel] ?: 0
+ hidden?.bestiaryNextLevel = nextLevel.toDouble()
+ hidden?.bestiaryCurrentKill = 0.0
+ hidden?.bestiaryKillNeeded = killNeeded.toDouble()
+ }
+ }
+ update()
+ }
+ }
+
+ @SubscribeEvent
+ fun onPurseChange(event: PurseChangeEvent) {
+ if (!isEnabled()) return
+ if (LorenzUtils.skyBlockArea != "The Mist") return
+ if (event.reason != PurseChangeCause.GAIN_MOB_KILL) return
+ SCAVENGERCOINS.add(event.coins, true)
+ SCAVENGERCOINS.add(event.coins)
+ }
+
+ @SubscribeEvent
+ fun onTick(event: TickEvent.ClientTickEvent) {
+ if (!isEnabled()) return
+ tick++
+ if (tick % 20 == 0) {
+ inMist = LorenzUtils.skyBlockArea == "The Mist"
+ update()
+ }
+
+ if (tick % 40 == 20) {
+ calculateXP()
+ calculateETA()
+ }
+
+ if (notifyCTModule && ProfileStorageData.profileSpecific?.ghostCounter?.ctDataImported == true) {
+ notifyCTModule = false
+ if (isUsingCTGhostCounter()) {
+ clickableChat("§6[SkyHanni] GhostCounterV3 ChatTriggers module has been detected, do you want to import saved data ? Click here to import data", "shimportghostcounterdata")
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onInventoryOpen(event: InventoryOpenEvent) {
+ if (!LorenzUtils.inSkyBlock) return
+ val inventoryName = event.inventoryName
+ if (inventoryName != "Bestiary ➜ Deep Caverns") return
+ val stacks = event.inventoryItems
+ val ghostStack = stacks[13] ?: return
+ val bestiaryNextLevel = Utils.parseIntOrRomanNumeral(ghostStack.displayName.substring(8)) + 1
+ hidden?.bestiaryNextLevel = bestiaryNextLevel.toDouble()
+
+ for (line in ghostStack.getLore()) {
+ ghostXPPattern.matchMatcher(line.removeColor().trim()) {
+ hidden?.bestiaryCurrentKill = group("current").formatNumber().toDouble()
+ hidden?.bestiaryKillNeeded = group("total").formatNumber().toDouble()
+ }
+ }
+ update()
+ }
+
+ fun isEnabled(): Boolean {
+ return LorenzUtils.inSkyBlock && config.enabled && LorenzUtils.skyBlockIsland == IslandType.DWARVEN_MINES
+ }
+
+ private fun percent(number: Double, total: Double): String {
+ return "${((number / total) * 100).roundToPrecision(4)}"
+ }
+
+ fun reset() {
+ for (opt in Option.values()) {
+ opt.set(0.0)
+ opt.set(0.0, true)
+ }
+ update()
+ }
+
+ private fun isUsingCTGhostCounter(): Boolean {
+ return ghostCounterV3File.exists() && ghostCounterV3File.isFile
+ }
+
+ fun importCTGhostCounterData() {
+ val c = ProfileStorageData.profileSpecific?.ghostCounter ?: return
+ if (isUsingCTGhostCounter()) {
+ if (c.ctDataImported) {
+ chat("§e[SkyHanni] §cYou already imported GhostCounterV3 data!")
+ return
+ }
+ val json = ConfigManager.gson.fromJson(FileReader(ghostCounterV3File), com.google.gson.JsonObject::class.java)
+ GHOSTSINCESORROW.add(json["ghostsSinceSorrow"].asDouble)
+ SORROWCOUNT.add(json["sorrowCount"].asDouble)
+ BAGOFCASH.add(json["BagOfCashCount"].asDouble)
+ PLASMACOUNT.add(json["PlasmaCount"].asDouble)
+ VOLTACOUNT.add(json["VoltaCount"].asDouble)
+ GHOSTLYBOOTS.add(json["GhostlyBootsCount"].asDouble)
+ KILLS.add(json["ghostsKilled"].asDouble)
+ hidden?.totalMF = hidden?.totalMF?.plus(json["TotalMF"].asDouble) ?: json["TotalMF"].asDouble
+ TOTALDROPS.add(json["TotalDrops"].asDouble)
+ c.ctDataImported = true
+ chat("§e[SkyHanni] §aImported data successfully!")
+ } else
+ chat("§e[SkyHanni] §cGhostCounterV3 ChatTriggers module not found!")
+ }
+
+ private fun String.formatText(value: Int, session: Int = -1): String {
+ return Utils.chromaStringByColourCode(this.replace("%value%", value.addSeparators())
+ .replace("%session%", session.addSeparators())
+ .replace("&", "§"))
+ }
+
+ private fun String.formatText(t: String): String {
+ return Utils.chromaStringByColourCode(this.replace("%value%", t)
+ .replace("&", "§"))
+ }
+
+ private fun String.formatText(value: Double, session: Double): String {
+ return Utils.chromaStringByColourCode(this.replace("%value%", value.roundToPrecision(2).addSeparators())
+ .replace("%session%", session.roundToPrecision(2).addSeparators())
+ .replace("&", "§"))
+ }
+
+ private fun String.formatBestiary(currentKill: Int, killNeeded: Int): String {
+ return Utils.chromaStringByColourCode(
+ this.replace("%currentKill%", if (config.showMax) bestiaryCurrentKill.addSeparators() else currentKill.addSeparators())
+ .replace("%percentNumber%", percent(bestiaryCurrentKill.toDouble(), 3_000_000.0))
+ .replace("%killNeeded%", NumberUtil.format(killNeeded))
+ .replace("%currentLevel%", if (hidden?.bestiaryNextLevel?.toInt()!! < 0) "46" else "${hidden?.bestiaryNextLevel?.toInt()!! - 1}")
+ .replace("%nextLevel%", if (config.showMax) "46" else "${hidden?.bestiaryNextLevel?.toInt()!!}")
+ .replace("&", "§"))
+ }
+
+ enum class Option(val pattern: Pattern? = null) {
+ KILLS,
+ SORROWCOUNT("§6§lRARE DROP! §r§9Sorrow §r§b\\([+](?<mf>.*)% §r§b✯ Magic Find§r§b\\)".toPattern()),
+ VOLTACOUNT("§6§lRARE DROP! §r§9Volta §r§b\\([+](?<mf>.*)% §r§b✯ Magic Find§r§b\\)".toPattern()),
+ PLASMACOUNT("§6§lRARE DROP! §r§9Plasma §r§b\\([+](?<mf>.*)% §r§b✯ Magic Find§r§b\\)".toPattern()),
+ GHOSTLYBOOTS("§6§lRARE DROP! §r§9Ghostly Boots §r§b\\([+](?<mf>.*)% §r§b✯ Magic Find§r§b\\)".toPattern()),
+ BAGOFCASH("§eThe ghost's death materialized §r§61,000,000 coins §r§efrom the mists!".toPattern()),
+ KILLCOMBOCOINS("[+]\\d+ Kill Combo [+](?<coin>.*) coins per kill".toPattern()),
+ TOTALDROPS,
+ GHOSTSINCESORROW,
+ SCAVENGERCOINS,
+ MAXKILLCOMBO,
+ KILLCOMBO("[+]\\d+ Kill Combo [+](?<coin>.*) coins per kill".toPattern()),
+ SKILLXPGAINED;
+
+ fun add(i: Double, s: Boolean = false) {
+ if (s)
+ session[this] = session[this]?.plus(i) ?: i
+ else
+ hidden?.data?.set(this, hidden?.data?.get(this)?.plus(i) ?: i)
+ }
+
+ fun set(i: Double, s: Boolean = false) {
+ if (s)
+ session[this] = i
+ else
+ hidden?.data?.set(this, i)
+ }
+
+ fun getInt(s: Boolean = false): Int {
+ return if (s)
+ session[this]?.roundToInt() ?: 0
+ else
+ hidden?.data?.get(this)?.roundToInt() ?: 0
+ }
+
+ fun get(s: Boolean = false): Double {
+ return if (s)
+ session[this] ?: 0.0
+ else
+ hidden?.data?.get(this) ?: 0.0
+ }
+ }
+
+ fun importFormatting() {
+ val base64: String = try {
+ Toolkit.getDefaultToolkit().systemClipboard.getData(DataFlavor.stringFlavor) as String
+ } catch (e: Exception) {
+ return
+ }
+
+ if (base64.length <= exportPrefix.length) return
+
+ val jsonString = try {
+ val t = String(Base64.getDecoder().decode(base64.trim()))
+ if (!t.startsWith(exportPrefix)) return
+ t.substring(exportPrefix.length)
+ } catch (e: IllegalArgumentException) {
+ return
+ }
+
+ val list = try {
+ JsonParser().parse(jsonString).asJsonArray
+ .filter { it.isJsonPrimitive }
+ .map { it.asString }
+ } catch (e: Exception) {
+ return
+ }
+
+ if (list.size == 30) {
+ with(config.textFormatting) {
+ titleFormat = list[0]
+ ghostKilledFormat = list[1]
+ sorrowsFormat = list[2]
+ ghostSinceSorrowFormat = list[3]
+ ghostKillPerSorrowFormat = list[4]
+ voltasFormat = list[5]
+ plasmasFormat = list[6]
+ ghostlyBootsFormat = list[7]
+ bagOfCashFormat = list[8]
+ avgMagicFindFormat = list[9]
+ scavengerCoinsFormat = list[10]
+ killComboFormat = list[11]
+ highestKillComboFormat = list[12]
+ skillXPGainFormat = list[13]
+ with(xpHourFormatting) {
+ base = list[14]
+ noData = list[15]
+ paused = list[16]
+ }
+ with(bestiaryFormatting) {
+ base = list[17]
+ openMenu = list[18]
+ maxed = list[19]
+ showMax_progress = list[20]
+ progress = list[21]
+ }
+ with(killHourFormatting) {
+ base = list[22]
+ noData = list[23]
+ paused = list[24]
+ }
+ with(etaFormatting) {
+ base = list[25]
+ maxed = list[26]
+ noData = list[27]
+ progress = list[28]
+ }
+ moneyHourFormat = list[29]
+ }
+ }
+ }
+
+ fun exportFormatting() {
+ val list = mutableListOf<String>()
+ with(config.textFormatting) {
+ list.add(titleFormat)
+ list.add(ghostKilledFormat)
+ list.add(sorrowsFormat)
+ list.add(ghostSinceSorrowFormat)
+ list.add(ghostKillPerSorrowFormat)
+ list.add(voltasFormat)
+ list.add(plasmasFormat)
+ list.add(ghostlyBootsFormat)
+ list.add(bagOfCashFormat)
+ list.add(avgMagicFindFormat)
+ list.add(scavengerCoinsFormat)
+ list.add(killComboFormat)
+ list.add(highestKillComboFormat)
+ list.add(skillXPGainFormat)
+ with(xpHourFormatting) {
+ list.add(base)
+ list.add(noData)
+ list.add(paused)
+ }
+ with(bestiaryFormatting) {
+ list.add(base)
+ list.add(openMenu)
+ list.add(maxed)
+ list.add(showMax_progress)
+ list.add(progress)
+ }
+ with(killHourFormatting) {
+ list.add(base)
+ list.add(noData)
+ list.add(paused)
+ }
+ with(etaFormatting) {
+ list.add(base)
+ list.add(maxed)
+ list.add(noData)
+ list.add(progress)
+ }
+ list.add(moneyHourFormat)
+ }
+ val jsonArray = JsonArray()
+ for (l in list) {
+ jsonArray.add(JsonPrimitive(l))
+ }
+ val base64 = Base64.getEncoder().encodeToString((exportPrefix + jsonArray).toByteArray(StandardCharsets.UTF_8))
+ Toolkit.getDefaultToolkit().systemClipboard.setContents(StringSelection(base64), null)
+ }
+
+ fun resetFormatting() {
+ with(config.textFormatting) {
+ titleFormat = "&6Ghost Counter"
+ ghostKilledFormat = " &6Ghost Killed: &b%value% &7(%session%)"
+ sorrowsFormat = " &6Sorrow: &b%value% &7(%session%)"
+ ghostSinceSorrowFormat = " &6Ghost since Sorrow: &b%value%"
+ ghostKillPerSorrowFormat = " &6Ghosts/Sorrow: &b%value%"
+ voltasFormat = " &6Volta: &b%value% &7(%session%)"
+ plasmasFormat = " &6Plasmas: &b%value% &7(%session%)"
+ ghostlyBootsFormat = " &6Ghostly Boots: &b%value% &7(%session%)"
+ bagOfCashFormat = " &6Bag Of Cash: &b%value% &7(%session%)"
+ avgMagicFindFormat = " &6Avg Magic Find: &b%value%"
+ scavengerCoinsFormat = " &6Scavenger Coins: &b%value% &7(%session%)"
+ killComboFormat = " &6Kill Combo: &b%value%"
+ highestKillComboFormat = " &6Highest Kill Combo: &b%value% &7(%session%)"
+ skillXPGainFormat = " &6Skill XP Gained: &b%value% &7(%session%)"
+ with(xpHourFormatting) {
+ base = " &6XP/h: &b%value%"
+ noData = "&bN/A"
+ paused = "&c(PAUSED)"
+ }
+ with(bestiaryFormatting) {
+ base = " &6Bestiary %currentLevel%->%nextLevel%: &b%value%"
+ openMenu = "§cOpen Bestiary Menu !"
+ maxed = "%currentKill% (&c&lMaxed!)"
+ showMax_progress = "%currentKill%/3M (%percentNumber%%)"
+ progress = "%currentKill%/%killNeeded%"
+ }
+ with(killHourFormatting) {
+ base = " &6Kill/h: &b%value%"
+ noData = "§bN/A"
+ paused = "&c(PAUSED)"
+ }
+ with(etaFormatting) {
+ base = " &6ETA: &b%value%"
+ maxed = "§c§lMAXED!"
+ noData = "§bN/A"
+ progress = "§b%value%"
+ }
+ moneyHourFormat = " &6$/h: &b%value%"
+ }
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt
index 9cf02c07d..20f203bb7 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt
@@ -12,12 +12,19 @@ import at.hannibal2.skyhanni.data.ProfileStorageData
import at.hannibal2.skyhanni.data.ScoreboardData
import at.hannibal2.skyhanni.features.garden.GardenAPI.getCropType
import at.hannibal2.skyhanni.utils.InventoryUtils
+import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName
+import at.hannibal2.skyhanni.utils.ItemUtils.name
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.LorenzUtils.colorCodeToRarity
+import at.hannibal2.skyhanni.utils.NEUItems
import at.hannibal2.skyhanni.utils.StringUtils.firstLetterUppercase
import at.hannibal2.skyhanni.utils.StringUtils.removeColor
+import at.hannibal2.skyhanni.utils.TabListData.Companion.getTabList
import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay.getCurrentPet
import io.github.moulberry.notenoughupdates.util.SkyBlockTime
+import net.minecraft.client.Minecraft
+import net.minecraft.item.ItemStack
+import net.minecraft.nbt.NBTTagCompound
import java.util.function.Supplier
import java.util.regex.Pattern
@@ -27,6 +34,49 @@ var lastKnownDisplayStrings: MutableMap<DiscordStatus, String> =
val purseRegex = Regex("""(?:Purse|Piggy): ([\d,]+)[\d.]*""")
val bitsRegex = Regex("""Bits: ([\d|,]+)[\d|.]*""")
+val stackingEnchants = mapOf(
+ "compact" to mapOf(
+ "levels" to listOf(0, 100, 500, 1500, 5000, 15000, 50000, 150000, 500000, 1000000),
+ "nbtNum" to "compact_blocks"
+ ),
+ "cultivating" to mapOf(
+ "levels" to listOf(
+ 0,
+ 1000,
+ 5000,
+ 25000,
+ 100000,
+ 300000,
+ 1500000,
+ 5000000,
+ 20000000,
+ 100000000
+ ), "nbtNum" to "farmed_cultivating"
+ ),
+ "expertise" to mapOf(
+ "levels" to listOf(0, 50, 100, 250, 500, 1000, 2500, 5500, 10000, 15000),
+ "nbtNum" to "expertise_kills"
+ ),
+ "hecatomb" to mapOf(
+ "levels" to listOf(0, 2, 5, 10, 20, 30, 40, 60, 80, 100),
+ "nbtNum" to "hecatomb_s_runs"
+ ),
+ "champion" to mapOf(
+ "levels" to listOf(
+ 0,
+ 50000,
+ 100000,
+ 250000,
+ 500000,
+ 1000000,
+ 1500000,
+ 2000000,
+ 2500000,
+ 3000000
+ ), "nbtNum" to "champion_combat_xp"
+ )
+) // nbtNum is the id of the enchantment in the nbt data
+
enum class DiscordStatus(private val displayMessageSupplier: Supplier<String>?) {
NONE(null),
@@ -54,7 +104,7 @@ enum class DiscordStatus(private val displayMessageSupplier: Supplier<String>?)
val scoreboard = ScoreboardData.sidebarLinesFormatted
// Matches coins amount in purse or piggy, with optional decimal points
val coins = scoreboard.firstOrNull { purseRegex.matches(it.removeColor()) }?.let {
- purseRegex.find(it.removeColor())?.groupValues?.get(1)
+ purseRegex.find(it.removeColor())?.groupValues?.get(1) ?: ""
}
if (coins == "1") {
lastKnownDisplayStrings[PURSE] = "1 Coin"
@@ -69,6 +119,7 @@ enum class DiscordStatus(private val displayMessageSupplier: Supplier<String>?)
val bits = scoreboard.firstOrNull { bitsRegex.matches(it.removeColor()) }?.let {
bitsRegex.find(it.removeColor())?.groupValues?.get(1)
}
+
when (bits) {
"1" -> "1 Bit"
null -> "0 Bits"
@@ -119,7 +170,36 @@ enum class DiscordStatus(private val displayMessageSupplier: Supplier<String>?)
}),
PROFILE({
- HypixelData.profileName.firstLetterUppercase()
+ val player = LorenzUtils.getPlayerName()
+
+ val tabData = getTabList()
+ val levelRegex = Regex("""\[(\d{1,3})] $player""")
+ var sbLevel = ""
+// SkyBlock Level: [999] on Lemon
+ for (line in tabData) {
+ if (line.contains(player)) {
+ val colorlessLine = line.removeColor()
+ sbLevel = levelRegex.find(colorlessLine)!!.groupValues[1]
+ break
+ }
+ }
+
+ var profile = "SkyBlock Level: [$sbLevel] on "
+
+ profile += (
+ if (HypixelData.ironman) "♲"
+ else if (HypixelData.bingo) "Ⓑ"
+ else if (HypixelData.stranded) "☀"
+ else ""
+ )
+
+ val fruit = HypixelData.profileName.firstLetterUppercase()
+ if (fruit == "") profile =
+ lastKnownDisplayStrings[PROFILE] ?: "SkyBlock Level: [$sbLevel]" // profile fruit has not loaded in yet
+ else profile += fruit
+
+ lastKnownDisplayStrings[PROFILE] = profile
+ profile
}),
SLAYER({
@@ -152,13 +232,11 @@ enum class DiscordStatus(private val displayMessageSupplier: Supplier<String>?)
AUTO({
val slayerResult = SLAYER.displayMessageSupplier!!.get()
- val milestoneResult = try {
- CROP_MILESTONES.displayMessageSupplier!!.get()
- } catch (e: Exception) {
- "Unable to get milestone"
- }
+ val stackingResult = STACKING.displayMessageSupplier!!.get()
+ val milestoneResult = CROP_MILESTONES.displayMessageSupplier!!.get()
if (slayerResult != "Planning to do a slayer quest") slayerResult
- else if (milestoneResult != "Unable to get milestone" && milestoneResult != "Unknown Item" && milestoneResult != "") milestoneResult
+ else if (milestoneResult != "Not farming!") milestoneResult
+ else if (stackingResult != "") stackingResult
else {
val statusNoAuto = DiscordStatus.values().toMutableList()
statusNoAuto.remove(AUTO)
@@ -176,9 +254,10 @@ enum class DiscordStatus(private val displayMessageSupplier: Supplier<String>?)
} ?: 100 // percentage to next milestone
if (tier != null) {
- lastKnownDisplayStrings[CROP_MILESTONES] = tier.let { "${crop.cropName}: Milestone $it ($progress)" }
+ "${crop.cropName}: Milestone $tier ($progress)"
+ } else {
+ "Not farming!"
}
- lastKnownDisplayStrings[CROP_MILESTONES] ?: ""
}),
PETS({
@@ -189,6 +268,62 @@ enum class DiscordStatus(private val displayMessageSupplier: Supplier<String>?)
"[Lvl $petLevel] ${colorCodeToRarity(colorCode)} $petName"
} ?: "No pet equipped"
+ }),
+
+ // Dynamic-only
+ STACKING({
+ // Logic for getting the currently held stacking enchant is from Skytils, except for getExtraAttributes() which they got from BiscuitDevelopment
+
+ fun getExtraAttributes(item: ItemStack?): NBTTagCompound? {
+ return if (item == null || !item.hasTagCompound()) {
+ null
+ } else item.getSubCompound("ExtraAttributes", false)
+ }
+
+ val itemInHand = Minecraft.getMinecraft().thePlayer.inventory.getCurrentItem()
+ val itemName = itemInHand?.let { NEUItems.getItemStack(it.getInternalName()).name?.removeColor() ?: "" } ?: ""
+
+ val extraAttributes = getExtraAttributes(itemInHand)
+
+ fun getProgressPercent(amount: Int, levels: List<Int>): String {
+ var currentLevel = 0
+ var percent = "MAXED"
+ for (level in levels.indices) {
+ if (amount > levels[level]) {
+ currentLevel++
+ continue
+ }
+ percent = if (amount.toDouble() == 0.0) {
+ ""
+ } else {
+ LorenzUtils.formatPercentage((amount.toDouble() - levels[level - 1]) / (levels[level] - levels[level - 1]))
+ }
+ break
+ }
+ return percent
+ }
+
+ var stackingReturn = ""
+ if (extraAttributes != null) {
+ val enchantments = extraAttributes.getCompoundTag("enchantments")
+ var stackingEnchant = ""
+ for (enchant in stackingEnchants.keys) {
+ if (extraAttributes.hasKey(stackingEnchants[enchant]?.get("nbtNum").toString())) {
+ stackingEnchant = enchant
+ break
+ }
+ }
+ val levels = stackingEnchants[stackingEnchant]?.get("levels") as? List<Int> ?: listOf(0)
+ val level = enchantments.getInteger(stackingEnchant)
+ val amount = extraAttributes.getInteger(stackingEnchants[stackingEnchant]?.get("nbtNum").toString())
+ val stackingPercent = getProgressPercent(amount, levels)
+
+ stackingReturn =
+ if (stackingPercent == "" || amount == 0) "" // outdated info is useless for AUTO; empty strings are manually ignored
+ else "$itemName: ${stackingEnchant.firstLetterUppercase()} $level ($stackingPercent)" // Hecatomb 100: (55.55%)
+ }
+ stackingReturn
+
})
;
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/CombatUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/CombatUtils.kt
new file mode 100644
index 000000000..bb199625d
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/CombatUtils.kt
@@ -0,0 +1,120 @@
+package at.hannibal2.skyhanni.utils
+
+import at.hannibal2.skyhanni.data.ProfileStorageData
+import at.hannibal2.skyhanni.features.misc.GhostCounter
+import io.github.moulberry.notenoughupdates.core.util.lerp.LerpUtils
+import io.github.moulberry.notenoughupdates.util.XPInformation
+
+object CombatUtils {
+
+ private var lastTotalXp = -1f
+ private val xpGainQueue = mutableListOf<Float>()
+ private var xpGainTimer = 0
+ var lastUpdate: Long = -1
+ private var skillInfo: XPInformation.SkillInfo? = null
+ private var skillInfoLast: XPInformation.SkillInfo? = null
+ private const val skillType = "Combat"
+ var xpGainHourLast = -1f
+ var xpGainHour = -1f
+ var isKilling = false
+ private var lastTotalKill = -1
+ private val killGainQueue = mutableListOf<Int>()
+ var lastKillUpdate: Long = -1
+ var killGainHourLast = -1
+ var killGainHour = -1
+ private var gainTimer = 0
+ var _isKilling = false
+
+
+ /**
+ * Taken from NotEnoughUpdates
+ */
+ fun calculateXP() {
+ lastUpdate = System.currentTimeMillis()
+ xpGainHourLast = xpGainHour
+ skillInfoLast = skillInfo
+ skillInfo = XPInformation.getInstance().getSkillInfo(skillType) ?: return
+ val totalXp: Float = skillInfo!!.totalXp
+ if (lastTotalXp > 0) {
+ val delta: Float = totalXp - lastTotalXp
+
+ if (delta > 0 && delta < 1000) {
+ xpGainTimer = GhostCounter.config.pauseTimer
+ xpGainQueue.add(0, delta)
+ while (xpGainQueue.size > 30) {
+ xpGainQueue.removeLast()
+ }
+ var totalGain = 0f
+ for (f in xpGainQueue) totalGain += f
+ xpGainHour = totalGain * (60 * 60) / xpGainQueue.size
+ isKilling = true
+ } else if (xpGainTimer > 0) {
+ xpGainTimer--
+ xpGainQueue.add(0, 0f)
+ while (xpGainQueue.size > 30) {
+ xpGainQueue.removeLast()
+ }
+ var totalGain = 0f
+ for (f in xpGainQueue) totalGain += f
+ xpGainHour = totalGain * (60 * 60) / xpGainQueue.size
+ isKilling = true
+ } else if (delta <= 0) {
+ isKilling = false
+ }
+ }
+ lastTotalXp = totalXp
+ }
+
+ /*
+ Must be a better way to do this than repeating the calculateXP function
+ */
+ fun calculateETA(){
+ lastKillUpdate = System.currentTimeMillis()
+ killGainHourLast = killGainHour
+ val nextLevel = GhostCounter.hidden?.bestiaryNextLevel?.toInt() ?: return
+ val kill = GhostCounter.hidden?.bestiaryCurrentKill?.toInt() ?: return
+ val sum = GhostCounter.bestiaryData.filterKeys { it <= nextLevel - 1 }.values.sum()
+ val cKill = sum + kill
+ val totalKill = if (GhostCounter.config.showMax) GhostCounter.bestiaryCurrentKill else cKill
+ if (lastTotalKill > 0){
+ val delta: Int = totalKill - lastTotalKill
+ if (delta in 1..19){
+ gainTimer = GhostCounter.config.pauseTimer
+ killGainQueue.add(0, delta)
+ while (killGainQueue.size > 30){
+ killGainQueue.removeLast()
+ }
+ var totalGain = 0
+ for (f in killGainQueue) totalGain += f
+ killGainHour = totalGain * (60 * 60) / killGainQueue.size
+ _isKilling = true
+ }else if(gainTimer > 0){
+ gainTimer--
+ killGainQueue.add(0, 0)
+ while (killGainQueue.size > 30){
+ killGainQueue.removeLast()
+ }
+ var totalGain = 0
+ for (f in killGainQueue) totalGain += f
+ killGainHour = totalGain * (60 * 60) / killGainQueue.size
+ _isKilling = true
+ }else if (delta <= 0){
+ _isKilling = false
+ }
+ }
+ lastTotalKill = totalKill
+ }
+ /**
+ * Taken from NotEnoughUpdates
+ */
+ fun interp(now: Float, last: Float, lastupdate: Long): Float {
+ var interp = now
+ if (last >= 0 && last != now) {
+ var factor = (System.currentTimeMillis() - lastupdate) / 1000f
+ factor = LerpUtils.clampZeroOne(factor)
+ interp = last + (now - last) * factor
+ }
+ return interp
+ }
+
+} \ No newline at end of file