diff --git a/README.md b/README.md index 780a972..cdb4c92 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,44 @@ -# Easy Giant's Foundry +
+
+
|
+
+Heating/Cooling Prediction | Low/High Heat Warning
+:-------------------------:|:-------------------------:
+
|
+
+Bonus Click Notification | Information Panel
+:-------------------------:|:-------------------------:
+
|
## Contributors
@@ -30,4 +54,11 @@ Helpful overlays for the Giant's Foundry minigame
- [Vanillj](https://github.com/Vanillj "Vanillj's github")
* Added config
* Added notifications for heat/stage changes
- * Added config for actions/heat left for notifications
\ No newline at end of file
+ * Added config for actions/heat left for notifications
+- [Louis Hong](https://github.com/TheLouisHong "Louis Hongs' github")
+ * Added crucible content and alloy quality calculation and overlay
+ * Added tools action/heat status overlay
+ * Added lava/waterfall action prediction and overlay
+ * Added border highlighting
+
+
diff --git a/banner_black.png b/banner_black.png
new file mode 100644
index 0000000..53d3766
Binary files /dev/null and b/banner_black.png differ
diff --git a/banner_white.png b/banner_white.png
new file mode 100644
index 0000000..cf19be2
Binary files /dev/null and b/banner_white.png differ
diff --git a/readme_gifs/best-mould.webp b/readme_gifs/best-mould.webp
new file mode 100644
index 0000000..89d7730
Binary files /dev/null and b/readme_gifs/best-mould.webp differ
diff --git a/readme_gifs/convert_gif2webp.bat b/readme_gifs/convert_gif2webp.bat
new file mode 100644
index 0000000..a7663bf
--- /dev/null
+++ b/readme_gifs/convert_gif2webp.bat
@@ -0,0 +1,5 @@
+# convert all gif files in the current directory to webp using ffmpeg
+# requires ffmpeg and webp
+
+for %%i in (*.gif) do D:\ffmpeg -i "%%i" -c:v libwebp -loop 0 -pix_fmt yuva420p "%%~ni.webp"
+
diff --git a/readme_gifs/crucible-value.png b/readme_gifs/crucible-value.png
new file mode 100644
index 0000000..d6cfc5a
Binary files /dev/null and b/readme_gifs/crucible-value.png differ
diff --git a/readme_gifs/info-panel.webp b/readme_gifs/info-panel.webp
new file mode 100644
index 0000000..22b9384
Binary files /dev/null and b/readme_gifs/info-panel.webp differ
diff --git a/readme_gifs/lava-waterfall-estimate.webp b/readme_gifs/lava-waterfall-estimate.webp
new file mode 100644
index 0000000..6d82e87
Binary files /dev/null and b/readme_gifs/lava-waterfall-estimate.webp differ
diff --git a/readme_gifs/tool-damage-warning.webp b/readme_gifs/tool-damage-warning.webp
new file mode 100644
index 0000000..50076a8
Binary files /dev/null and b/readme_gifs/tool-damage-warning.webp differ
diff --git a/readme_gifs/tools-bonus-notification.webp b/readme_gifs/tools-bonus-notification.webp
new file mode 100644
index 0000000..da16a5e
Binary files /dev/null and b/readme_gifs/tools-bonus-notification.webp differ
diff --git a/src/main/java/com/toofifty/easygiantsfoundry/BonusWidget.java b/src/main/java/com/toofifty/easygiantsfoundry/BonusWidget.java
index 5bf7f19..306f2ed 100644
--- a/src/main/java/com/toofifty/easygiantsfoundry/BonusWidget.java
+++ b/src/main/java/com/toofifty/easygiantsfoundry/BonusWidget.java
@@ -3,15 +3,17 @@ package com.toofifty.easygiantsfoundry;
import net.runelite.api.Client;
import net.runelite.api.widgets.Widget;
-public class BonusWidget {
- private static final int BONUS_WIDGET = 49414148;
- private static final int BONUS_COLOR = 0xfcd703;
+public class BonusWidget
+{
+ private static final int BONUS_WIDGET = 49414148;
+ private static final int BONUS_COLOR = 0xfcd703;
- static boolean isActive(Client client) {
- Widget bonusWidget = client.getWidget(BONUS_WIDGET);
- return bonusWidget != null
- && bonusWidget.getChildren() != null
- && bonusWidget.getChildren().length != 0
- && bonusWidget.getChild(0).getTextColor() == BONUS_COLOR;
- }
+ static boolean isActive(Client client)
+ {
+ Widget bonusWidget = client.getWidget(BONUS_WIDGET);
+ return bonusWidget != null
+ && bonusWidget.getChildren() != null
+ && bonusWidget.getChildren().length != 0
+ && bonusWidget.getChild(0).getTextColor() == BONUS_COLOR;
+ }
}
diff --git a/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryClientIDs.java b/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryClientIDs.java
new file mode 100644
index 0000000..9420e33
--- /dev/null
+++ b/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryClientIDs.java
@@ -0,0 +1,41 @@
+package com.toofifty.easygiantsfoundry;
+
+public class EasyGiantsFoundryClientIDs
+{
+ // heat and progress are from 0-1000
+ protected static final int VARBIT_HEAT = 13948;
+ protected static final int VARBIT_PROGRESS = 13949;
+
+ protected static final int VARBIT_BRONZE_COUNT = 13931;
+ protected static final int VARBIT_IRON_COUNT = 13932;
+ protected static final int VARBIT_STEEL_COUNT = 13933;
+ protected static final int VARBIT_MITHRIL_COUNT = 13934;
+ protected static final int VARBIT_ADAMANT_COUNT = 13935;
+ protected static final int VARBIT_RUNE_COUNT = 13936;
+
+ protected static final int VARBIT_FORTE_SELECTED = 13910;
+ protected static final int VARBIT_BLADE_SELECTED = 13911;
+ protected static final int VARBIT_TIP_SELECTED = 13912;
+
+ // 0 - load bars
+ // 1 - set mould
+ // 2 - collect preform
+ // 3 -
+ protected static final int VARBIT_GAME_STAGE = 13914;
+
+ protected static final int WIDGET_HEAT_PARENT = 49414153;
+ protected static final int WIDGET_LOW_HEAT_PARENT = 49414163;
+ protected static final int WIDGET_MED_HEAT_PARENT = 49414164;
+ protected static final int WIDGET_HIGH_HEAT_PARENT = 49414165;
+
+ protected static final int WIDGET_PROGRESS_PARENT = 49414219;
+ // children with type 3 are stage boxes
+ // every 11th child is a sprite
+
+ protected static final int SPRITE_ID_TRIP_HAMMER = 4442;
+ protected static final int SPRITE_ID_GRINDSTONE = 4443;
+ protected static final int SPRITE_ID_POLISHING_WHEEL = 4444;
+
+ protected static final int ANIMATION_HEATING = 827;
+ protected static final int ANIMATION_COOLING = 832;
+}
diff --git a/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryConfig.java b/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryConfig.java
index f053746..ed69cd4 100644
--- a/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryConfig.java
+++ b/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryConfig.java
@@ -1,245 +1,404 @@
package com.toofifty.easygiantsfoundry;
import java.awt.Color;
+
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.ConfigSection;
+import net.runelite.client.config.Range;
import net.runelite.client.ui.ColorScheme;
@ConfigGroup(EasyGiantsFoundryConfig.GROUP)
-public interface EasyGiantsFoundryConfig extends Config {
- String GROUP = "easygiantsfoundry";
- String SOUND_ID = "soundID";
- String POINTS_KEY = "easygiantsfoundrypoints";
+public interface EasyGiantsFoundryConfig extends Config
+{
- @ConfigSection(
- name = "Notifications",
- description = "Notifications",
- position = 0
- )
- String notificationList = "notificationList";
+ String GROUP = "easygiantsfoundry";
+ String SOUND_ID = "soundID";
+ String POINTS_KEY = "easygiantsfoundrypoints";
- @ConfigItem(
- keyName = "giantsFoundryStageNotification",
- name = "Notify stage changes",
- description = "Notifies just before completing a stage",
- position = 0,
- section = notificationList
- )
- default boolean showGiantsFoundryStageNotifications() {
- return true;
- }
+ @ConfigSection(
+ name = "Notifications",
+ description = "Notifications",
+ position = 0
+ )
+ String notificationList = "notificationList";
- @ConfigItem(
- keyName = "giantsFoundryHeatNotification",
- name = "Notify heat changes",
- description = "Notifies just before overheating/cooling when using tools",
- position = 1,
- section = notificationList
- )
- default boolean showGiantsFoundryHeatNotifications() {
- return true;
- }
+ @ConfigItem(
+ keyName = "giantsFoundryStageNotification",
+ name = "Notify stage changes",
+ description = "Notifies just before completing a stage",
+ position = 0,
+ section = notificationList
+ )
+ default boolean showGiantsFoundryStageNotifications()
+ {
+ return true;
+ }
- @ConfigItem(
- keyName = "giantsFoundryStageThreshold",
- name = "Stage threshold notification",
- description = "The number of actions left required for the notification.",
- position = 2,
- section = notificationList
- )
- default int StageNotificationsThreshold() {
- return 1;
- }
+ @ConfigItem(
+ keyName = "giantsFoundryHeatNotification",
+ name = "Notify heat changes",
+ description = "Notifies just before overheating/cooling when using tools",
+ position = 1,
+ section = notificationList
+ )
+ default boolean showGiantsFoundryHeatNotifications()
+ {
+ return true;
+ }
- @ConfigItem(
- keyName = "giantsFoundryHeatThreshold",
- name = "Heat threshold notification",
- description = "The heat level left required for the notification.",
- position = 3,
- section = notificationList
- )
- default int HeatNotificationsThreshold() {
- return 1;
- }
+ @ConfigItem(
+ keyName = "giantsFoundryStageThreshold",
+ name = "Stage threshold notification",
+ description = "The number of actions left required for the notification.",
+ position = 2,
+ section = notificationList
+ )
+ default int StageNotificationsThreshold()
+ {
+ return 1;
+ }
- @ConfigItem(
- keyName = "bonusNotification",
- name = "Notify bonus",
- description = "Notifies when bonus appears",
- position = 4,
- section = notificationList
- )
- default boolean bonusNotification() {
- return false;
- }
+ @ConfigItem(
+ keyName = "giantsFoundryHeatThreshold",
+ name = "Heat threshold notification",
+ description = "The heat level left required for the notification.",
+ position = 3,
+ section = notificationList
+ )
+ default int HeatNotificationsThreshold()
+ {
+ return 1;
+ }
- @ConfigItem(
- keyName = "bonusSound",
- name = "Bonus sound",
- description = "Plays a sound when bonus appears",
- position = 5,
- section = notificationList
- )
- default boolean bonusSoundNotify() {
- return true;
- }
+ @ConfigItem(
+ keyName = "bonusNotification",
+ name = "Notify bonus",
+ description = "Notifies when bonus appears",
+ position = 4,
+ section = notificationList
+ )
+ default boolean bonusNotification()
+ {
+ return false;
+ }
- @ConfigItem(
- keyName = SOUND_ID,
- name = "Bonus sound ID",
- description = "Sound Effect ID to play when bonus appears",
- position = 6,
- section = notificationList
- )
- default int soundId() {
- return 4212;
- }
+ @ConfigItem(
+ keyName = "bonusSound",
+ name = "Bonus sound",
+ description = "Plays a sound when bonus appears",
+ position = 5,
+ section = notificationList
+ )
+ default boolean bonusSoundNotify()
+ {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = SOUND_ID,
+ name = "Bonus sound ID",
+ description = "Sound Effect ID to play when bonus appears",
+ position = 6,
+ section = notificationList
+ )
+ default int soundId()
+ {
+ return 4212;
+ }
- @ConfigSection(
- name = "Highlights",
- description = "3D npc/object highlights",
- position = 1
- )
- String highlightList = "highlightList";
+ @ConfigSection(
+ name = "Highlights",
+ description = "3D npc/object highlights",
+ position = 1
+ )
+ String highlightList = "highlightList";
- @ConfigItem(
- keyName = "toolsHighlight",
- name = "Highlight Tools",
- description = "Highlights current tool with symbolic colors",
- position = 0,
- section = highlightList
- )
- default boolean highlightTools() {
- return true;
- }
+ @ConfigItem(
+ name = "Highlight Style",
+ description = "The style of the highlight",
+ position = 0,
+ section = highlightList,
+ keyName = "overlayOption")
+ default HighlightStyle highlightStyle()
+ {
+ return HighlightStyle.HIGHLIGHT_CLICKBOX;
+ }
- @ConfigItem(
- keyName = "waterLavaHighlight",
- name = "Highlight Waterfall/Lava Pool",
- description = "Highlight Lava Pool / Waterfall when heat change required",
- position = 1,
- section = highlightList
- )
- default boolean highlightWaterAndLava() {
- return true;
- }
+ @Range(
+ min = 1,
+ max = 4
+ )
+ @ConfigItem(
+ keyName = "borderThickness",
+ name = "Border Thickness",
+ description = "The thickness of the border",
+ position = 1,
+ section = highlightList
+ )
+ default int borderThickness()
+ {
+ return 1;
+ }
- @ConfigItem(
- keyName = "mouldHighlight",
- name = "Highlight Mould",
- description = "Highlight Mould when it should be clicked",
- position = 2,
- section = highlightList
- )
- default boolean highlightMould() {
- return true;
- }
+ @Range(
+ min = 0,
+ max = 4
+ )
+ @ConfigItem(
+ keyName = "borderFeather",
+ name = "Border Feather",
+ description = "The feather of the border",
+ position = 2,
+ section = highlightList
+ )
+ default int borderFeather()
+ {
+ return 0;
+ }
- @ConfigItem(
- keyName = "crucibleHighlight",
- name = "Highlight Crucible",
- description = "Highlight Crucible when it should be filled/poured",
- position = 3,
- section = highlightList
- )
- default boolean highlightCrucible() {
- return true;
- }
+ // alpha
+ @Range(
+ min = 0,
+ max = 255
+ )
+ @ConfigItem(
+ keyName = "borderAlpha",
+ name = "Border Alpha",
+ description = "The alpha of the border highlight",
+ position = 3,
+ section = highlightList
+ )
+ default int borderAlpha()
+ {
+ return 255;
+ }
- @ConfigItem(
- keyName = "kovacHighlight",
- name = "Highlight Kovac for hand in",
- description = "Highlight Kovac when sword can be handed in",
- position = 4,
- section = highlightList
- )
- default boolean highlightKovac() {
- return true;
- }
+ @ConfigItem(
+ keyName = "toolsHighlight",
+ name = "Highlight Tools",
+ description = "Highlights current tool with symbolic colors",
+ position = 4,
+ section = highlightList
+ )
+ default boolean highlightTools()
+ {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "waterLavaHighlight",
+ name = "Highlight Waterfall/Lava Pool",
+ description = "Highlight Lava Pool / Waterfall when heat change required",
+ position = 5,
+ section = highlightList
+ )
+ default boolean highlightWaterAndLava()
+ {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "mouldHighlight",
+ name = "Highlight Mould",
+ description = "Highlight Mould when it should be clicked",
+ position = 6,
+ section = highlightList
+ )
+ default boolean highlightMould()
+ {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "crucibleHighlight",
+ name = "Highlight Crucible",
+ description = "Highlight Crucible when it should be filled/poured",
+ position = 7,
+ section = highlightList
+ )
+ default boolean highlightCrucible()
+ {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "kovacHighlight",
+ name = "Highlight Kovac for hand in",
+ description = "Highlight Kovac when sword can be handed in",
+ position = 8,
+ section = highlightList
+ )
+ default boolean highlightKovac()
+ {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "crucibleContent",
+ name = "Show Crucible content and quality",
+ description = "Show the content and quality of the crucible",
+ position = 9,
+ section = highlightList
+ )
+ default boolean showCrucibleContent()
+ {
+ return true;
+ }
+
+ @ConfigSection(
+ name = "Info Panel",
+ description = "Settings for the Info Panel overlay",
+ position = 2
+ )
+ String infoPanelList = "infoPanelList";
+
+ @ConfigItem(
+ keyName = "infoTitle",
+ name = "Title",
+ description = "Toggle for \"Easy Giant's Foundry\" text",
+ position = 0,
+ section = infoPanelList
+ )
+ default boolean drawTitle()
+ {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "heatInfo",
+ name = "Heat",
+ description = "Toggle for Heat text",
+ position = 1,
+ section = infoPanelList
+ )
+ default boolean drawHeatInfo()
+ {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "stageInfo",
+ name = "Stage",
+ description = "Toggle for Stage text",
+ position = 2,
+ section = infoPanelList
+ )
+ default boolean drawStageInfo()
+ {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "actionLeft",
+ name = "Actions Left",
+ description = "Toggle for actions left text",
+ position = 3,
+ section = infoPanelList
+ )
+ default boolean drawActionsLeft()
+ {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "heatLeft",
+ name = "Heat Left",
+ description = "Toggle for heat left text",
+ position = 4,
+ section = infoPanelList
+ )
+ default boolean drawHeatLeft()
+ {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "shopPoints",
+ name = "Reputation",
+ description = "Toggle for reputation text",
+ position = 5,
+ section = infoPanelList
+ )
+ default boolean drawShopPoints()
+ {
+ return false;
+ }
- @ConfigSection(
- name = "Info Panel",
- description = "Settings for the Info Panel overlay",
- position = 2
- )
- String infoPanelList = "infoPanelList";
+ @ConfigSection(
+ name = "Info Overlay",
+ description = "Overlay Text Info On Objects",
+ position = 3
+ )
+ String infoOverlay = "infoOverlay";
- @ConfigItem(
- keyName = "infoTitle",
- name = "Title",
- description = "Toggle for \"Easy Giant's Foundry\" text",
- position = 0,
- section = infoPanelList
- )
- default boolean drawTitle() {
- return true;
- }
+ @ConfigItem(
+ keyName = "actionLeftOverlay",
+ name = "Actions Left Overlay",
+ description = "Toggle for actions left overlay",
+ position = 0,
+ section = infoOverlay
+ )
+ default boolean drawActionLeftOverlay()
+ {
+ return true;
+ }
- @ConfigItem(
- keyName = "heatInfo",
- name = "Heat",
- description = "Toggle for Heat text",
- position = 1,
- section = infoPanelList
- )
- default boolean drawHeatInfo() {
- return true;
- }
+ @ConfigItem(
+ keyName = "heatLeftOverlay",
+ name = "Heat Left Overlay",
+ description = "Toggle for heat left overlay",
+ position = 1,
+ section = infoOverlay
+ )
+ default boolean drawHeatLeftOverlay()
+ {
+ return true;
+ }
- @ConfigItem(
- keyName = "stageInfo",
- name = "Stage",
- description = "Toggle for Stage text",
- position = 2,
- section = infoPanelList
- )
- default boolean drawStageInfo() {
- return true;
- }
+ @ConfigItem(
+ keyName = "crucibleInfoOverlay",
+ name = "Crucible Info Overlay",
+ description = "Toggle for crucible info overlay",
+ position = 2,
+ section = infoOverlay
+ )
+ default boolean drawCrucibleInfoOverlay()
+ {
+ return true;
+ }
- @ConfigItem(
- keyName = "actionsLeft",
- name = "Actions Left",
- description = "Toggle for Actions left text",
- position = 3,
- section = infoPanelList
- )
- default boolean drawActionsLeft() {
- return true;
- }
-
- @ConfigItem(
- keyName = "heatLeft",
- name = "Heat Left",
- description = "Toggle for Heat left text",
- position = 4,
- section = infoPanelList
- )
- default boolean drawHeatLeft() {
- return true;
- }
-
- @ConfigItem(
- keyName = "shopPoints",
- name = "Reputation",
- description = "Toggle for reputation text",
- position = 5,
- section = infoPanelList
- )
- default boolean drawShopPoints()
- {
- return false;
- }
+ @ConfigItem(
+ keyName = "mouldInfoOverlay",
+ name = "Mould Info Overlay",
+ description = "Toggle for mould info overlay",
+ position = 3,
+ section = infoOverlay
+ )
+ default boolean drawMouldInfoOverlay()
+ {
+ return true;
+ }
+ @ConfigItem(
+ keyName = "LavaWaterInfoOverlay",
+ name = "Lava/Waterfall Info Overlay",
+ description = "Toggle for lava/waterfall info overlay",
+ position = 4,
+ section = infoOverlay
+ )
+ default boolean drawLavaWaterInfoOverlay()
+ {
+ return true;
+ }
@ConfigSection(
name = "Colour",
description = "Colours",
- position = 3
+ position = 4
)
String colourList = "colourList";
@@ -327,4 +486,23 @@ public interface EasyGiantsFoundryConfig extends Config {
{
return Color.CYAN;
}
+
+ @ConfigSection(
+ name = "Advanced",
+ description = "Advanced Settings",
+ position = 5
+ )
+ String generalSettings = "generalSettings";
+
+ @ConfigItem(
+ keyName = "heatingCoolingMarginOfError",
+ name = "Heating/Cooling Margin of Error",
+ description = "The margin of error for lava/waterfall calculations to compensate for decay and overshooting.",
+ position = 0,
+ section = generalSettings
+ )
+ default int heatingCoolingBuffer()
+ {
+ return 20;
+ }
}
diff --git a/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryHelper.java b/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryHelper.java
index 8041aaf..ab4d879 100644
--- a/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryHelper.java
+++ b/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryHelper.java
@@ -1,83 +1,29 @@
package com.toofifty.easygiantsfoundry;
-import com.toofifty.easygiantsfoundry.enums.Heat;
-import com.toofifty.easygiantsfoundry.enums.Stage;
-import javax.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import net.runelite.client.ui.ColorScheme;
+
import javax.inject.Singleton;
+import java.awt.Color;
+@Slf4j
@Singleton
-public class EasyGiantsFoundryHelper
+public final class EasyGiantsFoundryHelper
{
- // heat lowers every 2 ticks
- // seems to be between 7-11 per
- private static final int HEAT_LAVA_HEAT = 8;
- private static final int COOL_WATERFALL_HEAT = -8;
- // 27-37
- private static final int DUNK_LAVA_HEAT = 32;
- private static final int QUENCH_WATERFALL_HEAT = -32;
-
- @Inject
- private EasyGiantsFoundryState state;
-
- /**
- * Get the amount of progress each stage needs
- */
- public double getProgressPerStage()
+ public static Color getHeatColor(int actions, int heat)
{
- return 1000d / state.getStages().size();
- }
-
- public int getActionsLeftInStage()
- {
- int progress = state.getProgressAmount();
- double progressPerStage = getProgressPerStage();
- double progressTillNext = progressPerStage - progress % progressPerStage;
-
- Stage current = state.getCurrentStage();
- return (int) Math.ceil(progressTillNext / current.getProgressPerAction());
- }
-
- public int[] getCurrentHeatRange()
- {
- switch (state.getCurrentStage())
+ if (heat >= actions)
{
- case POLISHING_WHEEL:
- return state.getLowHeatRange();
- case GRINDSTONE:
- return state.getMedHeatRange();
- case TRIP_HAMMER:
- return state.getHighHeatRange();
- default:
- return new int[]{0, 0};
- }
- }
-
- /**
- * Get the amount of current stage actions that can be
- * performed before the heat drops too high or too low to
- * continue
- */
- public int getActionsForHeatLevel()
- {
- Heat heatStage = state.getCurrentHeat();
- Stage stage = state.getCurrentStage();
- if (heatStage != stage.getHeat())
- {
- // not the right heat to start with
- return 0;
+ return ColorScheme.PROGRESS_COMPLETE_COLOR;
}
- int[] range = getCurrentHeatRange();
- int actions = 0;
- int heat = state.getHeatAmount();
- while (heat > range[0] && heat < range[1])
+ if (heat > 0)
{
- actions++;
- heat += stage.getHeatChange();
+ return ColorScheme.PROGRESS_INPROGRESS_COLOR;
}
- return actions;
+ return ColorScheme.PROGRESS_ERROR_COLOR;
}
}
diff --git a/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryPlugin.java b/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryPlugin.java
index dbfc44a..16d0c0d 100644
--- a/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryPlugin.java
+++ b/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryPlugin.java
@@ -1,10 +1,14 @@
package com.toofifty.easygiantsfoundry;
import com.google.inject.Provides;
+import static com.toofifty.easygiantsfoundry.EasyGiantsFoundryClientIDs.VARBIT_HEAT;
import com.toofifty.easygiantsfoundry.enums.Stage;
+
import javax.inject.Inject;
+
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
+import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.GameObject;
import net.runelite.api.GameState;
@@ -15,6 +19,7 @@ import net.runelite.api.events.GameObjectSpawned;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.ItemContainerChanged;
+import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.NpcSpawned;
import net.runelite.api.events.ScriptPostFired;
@@ -143,6 +148,7 @@ public class EasyGiantsFoundryPlugin extends Plugin
}
}
+
@Subscribe
public void onGameStateChanged(GameStateChanged event)
{
@@ -172,14 +178,14 @@ public class EasyGiantsFoundryPlugin extends Plugin
}
if (config.showGiantsFoundryStageNotifications() &&
- helper.getActionsLeftInStage() == config.StageNotificationsThreshold() &&
+ state.getActionsLeftInStage() == config.StageNotificationsThreshold() &&
(oldStage == null || oldStage != state.getCurrentStage()))
{
notifier.notify("About to finish the current stage!");
oldStage = state.getCurrentStage();
}
else if (config.showGiantsFoundryHeatNotifications() &&
- helper.getActionsForHeatLevel() == config.HeatNotificationsThreshold())
+ state.getActionsForHeatLevel() == config.HeatNotificationsThreshold())
{
notifier.notify("About to run out of heat!");
}
@@ -245,6 +251,48 @@ public class EasyGiantsFoundryPlugin extends Plugin
}
}
+ @Subscribe
+ public void onMenuOptionClicked(MenuOptionClicked event)
+ {
+ if (!state.isEnabled()) return;
+
+ if (event.getMenuTarget().contains("Crucible "))
+ {
+ if (event.getMenuOption().equals("Pour"))
+ {
+ // add persistent game message of the alloy value so user can reference later.
+ client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "The quality of the alloy poured is " + (int) state.getCrucibleQuality(), null);
+ }
+ }
+
+ // Could not find a varbit to capture, so capture the menu-option directly.
+ // start the HeatActionStateMachine when varbit begins to update in onVarbitChanged()
+ if (event.getMenuOption().startsWith("Heat-preform"))
+ {
+ state.heatingCoolingState.stop();
+ state.heatingCoolingState.setup(7, 0, "heats");
+ }
+ else if (event.getMenuOption().startsWith("Dunk-preform"))
+ {
+ state.heatingCoolingState.stop();
+ state.heatingCoolingState.setup(27, 2, "dunks");
+ }
+ else if (event.getMenuOption().startsWith("Cool-preform"))
+ {
+ state.heatingCoolingState.stop();
+ state.heatingCoolingState.setup(-7, 0, "cools");
+ }
+ else if (event.getMenuOption().startsWith("Quench-preform"))
+ {
+ state.heatingCoolingState.stop();
+ state.heatingCoolingState.setup(-27, -2, "quenches");
+ }
+ else // canceled heating/cooling, stop the heating state-machine
+ {
+ state.heatingCoolingState.stop();
+ }
+ }
+
@Subscribe
public void onScriptPostFired(ScriptPostFired event)
{
@@ -257,6 +305,9 @@ public class EasyGiantsFoundryPlugin extends Plugin
}
}
+ // previous heat varbit value, used to filter out passive heat decay.
+ private int previousHeat = 0;
+
@Subscribe
public void onVarbitChanged(VarbitChanged event)
{
@@ -264,6 +315,24 @@ public class EasyGiantsFoundryPlugin extends Plugin
{
reputation = client.getVarpValue(REPUTATION_VARBIT);
}
+
+ // start the heating state-machine when the varbit updates
+ // if heat varbit updated and the user clicked, start the state-machine
+ if (event.getVarbitId() == VARBIT_HEAT && state.heatingCoolingState.getActionName() != null)
+ {
+ // ignore passive heat decay, one heat per two ticks
+ if (event.getValue() - previousHeat != -1)
+ {
+ // if the state-machine is idle, start it
+ if (state.heatingCoolingState.isIdle())
+ {
+ state.heatingCoolingState.start(state, config, state.getHeatAmount());
+ }
+
+ state.heatingCoolingState.onTick();
+ }
+ previousHeat = event.getValue();
+ }
}
@Subscribe
diff --git a/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryState.java b/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryState.java
index 47e2b63..370a9b5 100644
--- a/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryState.java
+++ b/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryState.java
@@ -1,7 +1,13 @@
package com.toofifty.easygiantsfoundry;
+import static com.toofifty.easygiantsfoundry.MathUtil.max1;
+import static com.toofifty.easygiantsfoundry.EasyGiantsFoundryClientIDs.*;
+
import com.toofifty.easygiantsfoundry.enums.Heat;
import com.toofifty.easygiantsfoundry.enums.Stage;
+import static com.toofifty.easygiantsfoundry.enums.Stage.GRINDSTONE;
+import static com.toofifty.easygiantsfoundry.enums.Stage.POLISHING_WHEEL;
+import static com.toofifty.easygiantsfoundry.enums.Stage.TRIP_HAMMER;
import lombok.Getter;
import lombok.Setter;
import net.runelite.api.Client;
@@ -15,33 +21,6 @@ import java.util.List;
@Singleton
public class EasyGiantsFoundryState
{
- // heat and progress are from 0-1000
- private static final int VARBIT_HEAT = 13948;
- private static final int VARBIT_PROGRESS = 13949;
-
- private static final int VARBIT_ORE_COUNT = 13934;
- private static final int VARBIT_FORTE_SELECTED = 13910;
- private static final int VARBIT_BLADE_SELECTED = 13911;
- private static final int VARBIT_TIP_SELECTED = 13912;
-
- // 0 - load bars
- // 1 - set mould
- // 2 - collect preform
- // 3 -
- static final int VARBIT_GAME_STAGE = 13914;
-
- private static final int WIDGET_HEAT_PARENT = 49414153;
- private static final int WIDGET_LOW_HEAT_PARENT = 49414163;
- private static final int WIDGET_MED_HEAT_PARENT = 49414164;
- private static final int WIDGET_HIGH_HEAT_PARENT = 49414165;
-
- static final int WIDGET_PROGRESS_PARENT = 49414219;
- // children with type 3 are stage boxes
- // every 11th child is a sprite
-
- private static final int SPRITE_ID_TRIP_HAMMER = 4442;
- private static final int SPRITE_ID_GRINDSTONE = 4443;
- private static final int SPRITE_ID_POLISHING_WHEEL = 4444;
@Inject
private Client client;
@@ -80,7 +59,7 @@ public class EasyGiantsFoundryState
return 0;
}
- heatRangeRatio = medHeat.getWidth() /(double) heatWidget.getWidth();
+ heatRangeRatio = medHeat.getWidth() / (double) heatWidget.getWidth();
}
return heatRangeRatio;
@@ -125,13 +104,13 @@ public class EasyGiantsFoundryState
switch (child.getSpriteId())
{
case SPRITE_ID_TRIP_HAMMER:
- stages.add(Stage.TRIP_HAMMER);
+ stages.add(TRIP_HAMMER);
break;
case SPRITE_ID_GRINDSTONE:
- stages.add(Stage.GRINDSTONE);
+ stages.add(GRINDSTONE);
break;
case SPRITE_ID_POLISHING_WHEEL:
- stages.add(Stage.POLISHING_WHEEL);
+ stages.add(POLISHING_WHEEL);
break;
}
}
@@ -204,4 +183,109 @@ public class EasyGiantsFoundryState
else
return 0;
}
+
+ public int getCrucibleCount()
+ {
+ int bronze = client.getVarbitValue(VARBIT_BRONZE_COUNT);
+ int iron = client.getVarbitValue(VARBIT_IRON_COUNT);
+ int steel = client.getVarbitValue(VARBIT_STEEL_COUNT);
+ int mithril = client.getVarbitValue(VARBIT_MITHRIL_COUNT);
+ int adamant = client.getVarbitValue(VARBIT_ADAMANT_COUNT);
+ int rune = client.getVarbitValue(VARBIT_RUNE_COUNT);
+
+ return bronze + iron + steel + mithril + adamant + rune;
+ }
+
+ public double getCrucibleQuality()
+ {
+ if (getCrucibleCount() == 0) return 0;
+
+ int bronze = client.getVarbitValue(VARBIT_BRONZE_COUNT);
+ int iron = client.getVarbitValue(VARBIT_IRON_COUNT);
+ int steel = client.getVarbitValue(VARBIT_STEEL_COUNT);
+ int mithril = client.getVarbitValue(VARBIT_MITHRIL_COUNT);
+ int adamant = client.getVarbitValue(VARBIT_ADAMANT_COUNT);
+ int rune = client.getVarbitValue(VARBIT_RUNE_COUNT);
+
+ final int BRONZE_VALUE = 1;
+ final int IRON_VALUE = 2;
+ final int STEEL_VALUE = 3;
+ final int MITHRIL_VALUE = 4;
+ final int ADAMANT_VALUE = 5;
+ final int RUNE_VALUE = 6;
+
+ final double vB = (10 * BRONZE_VALUE * bronze) / 28.0;
+ final double vI = (10 * IRON_VALUE * iron) / 28.0;
+ final double vS = (10 * STEEL_VALUE * steel) / 28.0;
+ final double vM = (10 * MITHRIL_VALUE * mithril) / 28.0;
+ final double vA = (10 * ADAMANT_VALUE * adamant) / 28.0;
+ final double vR = (10 * RUNE_VALUE * rune) / 28.0;
+
+ return
+ (10 * (vB + vI + vS + vM + vA + vR)
+ + (max1(vB) * max1(vI) * max1(vS) * max1(vM) * max1(vA) * max1(vR))) / 10.0;
+ }
+
+ /**
+ * Get the amount of progress each stage needs
+ */
+ public double getProgressPerStage()
+ {
+ return 1000d / getStages().size();
+ }
+
+ public int getActionsLeftInStage()
+ {
+ int progress = getProgressAmount();
+ double progressPerStage = getProgressPerStage();
+ double progressTillNext = progressPerStage - progress % progressPerStage;
+
+ Stage current = getCurrentStage();
+ return (int) Math.ceil(progressTillNext / current.getProgressPerAction());
+ }
+
+ public int[] getCurrentHeatRange()
+ {
+ switch (getCurrentStage())
+ {
+ case POLISHING_WHEEL:
+ return getLowHeatRange();
+ case GRINDSTONE:
+ return getMedHeatRange();
+ case TRIP_HAMMER:
+ return getHighHeatRange();
+ default:
+ return new int[]{0, 0};
+ }
+ }
+
+ /**
+ * Get the amount of current stage actions that can be
+ * performed before the heat drops too high or too low to
+ * continue
+ */
+ public int getActionsForHeatLevel()
+ {
+ Heat heatStage = getCurrentHeat();
+ Stage stage = getCurrentStage();
+ if (heatStage != stage.getHeat())
+ {
+ // not the right heat to start with
+ return 0;
+ }
+
+ int[] range = getCurrentHeatRange();
+ int actions = 0;
+ int heat = getHeatAmount();
+ while (heat > range[0] && heat < range[1])
+ {
+ actions++;
+ heat += stage.getHeatChange();
+ }
+
+ return actions;
+ }
+
+ public HeatActionStateMachine heatingCoolingState = new HeatActionStateMachine();
+
}
diff --git a/src/main/java/com/toofifty/easygiantsfoundry/FoundryOverlay2D.java b/src/main/java/com/toofifty/easygiantsfoundry/FoundryOverlay2D.java
index 660271f..a5e5f5b 100644
--- a/src/main/java/com/toofifty/easygiantsfoundry/FoundryOverlay2D.java
+++ b/src/main/java/com/toofifty/easygiantsfoundry/FoundryOverlay2D.java
@@ -1,14 +1,15 @@
package com.toofifty.easygiantsfoundry;
+import static com.toofifty.easygiantsfoundry.EasyGiantsFoundryHelper.getHeatColor;
import com.toofifty.easygiantsfoundry.enums.Heat;
import com.toofifty.easygiantsfoundry.enums.Stage;
-import java.awt.Color;
+
import java.awt.Dimension;
import java.awt.Graphics2D;
import javax.inject.Inject;
import javax.inject.Singleton;
+
import net.runelite.api.Client;
-import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.overlay.OverlayPanel;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.components.LineComponent;
@@ -21,35 +22,22 @@ public class FoundryOverlay2D extends OverlayPanel
private final Client client;
private final EasyGiantsFoundryPlugin plugin;
private final EasyGiantsFoundryState state;
- private final EasyGiantsFoundryHelper helper;
private final EasyGiantsFoundryConfig config;
@Inject
- private FoundryOverlay2D(Client client, EasyGiantsFoundryPlugin plugin, EasyGiantsFoundryState state, EasyGiantsFoundryHelper helper, EasyGiantsFoundryConfig config)
+ private FoundryOverlay2D(
+ Client client,
+ EasyGiantsFoundryPlugin plugin,
+ EasyGiantsFoundryState state,
+ EasyGiantsFoundryConfig config)
{
this.client = client;
this.plugin = plugin;
this.state = state;
- this.helper = helper;
this.config = config;
this.setPosition(OverlayPosition.BOTTOM_LEFT);
}
- private Color getHeatColor(int actions, int heat)
- {
- if (heat >= actions)
- {
- return ColorScheme.PROGRESS_COMPLETE_COLOR;
- }
-
- if (heat > 0)
- {
- return ColorScheme.PROGRESS_INPROGRESS_COLOR;
- }
-
- return ColorScheme.PROGRESS_ERROR_COLOR;
- }
-
@Override
public Dimension render(Graphics2D graphics)
{
@@ -64,7 +52,8 @@ public class FoundryOverlay2D extends OverlayPanel
panelComponent.getChildren().add(TitleComponent.builder().text("Easy Giant's Foundry").build());
}
- if (swordPickedUp) {
+ if (swordPickedUp)
+ {
Heat heat = state.getCurrentHeat();
Stage stage = state.getCurrentStage();
@@ -81,8 +70,8 @@ public class FoundryOverlay2D extends OverlayPanel
);
}
- int actionsLeft = helper.getActionsLeftInStage();
- int heatLeft = helper.getActionsForHeatLevel();
+ int actionsLeft = state.getActionsLeftInStage();
+ int heatLeft = state.getActionsForHeatLevel();
if (config.drawActionsLeft())
{
@@ -102,7 +91,7 @@ public class FoundryOverlay2D extends OverlayPanel
if (config.drawShopPoints())
{
panelComponent.getChildren().add(
- LineComponent.builder().left("Reputation").right(plugin.getReputation() + "").build()
+ LineComponent.builder().left("Reputation").right(plugin.getReputation() + "").build()
);
}
diff --git a/src/main/java/com/toofifty/easygiantsfoundry/FoundryOverlay3D.java b/src/main/java/com/toofifty/easygiantsfoundry/FoundryOverlay3D.java
index 7ee4dab..781bb02 100644
--- a/src/main/java/com/toofifty/easygiantsfoundry/FoundryOverlay3D.java
+++ b/src/main/java/com/toofifty/easygiantsfoundry/FoundryOverlay3D.java
@@ -1,229 +1,419 @@
package com.toofifty.easygiantsfoundry;
+import static com.toofifty.easygiantsfoundry.EasyGiantsFoundryClientIDs.VARBIT_GAME_STAGE;
+import static com.toofifty.easygiantsfoundry.EasyGiantsFoundryClientIDs.WIDGET_PROGRESS_PARENT;
+import static com.toofifty.easygiantsfoundry.EasyGiantsFoundryHelper.getHeatColor;
+import static com.toofifty.easygiantsfoundry.MouldHelper.SWORD_TYPE_1_VARBIT;
+import static com.toofifty.easygiantsfoundry.MouldHelper.SWORD_TYPE_2_VARBIT;
+import com.toofifty.easygiantsfoundry.enums.CommissionType;
import com.toofifty.easygiantsfoundry.enums.Heat;
import com.toofifty.easygiantsfoundry.enums.Stage;
+
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Shape;
import javax.inject.Inject;
+
import net.runelite.api.Client;
import net.runelite.api.GameObject;
import net.runelite.api.NPC;
+import net.runelite.api.Perspective;
import net.runelite.api.Point;
+import net.runelite.api.coords.LocalPoint;
import net.runelite.api.widgets.Widget;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayPosition;
+import net.runelite.client.ui.overlay.OverlayUtil;
+import net.runelite.client.ui.overlay.outline.ModelOutlineRenderer;
+import org.apache.commons.lang3.StringUtils;
-public class FoundryOverlay3D extends Overlay {
+public class FoundryOverlay3D extends Overlay
+{
- private static final int HAND_IN_WIDGET = 49414221;
+ private static final int HAND_IN_WIDGET = 49414221;
+ private final ModelOutlineRenderer modelOutlineRenderer;
- GameObject tripHammer;
- GameObject grindstone;
- GameObject polishingWheel;
- GameObject lavaPool;
- GameObject waterfall;
- GameObject mouldJig;
- GameObject crucible;
- NPC kovac;
+ GameObject tripHammer;
+ GameObject grindstone;
+ GameObject polishingWheel;
+ GameObject lavaPool;
+ GameObject waterfall;
+ GameObject mouldJig;
+ GameObject crucible;
+ NPC kovac;
- private final Client client;
- private final EasyGiantsFoundryState state;
- private final EasyGiantsFoundryHelper helper;
- private final EasyGiantsFoundryConfig config;
+ private final Client client;
+ private final EasyGiantsFoundryState state;
+ private final EasyGiantsFoundryConfig config;
- @Inject
- private FoundryOverlay3D(Client client, EasyGiantsFoundryState state, EasyGiantsFoundryHelper helper,
- EasyGiantsFoundryConfig config)
- {
- setPosition(OverlayPosition.DYNAMIC);
- this.client = client;
- this.state = state;
- this.helper = helper;
- this.config = config;
- }
+ @Inject
+ private FoundryOverlay3D(
+ Client client,
+ EasyGiantsFoundryState state,
+ EasyGiantsFoundryConfig config,
+ ModelOutlineRenderer modelOutlineRenderer)
+ {
+ setPosition(OverlayPosition.DYNAMIC);
+ this.client = client;
+ this.state = state;
+ this.config = config;
+ this.modelOutlineRenderer = modelOutlineRenderer;
+ }
- private Color getObjectColor(Stage stage, Heat heat)
- {
- if (stage.getHeat() != heat)
- {
- return config.toolBad();
- }
+ private Color getObjectColor(Stage stage, Heat heat)
+ {
+ if (stage.getHeat() != heat)
+ {
+ return config.toolBad();
+ }
- if (BonusWidget.isActive(client))
- {
- return config.toolBonus();
- }
+ if (BonusWidget.isActive(client))
+ {
+ return config.toolBonus();
+ }
- int actionsLeft = helper.getActionsLeftInStage();
- int heatLeft = helper.getActionsForHeatLevel();
- if (actionsLeft <= 1 || heatLeft <= 1)
- {
- return config.toolCaution();
- }
+ int actionsLeft = state.getActionsLeftInStage();
+ int heatLeft = state.getActionsForHeatLevel();
+ if (actionsLeft <= 1 || heatLeft <= 1)
+ {
+ return config.toolCaution();
+ }
- return config.toolGood();
- }
+ return config.toolGood();
+ }
- private GameObject getStageObject(Stage stage)
- {
- switch (stage)
- {
- case TRIP_HAMMER:
- return tripHammer;
- case GRINDSTONE:
- return grindstone;
- case POLISHING_WHEEL:
- return polishingWheel;
- }
- return null;
- }
+ private GameObject getStageObject(Stage stage)
+ {
+ switch (stage)
+ {
+ case TRIP_HAMMER:
+ return tripHammer;
+ case GRINDSTONE:
+ return grindstone;
+ case POLISHING_WHEEL:
+ return polishingWheel;
+ }
+ return null;
+ }
- @Override
- public Dimension render(Graphics2D graphics)
- {
- if (!state.isEnabled())
- {
- return null;
- }
+ @Override
+ public Dimension render(Graphics2D graphics)
+ {
+ if (!state.isEnabled())
+ {
+ return null;
+ }
- if (config.highlightKovac())
- {
- drawKovacIfHandIn(graphics);
- }
+ if (config.highlightKovac())
+ {
+ drawKovacIfHandIn(graphics);
+ }
- if (state.getCurrentStage() == null)
- {
- if (config.highlightMould())
- {
- drawMouldIfNotSet(graphics);
- }
- if (config.highlightCrucible())
- {
- drawCrucibleIfMouldSet(graphics);
- }
- return null;
- }
+ if (state.getCurrentStage() == null)
+ {
+ if (config.highlightMould())
+ {
+ drawMouldIfNotSet(graphics);
+ }
+ if (config.highlightCrucible())
+ {
+ drawCrucibleIfMouldSet(graphics);
+ }
+ return null;
+ }
- Stage stage = state.getCurrentStage();
- GameObject stageObject = getStageObject(stage);
- if (stageObject == null)
- {
- return null;
- }
+ Stage stage = state.getCurrentStage();
+ GameObject stageObject = getStageObject(stage);
+ if (stageObject == null)
+ {
+ return null;
+ }
- Heat heat = state.getCurrentHeat();
- Color color = getObjectColor(stage, heat);
- Shape objectClickbox = stageObject.getClickbox();
- if (objectClickbox != null && config.highlightTools())
- {
- Point mousePosition = client.getMouseCanvasPosition();
- if (objectClickbox.contains(mousePosition.getX(), mousePosition.getY()))
- {
- graphics.setColor(color.darker());
- }
- else
- {
- graphics.setColor(color);
- }
- graphics.draw(objectClickbox);
- graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20));
- graphics.fill(objectClickbox);
- }
+ drawHeatingActionOverlay(graphics, stageObject);
- if (stage.getHeat() != heat && config.highlightWaterAndLava())
- {
- drawHeatChangers(graphics);
- }
+ Heat heat = state.getCurrentHeat();
+ Color color = getObjectColor(stage, heat);
+ // TODO Config
+ if (config.highlightStyle() == HighlightStyle.HIGHLIGHT_CLICKBOX)
+ {
+ drawObjectClickbox(graphics, stageObject, color);
+ }
+ else
+ {
+ drawObjectOutline(graphics, stageObject, color);
+ }
- return null;
- }
+ if ((stage.getHeat() != heat || !state.heatingCoolingState.isIdle()) && config.highlightWaterAndLava())
+ {
+ drawHeatChangers(graphics);
+ }
- private void drawHeatChangers(Graphics2D graphics)
- {
- int change = state.getHeatChangeNeeded();
- Shape shape = null;
- if (change < 0)
- {
- shape = waterfall.getClickbox();
- } else if (change > 0)
- {
- shape = lavaPool.getClickbox();
- }
- if (shape != null)
- {
- Point mousePosition = client.getMouseCanvasPosition();
- Color color = config.lavaWaterfallColour();
- if (shape.contains(mousePosition.getX(), mousePosition.getY()))
- {
- graphics.setColor(color.darker());
- }
- else
- {
- graphics.setColor(color);
- }
- graphics.draw(shape);
- graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20));
- graphics.fill(shape);
- }
- }
+ if (state.heatingCoolingState.isCooling())
+ {
+ drawHeatingActionOverlay(graphics, waterfall, false);
+ }
+ if (state.heatingCoolingState.isHeating())
+ {
+ drawHeatingActionOverlay(graphics, lavaPool, true);
+ }
- private void drawCrucibleIfMouldSet(Graphics2D graphics)
- {
- if (client.getVarbitValue(MouldHelper.SWORD_TYPE_1_VARBIT) == 0)
- {
- return;
- }
- if (client.getVarbitValue(EasyGiantsFoundryState.VARBIT_GAME_STAGE) != 1)
- {
- return;
- }
- Shape shape = crucible.getConvexHull();
- if (shape != null)
- {
- Color color = config.generalHighlight();
- graphics.setColor(color);
- graphics.draw(shape);
- graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20));
- graphics.fill(shape);
- }
- }
- private void drawMouldIfNotSet(Graphics2D graphics)
- {
- if (client.getWidget(EasyGiantsFoundryState.WIDGET_PROGRESS_PARENT) != null
- || client.getVarbitValue(MouldHelper.SWORD_TYPE_1_VARBIT) == 0
- || (client.getVarbitValue(EasyGiantsFoundryState.VARBIT_GAME_STAGE) != 0
- && client.getVarbitValue(EasyGiantsFoundryState.VARBIT_GAME_STAGE) != 2))
- {
- return;
- }
- Shape shape = mouldJig.getConvexHull();
- if (shape != null)
- {
- Color color = config.generalHighlight();
- graphics.setColor(color);
- graphics.draw(shape);
- graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20));
- graphics.fill(shape);
- }
- }
+ return null;
+ }
- private void drawKovacIfHandIn(Graphics2D graphics)
- {
- Widget handInWidget = client.getWidget(HAND_IN_WIDGET);
- if (handInWidget != null && !handInWidget.isHidden())
- {
- Shape shape = kovac.getConvexHull();
- if (shape != null)
- {
- Color color = config.generalHighlight();
- graphics.setColor(color);
- graphics.draw(shape);
- graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20));
- graphics.fill(shape);
- }
- }
- }
+ private void drawObjectClickbox(Graphics2D graphics, GameObject stageObject, Color color)
+ {
+ Shape objectClickbox = stageObject.getClickbox();
+ if (objectClickbox != null && config.highlightTools())
+ {
+ Point mousePosition = client.getMouseCanvasPosition();
+ if (objectClickbox.contains(mousePosition.getX(), mousePosition.getY()))
+ {
+ graphics.setColor(color.darker());
+ }
+ else
+ {
+ graphics.setColor(color);
+ }
+ graphics.draw(objectClickbox);
+ graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20));
+ graphics.fill(objectClickbox);
+ }
+ }
+
+ private void drawObjectOutline(Graphics2D graphics, GameObject stageObject, Color color)
+ {
+ Color _color = new Color(color.getRed(), color.getGreen(), color.getBlue(), config.borderAlpha());
+ modelOutlineRenderer.drawOutline(stageObject, config.borderThickness(), _color, config.borderFeather());
+ }
+
+ private void drawHeatingActionOverlay(
+ Graphics2D graphics,
+ GameObject stageObject,
+ boolean isLava /* and not cooling */)
+ {
+ if (!config.drawLavaWaterInfoOverlay())
+ {
+ return;
+ }
+
+ if (state.heatingCoolingState.isIdle())
+ {
+ return;
+ }
+
+ String text;
+ if (isLava)
+ {
+ // %d heats or %d dunks
+ text = String.format("%d %s",
+ state.heatingCoolingState.getRemainingDuration(),
+ state.heatingCoolingState.getActionName()
+ );
+ }
+ else
+ {
+ // %d cools
+ text = String.format("%d %s",
+ state.heatingCoolingState.getRemainingDuration(),
+ state.heatingCoolingState.getActionName()
+ );
+ }
+
+ LocalPoint stageLoc = stageObject.getLocalLocation();
+ stageLoc = new LocalPoint(stageLoc.getX(), stageLoc.getY());
+
+ Point pos = Perspective.getCanvasTextLocation(client, graphics, stageLoc, text, 50);
+ Color color = config.lavaWaterfallColour();
+
+ OverlayUtil.renderTextLocation(graphics, pos, text, color);
+ }
+
+ private void drawHeatChangers(Graphics2D graphics)
+ {
+ int change = state.getHeatChangeNeeded();
+ Shape shape = null;
+
+ if (change < 0 || state.heatingCoolingState.isCooling())
+ {
+ shape = waterfall.getClickbox();
+ }
+ else if (change > 0 || state.heatingCoolingState.isHeating())
+ {
+ shape = lavaPool.getClickbox();
+ }
+ if (shape != null)
+ {
+ Point mousePosition = client.getMouseCanvasPosition();
+ Color color = config.lavaWaterfallColour();
+ if (shape.contains(mousePosition.getX(), mousePosition.getY()))
+ {
+ graphics.setColor(color.darker());
+ }
+ else
+ {
+ graphics.setColor(color);
+ }
+ graphics.draw(shape);
+ graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20));
+ graphics.fill(shape);
+ }
+ }
+
+ static final int CRUCIBLE_CAPACITY = 28;
+
+ private void drawCrucibleContent(Graphics2D graphics)
+ {
+ if (!config.drawCrucibleInfoOverlay())
+ {
+ return;
+ }
+ String text = String.format("%d/%d quality: %d", state.getCrucibleCount(), CRUCIBLE_CAPACITY, (int)state.getCrucibleQuality());
+
+ LocalPoint crucibleLoc = crucible.getLocalLocation();
+ crucibleLoc = new LocalPoint(crucibleLoc.getX() - 100, crucibleLoc.getY());
+
+ Point pos = Perspective.getCanvasTextLocation(client, graphics, crucibleLoc, text, 200);
+ Color color;
+ if (state.getCrucibleCount() == CRUCIBLE_CAPACITY)
+ {
+ color = config.toolGood();
+ }
+ else
+ {
+ color = config.generalHighlight();
+ }
+ OverlayUtil.renderTextLocation(graphics, pos, text, color);
+ }
+
+
+ private void drawCrucibleIfMouldSet(Graphics2D graphics)
+ {
+ if (client.getVarbitValue(SWORD_TYPE_1_VARBIT) == 0)
+ {
+ return;
+ }
+ if (client.getVarbitValue(VARBIT_GAME_STAGE) != 1)
+ {
+ return;
+ }
+
+ drawCrucibleContent(graphics);
+
+ if (config.highlightStyle() == HighlightStyle.HIGHLIGHT_CLICKBOX)
+ {
+ Shape shape = crucible.getConvexHull();
+ if (shape != null)
+ {
+ Color color = config.generalHighlight();
+ if (state.getCrucibleCount() == CRUCIBLE_CAPACITY)
+ {
+ graphics.setColor(config.toolGood());
+ }
+ else
+ {
+ graphics.setColor(config.generalHighlight());
+ }
+ graphics.draw(shape);
+ graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20));
+ graphics.fill(shape);
+ }
+ }
+ else if (config.highlightStyle() == HighlightStyle.HIGHLIGHT_BORDER)
+ {
+ Color color;
+ if (state.getCrucibleCount() == CRUCIBLE_CAPACITY)
+ {
+ color = config.toolGood();
+ }
+ else
+ {
+ color = config.generalHighlight();
+ }
+ drawObjectOutline(graphics, crucible, color);
+ }
+ }
+
+ private void drawMouldIfNotSet(Graphics2D graphics)
+ {
+ if (client.getWidget(WIDGET_PROGRESS_PARENT) != null
+ || client.getVarbitValue(SWORD_TYPE_1_VARBIT) == 0
+ || (client.getVarbitValue(VARBIT_GAME_STAGE) != 0
+ && client.getVarbitValue(VARBIT_GAME_STAGE) != 2))
+ {
+ return;
+ }
+ if (config.highlightStyle() == HighlightStyle.HIGHLIGHT_CLICKBOX)
+ {
+ Shape shape = mouldJig.getConvexHull();
+ if (shape != null)
+ {
+ Color color = config.generalHighlight();
+ graphics.setColor(color);
+ graphics.draw(shape);
+ graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20));
+ graphics.fill(shape);
+ }
+ }
+ else if (config.highlightStyle() == HighlightStyle.HIGHLIGHT_BORDER)
+ {
+ drawObjectOutline(graphics, mouldJig, config.generalHighlight());
+ }
+
+ if (config.drawMouldInfoOverlay())
+ {
+ CommissionType type1 = CommissionType.forVarbit(client.getVarbitValue(SWORD_TYPE_1_VARBIT));
+ CommissionType type2 = CommissionType.forVarbit(client.getVarbitValue(SWORD_TYPE_2_VARBIT));
+ String text = StringUtils.capitalize(type1.toString().toLowerCase()) + " " + StringUtils.capitalize(type2.toString().toLowerCase());
+ LocalPoint textLocation = mouldJig.getLocalLocation();
+ textLocation = new LocalPoint(textLocation.getX(), textLocation.getY());
+ Point canvasLocation = Perspective.getCanvasTextLocation(client, graphics, textLocation, text, 100);
+ canvasLocation = new Point(canvasLocation.getX(), canvasLocation.getY() + 10);
+ OverlayUtil.renderTextLocation(graphics, canvasLocation, text, config.generalHighlight());
+ }
+ }
+
+ private void drawKovacIfHandIn(Graphics2D graphics)
+ {
+ Widget handInWidget = client.getWidget(HAND_IN_WIDGET);
+ if (handInWidget != null && !handInWidget.isHidden())
+ {
+ Shape shape = kovac.getConvexHull();
+ if (shape != null)
+ {
+ Color color = config.generalHighlight();
+ graphics.setColor(color);
+ graphics.draw(shape);
+ graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20));
+ graphics.fill(shape);
+ }
+ }
+ }
+
+ private void drawHeatingActionOverlay(Graphics2D graphics, GameObject gameObject)
+ {
+ int actionsLeft = state.getActionsLeftInStage();
+ int heatLeft = state.getActionsForHeatLevel();
+
+ // Draw heat left
+ if (config.drawHeatLeftOverlay())
+ {
+ String text = "Heat left: " + heatLeft;
+ LocalPoint textLocation = gameObject.getLocalLocation();
+ textLocation = new LocalPoint(textLocation.getX(), textLocation.getY());
+ Point canvasLocation = Perspective.getCanvasTextLocation(client, graphics, textLocation, text, 250);
+ OverlayUtil.renderTextLocation(graphics, canvasLocation, text, getHeatColor(actionsLeft, heatLeft));
+ }
+ if (config.drawActionLeftOverlay())
+ // Draw actions left
+ {
+ String text = "Actions left: " + actionsLeft;
+ LocalPoint textLocation = gameObject.getLocalLocation();
+ textLocation = new LocalPoint(textLocation.getX(), textLocation.getY());
+ Point canvasLocation = Perspective.getCanvasTextLocation(client, graphics, textLocation, text, 250);
+ canvasLocation = new Point(canvasLocation.getX(), canvasLocation.getY() + 10);
+ OverlayUtil.renderTextLocation(graphics, canvasLocation, text, getHeatColor(actionsLeft, heatLeft));
+ }
+ }
}
diff --git a/src/main/java/com/toofifty/easygiantsfoundry/HeatActionSolver.java b/src/main/java/com/toofifty/easygiantsfoundry/HeatActionSolver.java
new file mode 100644
index 0000000..6c534e6
--- /dev/null
+++ b/src/main/java/com/toofifty/easygiantsfoundry/HeatActionSolver.java
@@ -0,0 +1,217 @@
+package com.toofifty.easygiantsfoundry;
+
+//import java.util.ArrayList;
+//import java.util.List;
+
+/**
+ * Solves the heating/cooling action and predicts tick duration (index)
+ * the naming convention is focused on the algorithm rather than in-game terminology for the context.
+ * + * the dx_n refers to successive derivatives of an ordinary-differential-equations + * https://en.wikipedia.org/wiki/Ordinary_differential_equation + * also known as distance (dx0), speed (dx1), and acceleration (dx2). + *
+ * dx0 - players current heat at tick + * dx1 - dx0_current - dx0_last_tick, aka the first derivative + * dx2 - dx1_current - dx1_last_tick, aka the second derivative + *
+ * for context, here's what dx1 extracted directly from in-game dunking looks like.
+ * the purpose of the HeatActionSolver.java is to accurately model this data.
+ * int[] dx1 = {
+ * 27,
+ * 30,
+ * 33,
+ * 37,
+ * 41,
+ * 45,
+ * 49,
+ * 53,
+ * 57,
+ * 62,
+ * 67,
+ * 72,
+ * 77,
+ * 83,
+ * 89,
+ * 95,
+ * 91,
+ * };
+ */
+
+/* The following code-snippet can be copy-pasted into runelite developer-tools "Shell" to extract dx1
+
+import java.awt.Toolkit;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Clipboard;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+int HEAT_ID = 13948;
+
+AtomicInteger tickCounter = new AtomicInteger(-1);
+AtomicInteger prevHeat = new AtomicInteger(client.getVarbitValue(HEAT_ID));
+
+
+Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+
+String output = "";
+
+subscribe(VarbitChanged.class, ev ->
+{
+ if (ev.getVarbitId() == HEAT_ID)
+ {
+ int deltaHeat = ev.getValue() - prevHeat.getAndSet(ev.getValue());
+
+ if (deltaHeat == -1) return; // ignore passive drain
+
+ String str = "[" + tickCounter.incrementAndGet()
+ + "] deltaHeat: " + deltaHeat;
+ log.info(str);
+ output = output + deltaHeat + "\n";
+ StringSelection selection = new StringSelection(output);
+ clipboard.setContents(selection, selection);
+ }
+});
+*/
+
+public class HeatActionSolver
+{
+
+ /**
+ * @param goal the desired heat destination
+ * @param init_dx1 initial speed of heating/cooling. currently 7 for heat/cool, 27 for dunk/quench.
+ * @param dx2_offset bonus acceleration. currently, 0 for heat/cool, 2 for dunk/quench.
+ * @return Index here refers to tick. So an index of 10 means the goal can be reached in 10 ticks.
+ */
+ public static int findDx0Index(int goal, int init_dx1, int dx2_offset)
+ {
+ int dx0 = 0;
+ int dx1 = init_dx1;
+ int count_index = 0;
+ for (int dx2 = 1; dx0 <= goal; dx2++)
+ { // Start from 1 up to the count inclusive
+ int repetitions;
+ if (dx2 == 1)
+ {
+ repetitions = 2; // The first number appears twice
+ }
+ else if (dx2 % 2 == 0)
+ {
+ repetitions = 6; // Even numbers appear six times
+ }
+ else
+ {
+ repetitions = 4; // Odd numbers (after 1) appear four times
+ }
+ for (int j = 0; j < repetitions && dx0 <= goal; j++)
+ {
+ dx0 += dx1;
+ dx1 += dx2 + dx2_offset; // Sum the current number 'repetitions' times
+ count_index += 1;
+ }
+ }
+ return count_index;
+ }
+
+
+ /**
+ * We can use the pattern to get the dx2 at a specific index numerically
+ *
+ * @param index the index/tick we want to calculate dx2 at
+ * @return the acceleration of heating/cooling at index/tick
+ */
+ public static int getDx2AtIndex(int index)
+ {
+ if (index <= 1) return 1;
+
+ index -= 2;
+ // 0 1 2 3 4 5 6 7 8 9
+ // e,e,e,e,e,e,o,o,o,o
+
+ int block = index / 10;
+ int block_idx = index % 10;
+ int number = block * 2;
+ if (block_idx <= 5)
+ {
+ return number + 2;
+ }
+ else
+ {
+ return number + 3;
+ }
+ }
+
+
+ /**
+ * We can use the pattern to get the dx1 at a specific index numerically
+ *
+ * @param index the index/tick we want to calculate the speed of heating/cooling
+ * @param constant the initial speed of heating/cooling.
+ * @return the speed of heating at index/tick
+ */
+ public static int getDx1AtIndex(int index, int constant)
+ {
+ int _dx1 = constant;
+ for (int i = 0; i < index; ++i)
+ {
+ _dx1 += getDx2AtIndex(i);
+ }
+
+ return _dx1;
+ }
+
+// Methods below are functional, but only used to for debugging & development
+
+// public static int getDx0AtIndex(int index, int constant)
+// {
+// int dx0 = 0;
+// int dx1 = getDx1AtIndex(0, constant);
+// for (int i = 0; i < index; i++)
+// { // Start from 1 up to the count inclusive
+// int dx2 = getDx2AtIndex(i);
+// dx1 += dx2; // Sum the current number 'repetitions' times
+// dx0 += dx1;
+// }
+// return dx0;
+// }
+
+ // We iteratively generate dx2 into a list
+// public static List
+ * These parameters have to be set-up manually before start().
+ * Velocity, AccelerationBonus, ActionName
+ *
+ * @param state the current state of the foundry
+ * @param config the current configuration of the plugin
+ * @param startingHeat the starting heat amount
+ * @see HeatActionStateMachine#setup(int, int, String)
+ */
+ public void start(EasyGiantsFoundryState state, EasyGiantsFoundryConfig config, int startingHeat)
+ {
+ // use Velocity to determine if heating or cooling
+ if (Velocity > 0)
+ {
+ HeatingTicks = 0;
+ CoolingTicks = -1;
+ }
+ else
+ {
+ CoolingTicks = 0;
+ HeatingTicks = -1;
+ }
+ StartingHeat = startingHeat - Velocity;
+ State = state;
+ Config = config;
+
+ calculateEstimates();
+ }
+
+ /**
+ * Get the estimated remaining duration of the heating/cooling action.
+ *
+ * @return the estimated remaining duration in ticks
+ */
+ public int getRemainingDuration()
+ {
+ if (isHeating())
+ {
+ return Math.max(0, EstimatedDuration - HeatingTicks);
+ }
+ else if (isCooling())
+ {
+ return Math.max(0, EstimatedDuration - CoolingTicks);
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ /**
+ * Core logic. Runs once on {@link HeatActionStateMachine#start} and assumes synchronization with the game.
+ * Calculate the estimated duration and goal heat amount of the heating/cooling action.
+ */
+ public void calculateEstimates()
+ {
+ int[] range = State.getCurrentHeatRange();
+ Stage stage = State.getCurrentStage();
+ int actionsLeft = State.getActionsLeftInStage();
+ int actionsLeft_DeltaHeat = actionsLeft * stage.getHeatChange();
+ if (isHeating())
+ {
+ if (stage.isHeating())
+ {
+ GoalHeat = Math.max(range[0] + Config.heatingCoolingBuffer(), range[1] - actionsLeft_DeltaHeat);
+ if (StartingHeat < GoalHeat)
+ {
+ EstimatedDuration = HeatActionSolver.findDx0Index(
+ GoalHeat - StartingHeat,
+ Velocity, AccelerationBonus);
+
+ GoalHeat += EstimatedDuration / 2; // compensate for decay during heating
+
+ EstimatedDuration = HeatActionSolver.findDx0Index(
+ GoalHeat - StartingHeat,
+ Velocity, AccelerationBonus);
+ }
+ else // overheating
+ {
+ EstimatedDuration = 0;
+ }
+ }
+ else // is cooling
+ {
+ GoalHeat = Math.min(range[1] - Config.heatingCoolingBuffer(), range[0] - actionsLeft_DeltaHeat);
+ if (StartingHeat < GoalHeat)
+ {
+ EstimatedDuration = HeatActionSolver.findDx0Index(
+ GoalHeat - StartingHeat,
+ Velocity, AccelerationBonus
+ );
+ }
+ else // cold enough
+ {
+ EstimatedDuration = 0;
+ }
+ }
+ }
+ else if (isCooling())
+ {
+ if (stage.isCooling())
+ {
+ GoalHeat = Math.max(range[1] - Config.heatingCoolingBuffer(), range[0] + actionsLeft_DeltaHeat);
+ if (StartingHeat > GoalHeat) // too hot
+ {
+ EstimatedDuration = HeatActionSolver.findDx0Index(
+ StartingHeat - GoalHeat,
+ Math.abs(Velocity), Math.abs(AccelerationBonus)
+ );
+ }
+ else // hot enough
+ {
+ EstimatedDuration = 0;
+ }
+ }
+ else // Heating Stage
+ {
+ GoalHeat = Math.max(range[0] + Config.heatingCoolingBuffer(), range[1] - actionsLeft_DeltaHeat);
+ if (StartingHeat > GoalHeat)
+ {
+ EstimatedDuration = HeatActionSolver.findDx0Index(
+ (StartingHeat - GoalHeat),
+ Math.abs(Velocity), Math.abs(AccelerationBonus)
+ );
+ }
+ else
+ {
+ EstimatedDuration = 0;
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper to remind the neccessary parameters to start the state-machine.
+ *
+ * @param velocity the velocity of the heating/cooling action, 7 for slow, 27 for fast.
+ * @param accelerationBonus the acceleration bonus of the heating/cooling action. Usually 0 for slow, 2 for fast.
+ * @param actionName the name of the action to display in the ui overlay
+ */
+ public void setup(int velocity, int accelerationBonus, String actionName)
+ {
+ Velocity = velocity;
+ AccelerationBonus = accelerationBonus;
+ ActionName = actionName;
+ }
+
+ /**
+ * Stop the state-machine.
+ */
+ public void stop()
+ {
+ HeatingTicks = -1;
+ CoolingTicks = -1;
+ ActionName = null;
+ }
+
+ /**
+ * Check if the state is currently heating.
+ *
+ * @return true if heating, false otherwise
+ */
+ public boolean isHeating()
+ {
+ return HeatingTicks >= 0;
+ }
+
+ /**
+ * Check if the state is currently cooling.
+ *
+ * @return true if cooling, false otherwise
+ */
+ public boolean isCooling()
+ {
+ return CoolingTicks >= 0;
+ }
+
+ /**
+ * Check if the heating/cooling state is currently idle. Neither heating nor cooling.
+ *
+ * @return
+ */
+ public boolean isIdle()
+ {
+ return !(isHeating() || isCooling());
+ }
+
+ /**
+ * Tick the state-machine. This has to be called onVarbitChanged in order to sync with the game.
+ */
+ public void onTick()
+ {
+ if (isHeating())
+ {
+ HeatingTicks++;
+ if (HeatingTicks >= EstimatedDuration)
+ {
+ stop();
+ }
+ }
+ if (isCooling())
+ {
+ CoolingTicks++;
+ if (CoolingTicks >= EstimatedDuration)
+ {
+ stop();
+ }
+ }
+// log.info("\nReal Heat: " + State.getHeatAmount()
+// + "\nGoal Heat - StartingHeat: " + (GoalHeat - StartingHeat)
+// + "\nDuration: " + EstimatedDuration);
+ }
+
+}
diff --git a/src/main/java/com/toofifty/easygiantsfoundry/HighlightStyle.java b/src/main/java/com/toofifty/easygiantsfoundry/HighlightStyle.java
new file mode 100644
index 0000000..e1eaedd
--- /dev/null
+++ b/src/main/java/com/toofifty/easygiantsfoundry/HighlightStyle.java
@@ -0,0 +1,7 @@
+package com.toofifty.easygiantsfoundry;
+
+public enum HighlightStyle
+{
+ HIGHLIGHT_BORDER,
+ HIGHLIGHT_CLICKBOX
+}
diff --git a/src/main/java/com/toofifty/easygiantsfoundry/MathUtil.java b/src/main/java/com/toofifty/easygiantsfoundry/MathUtil.java
new file mode 100644
index 0000000..e5dbb4c
--- /dev/null
+++ b/src/main/java/com/toofifty/easygiantsfoundry/MathUtil.java
@@ -0,0 +1,9 @@
+package com.toofifty.easygiantsfoundry;
+
+public class MathUtil
+{
+ public static double max1(double a)
+ {
+ return a > 0 ? a : 1;
+ }
+}
diff --git a/src/main/java/com/toofifty/easygiantsfoundry/MouldHelper.java b/src/main/java/com/toofifty/easygiantsfoundry/MouldHelper.java
index 0c0a561..a6b8b9e 100644
--- a/src/main/java/com/toofifty/easygiantsfoundry/MouldHelper.java
+++ b/src/main/java/com/toofifty/easygiantsfoundry/MouldHelper.java
@@ -2,9 +2,11 @@ package com.toofifty.easygiantsfoundry;
import com.toofifty.easygiantsfoundry.enums.CommissionType;
import com.toofifty.easygiantsfoundry.enums.Mould;
+
import java.util.LinkedHashMap;
import java.util.Map;
import javax.inject.Inject;
+
import net.runelite.api.Client;
import net.runelite.api.ScriptID;
import net.runelite.api.widgets.Widget;
@@ -12,83 +14,89 @@ import net.runelite.client.callback.ClientThread;
public class MouldHelper
{
- static final int MOULD_LIST_PARENT = 47054857;
- static final int DRAW_MOULD_LIST_SCRIPT = 6093;
- static final int REDRAW_MOULD_LIST_SCRIPT = 6095;
- static final int RESET_MOULD_SCRIPT = 6108;
- public static final int SELECT_MOULD_SCRIPT = 6098;
- static final int SWORD_TYPE_1_VARBIT = 13907; // 4=Broad
- static final int SWORD_TYPE_2_VARBIT = 13908; // 3=Flat
- private static final int DISABLED_TEXT_COLOR = 0x9f9f9f;
- private static final int GREEN = 0xdc10d;
+ static final int MOULD_LIST_PARENT = 47054857;
+ static final int DRAW_MOULD_LIST_SCRIPT = 6093;
+ static final int REDRAW_MOULD_LIST_SCRIPT = 6095;
+ static final int RESET_MOULD_SCRIPT = 6108;
+ public static final int SELECT_MOULD_SCRIPT = 6098;
+ static final int SWORD_TYPE_1_VARBIT = 13907; // 4=Broad
+ static final int SWORD_TYPE_2_VARBIT = 13908; // 3=Flat
+ private static final int DISABLED_TEXT_COLOR = 0x9f9f9f;
- @Inject
- private Client client;
+ @Inject
+ private Client client;
- @Inject
- private ClientThread clientThread;
+ @Inject
+ private ClientThread clientThread;
@Inject
private EasyGiantsFoundryConfig config;
- public void selectBest(int scriptId)
- {
- Widget parent = client.getWidget(MOULD_LIST_PARENT);
- if (parent == null || parent.getChildren() == null)
- {
- return;
- }
+ public void selectBest(int scriptId)
+ {
+ Widget parent = client.getWidget(MOULD_LIST_PARENT);
+ if (parent == null || parent.getChildren() == null)
+ {
+ return;
+ }
- Map