Crucible Overlay, Tools action overlay, Lava/waterfall prediction
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
61
README.md
@@ -1,20 +1,44 @@
|
||||
# Easy Giant's Foundry
|
||||
<p align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: light)" srcset="./banner_black.png">
|
||||
<img width=60% src="./banner_white.png">
|
||||
</picture>
|
||||
</p>
|
||||
|
||||
Helpful overlays for the Giant's Foundry minigame
|
||||
---
|
||||
The "Easy Giants' Foundry" plugin is designed to optimize your performance in the Giants' Foundry.
|
||||
|
||||
## Features
|
||||
# Features Overview
|
||||
- **Interactive Elements and NPCs**
|
||||
- Highlights **Kovac, Crucible, and Mould Jig** when relevant, drawing your attention to key NPCs and equipment.
|
||||
- Alerts you when the **waterfall/lava pool** can be used to correct temperature discrepancies.
|
||||
- Uses **customizable status colors** to highlight relevant tools, helping you maintain the right temperature:
|
||||
* **Red:** Wrong temperature
|
||||
* **Green:** Right temperature
|
||||
* **Orange:** One action or temperature change remaining
|
||||
* **Cyan:** Click tool again for bonus progress
|
||||
- **Alloy Quality and Crucible Content**
|
||||
- Overlays **current crucible contents** and the **quality of the alloy** being forged.
|
||||
- **Best Mould Guidance**
|
||||
- Highlights the **best moulds to use** for your current task, guiding your selection process.
|
||||
- **Progress and Actions Tracking**
|
||||
- Displays the **number of lava/waterfall actions** needed to complete the current stage.
|
||||
- Shows the **number of actions required** to complete the next stage.
|
||||
- Indicates the **number of actions** before gaining or losing too much heat.
|
||||
- Tracks **heat and progress** as percentages.
|
||||
|
||||
- Shows heat and progress as percentages
|
||||
- Shows number of actions required to move to the next stage
|
||||
- Shows number of actions before gaining/losing too much heat
|
||||
- Shows best moulds to use
|
||||
- Highlights relevant tool with customizable status colors
|
||||
* Red = Wrong temperature
|
||||
* Green = Right temperature
|
||||
* Orange = one action or temperature change remaining
|
||||
* Cyan = Click tool again for bonus progress
|
||||
- Highlights Kovac, Crucible, and Mould Jig when relevant
|
||||
- Highlights waterfall/lava pool when temperature is wrong
|
||||
# Pictures
|
||||
Best Mould | Crucible Alloy Quality
|
||||
:-------------------------:|:-------------------------:
|
||||
<img width=350px src="./readme_gifs/best-mould.webp">|<img width=350px src="./readme_gifs/crucible-value.png">
|
||||
|
||||
Heating/Cooling Prediction | Low/High Heat Warning
|
||||
:-------------------------:|:-------------------------:
|
||||
<img width=350px src="./readme_gifs/lava-waterfall-estimate.webp">|<img width=350px src="./readme_gifs/tool-damage-warning.webp">
|
||||
|
||||
Bonus Click Notification | Information Panel
|
||||
:-------------------------:|:-------------------------:
|
||||
<img width=350px src="./readme_gifs/tools-bonus-notification.webp">|<img width=350px src="./readme_gifs/info-panel.webp">
|
||||
|
||||
## 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
|
||||
* 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
|
||||
|
||||
|
||||
|
||||
BIN
banner_black.png
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
banner_white.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
readme_gifs/best-mould.webp
Normal file
|
After Width: | Height: | Size: 3.6 MiB |
5
readme_gifs/convert_gif2webp.bat
Normal file
@@ -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"
|
||||
|
||||
BIN
readme_gifs/crucible-value.png
Normal file
|
After Width: | Height: | Size: 265 KiB |
BIN
readme_gifs/info-panel.webp
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
readme_gifs/lava-waterfall-estimate.webp
Normal file
|
After Width: | Height: | Size: 6.4 MiB |
BIN
readme_gifs/tool-damage-warning.webp
Normal file
|
After Width: | Height: | Size: 733 KiB |
BIN
readme_gifs/tools-bonus-notification.webp
Normal file
|
After Width: | Height: | Size: 710 KiB |
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 = "highlightAlpha",
|
||||
name = "Highlight Alpha",
|
||||
description = "The alpha of the 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 " + 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
|
||||
|
||||
@@ -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;
|
||||
@@ -59,6 +38,11 @@ public class EasyGiantsFoundryState
|
||||
heatRangeRatio = 0;
|
||||
}
|
||||
|
||||
public int getBarCount()
|
||||
{
|
||||
return client.getVarbitValue(VARBIT_STEEL_COUNT);
|
||||
}
|
||||
|
||||
public int getHeatAmount()
|
||||
{
|
||||
return client.getVarbitValue(VARBIT_HEAT);
|
||||
@@ -80,7 +64,7 @@ public class EasyGiantsFoundryState
|
||||
return 0;
|
||||
}
|
||||
|
||||
heatRangeRatio = medHeat.getWidth() /(double) heatWidget.getWidth();
|
||||
heatRangeRatio = medHeat.getWidth() / (double) heatWidget.getWidth();
|
||||
}
|
||||
|
||||
return heatRangeRatio;
|
||||
@@ -125,13 +109,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 +188,149 @@ public class EasyGiantsFoundryState
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// boolean valid = false;
|
||||
//
|
||||
// int bronze = 0;
|
||||
// int iron = 0;
|
||||
// int steel = 0;
|
||||
// int mithril = 0;
|
||||
// int adamant = 0;
|
||||
// int rune = 0;
|
||||
// // Currently 28, will prob always be 28, but I want to future-proof this
|
||||
// int capacity = 28;
|
||||
//
|
||||
// public boolean parseCrucibleText(String text)
|
||||
// {
|
||||
// if (!text.startsWith("The crucible currently contains"))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// String[] parts = text.split("<br>");
|
||||
// capacity = Integer.parseInt(parts[0].split(" / ")[1].split(" ")[0]);
|
||||
//
|
||||
// String[] counts = (parts[1] + parts[2]).split(", ");
|
||||
// bronze = Integer.parseInt(counts[0].split(" x ")[0]);
|
||||
// iron = Integer.parseInt(counts[1].split(" x ")[0]);
|
||||
// steel = Integer.parseInt(counts[2].split(" x ")[0]);
|
||||
// mithril = Integer.parseInt(counts[3].split(" x ")[0]);
|
||||
// adamant = Integer.parseInt(counts[4].split(" x ")[0]);
|
||||
// rune = Integer.parseInt(counts[5].split(" x ")[0]);
|
||||
//
|
||||
// valid = true;
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// public String toString()
|
||||
// {
|
||||
// return String.format("[Capacity %d/%d. Total Value %d] Bronze: %d, Iron: %d, Steel: %d, Mithril: %d, Adamant: %d, Rune: %d.",
|
||||
// bronze, iron, steel, mithril, adamant, rune, count(), capacity, value());
|
||||
// }
|
||||
|
||||
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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: %.1f", state.getCrucibleCount(), CRUCIBLE_CAPACITY, 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
* <p>
|
||||
* 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).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* 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<Integer> generateDx2List(int count)
|
||||
// {
|
||||
// List<Integer> pattern = new ArrayList<>(); // This will hold our pattern
|
||||
// for (int n = 1, i = 0; i < count; n++)
|
||||
// { // Start from 1 up to the count inclusive
|
||||
// int repetitions;
|
||||
// if (n == 1)
|
||||
// {
|
||||
// repetitions = 2; // The first number appears twice
|
||||
// } else if (n % 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 && i < count; j++, i++)
|
||||
// {
|
||||
// pattern.add(n); // Append the current number 'repetitions' times
|
||||
// }
|
||||
// }
|
||||
// return pattern;
|
||||
// }
|
||||
|
||||
// public static int findDx0IndexContinue(int goal, int constant, int init_index)
|
||||
// {
|
||||
// int dx0 = getDx0AtIndex(init_index, constant);
|
||||
// int dx1 = getDx1AtIndex(init_index, constant);
|
||||
// int count_index = init_index;
|
||||
// for (; dx0 <= goal; count_index++)
|
||||
// { // Start from 1 up to the count inclusive
|
||||
// int dx2 = getDx2AtIndex(count_index);
|
||||
// dx1 += dx2; // Sum the current number 'repetitions' times
|
||||
// dx0 += dx1;
|
||||
// }
|
||||
// return count_index - init_index;
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
package com.toofifty.easygiantsfoundry;
|
||||
|
||||
import com.toofifty.easygiantsfoundry.enums.Stage;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* A state-machine that keeps track of heating/cooling actions.
|
||||
*/
|
||||
@Slf4j
|
||||
@Data
|
||||
public class HeatActionStateMachine
|
||||
{
|
||||
/**
|
||||
* Tick counter for heating, -1 means not currently heating.
|
||||
*/
|
||||
int HeatingTicks = -1;
|
||||
|
||||
/**
|
||||
* Tick counter for cooling, -1 means not currently cooling.
|
||||
*/
|
||||
int CoolingTicks = -1;
|
||||
|
||||
/**
|
||||
* The velocity of the heating/cooling action.
|
||||
*/
|
||||
int Velocity;
|
||||
|
||||
/**
|
||||
* The acceleration bonus of the heating/cooling action.
|
||||
*/
|
||||
int AccelerationBonus;
|
||||
|
||||
/**
|
||||
* The starting heat amount of the heating/cooling action.
|
||||
*/
|
||||
int StartingHeat;
|
||||
|
||||
/**
|
||||
* The estimated tick duration of the heating/cooling action.
|
||||
*/
|
||||
int EstimatedDuration;
|
||||
|
||||
/**
|
||||
* The goal heat amount of the heating/cooling action.
|
||||
*/
|
||||
int GoalHeat = 0;
|
||||
|
||||
/**
|
||||
* The last action the player clicked on. Used for ui overlay to display.
|
||||
* When null, the state-machine will stop() and reset.
|
||||
*/
|
||||
String ActionName = null;
|
||||
|
||||
private EasyGiantsFoundryState State;
|
||||
private EasyGiantsFoundryConfig Config;
|
||||
|
||||
/**
|
||||
* Start the state-machine with the given parameters.
|
||||
* <p>
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.toofifty.easygiantsfoundry;
|
||||
|
||||
public enum HighlightStyle
|
||||
{
|
||||
HIGHLIGHT_BORDER,
|
||||
HIGHLIGHT_CLICKBOX
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.toofifty.easygiantsfoundry;
|
||||
|
||||
public class MathUtil
|
||||
{
|
||||
public static double max1(double a)
|
||||
{
|
||||
return a > 0 ? a : 1;
|
||||
}
|
||||
}
|
||||
@@ -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<Mould, Widget> mouldToChild = getOptions(parent.getChildren());
|
||||
Map<Mould, Widget> mouldToChild = getOptions(parent.getChildren());
|
||||
|
||||
int bestScore = -1;
|
||||
Widget bestWidget = null;
|
||||
CommissionType type1 = CommissionType.forVarbit(client.getVarbitValue(SWORD_TYPE_1_VARBIT));
|
||||
CommissionType type2 = CommissionType.forVarbit(client.getVarbitValue(SWORD_TYPE_2_VARBIT));
|
||||
for (Map.Entry<Mould, Widget> entry : mouldToChild.entrySet()) {
|
||||
Mould mould = entry.getKey();
|
||||
int score = mould.getScore(type1, type2);
|
||||
if (score > bestScore) {
|
||||
bestScore = score;
|
||||
bestWidget = entry.getValue();
|
||||
}
|
||||
}
|
||||
if (bestWidget != null) {
|
||||
bestWidget.setTextColor(config.mouldTextColour().getRGB());
|
||||
}
|
||||
int bestScore = -1;
|
||||
Widget bestWidget = null;
|
||||
CommissionType type1 = CommissionType.forVarbit(client.getVarbitValue(SWORD_TYPE_1_VARBIT));
|
||||
CommissionType type2 = CommissionType.forVarbit(client.getVarbitValue(SWORD_TYPE_2_VARBIT));
|
||||
for (Map.Entry<Mould, Widget> entry : mouldToChild.entrySet())
|
||||
{
|
||||
Mould mould = entry.getKey();
|
||||
int score = mould.getScore(type1, type2);
|
||||
if (score > bestScore)
|
||||
{
|
||||
bestScore = score;
|
||||
bestWidget = entry.getValue();
|
||||
}
|
||||
}
|
||||
if (bestWidget != null)
|
||||
{
|
||||
bestWidget.setTextColor(config.mouldTextColour().getRGB());
|
||||
}
|
||||
|
||||
if (scriptId == DRAW_MOULD_LIST_SCRIPT || scriptId == REDRAW_MOULD_LIST_SCRIPT)
|
||||
{
|
||||
Widget scrollBar = client.getWidget(718, 11);
|
||||
Widget scrollList = client.getWidget(718, 9);
|
||||
if (scrollBar != null && scrollList != null)
|
||||
{
|
||||
int height = scrollList.getHeight();
|
||||
int scrollMax = scrollList.getScrollHeight();
|
||||
Widget finalBestWidget = bestWidget;
|
||||
clientThread.invokeLater(() -> {
|
||||
if (finalBestWidget != null) {
|
||||
client.runScript(
|
||||
ScriptID.UPDATE_SCROLLBAR,
|
||||
scrollBar.getId(),
|
||||
scrollList.getId(),
|
||||
Math.min(finalBestWidget.getOriginalY() - 2, scrollMax - height));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (scriptId == DRAW_MOULD_LIST_SCRIPT || scriptId == REDRAW_MOULD_LIST_SCRIPT)
|
||||
{
|
||||
Widget scrollBar = client.getWidget(718, 11);
|
||||
Widget scrollList = client.getWidget(718, 9);
|
||||
if (scrollBar != null && scrollList != null)
|
||||
{
|
||||
int height = scrollList.getHeight();
|
||||
int scrollMax = scrollList.getScrollHeight();
|
||||
Widget finalBestWidget = bestWidget;
|
||||
clientThread.invokeLater(() ->
|
||||
{
|
||||
if (finalBestWidget != null)
|
||||
{
|
||||
client.runScript(
|
||||
ScriptID.UPDATE_SCROLLBAR,
|
||||
scrollBar.getId(),
|
||||
scrollList.getId(),
|
||||
Math.min(finalBestWidget.getOriginalY() - 2, scrollMax - height));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Mould, Widget> getOptions(Widget[] children) {
|
||||
Map<Mould, Widget> mouldToChild = new LinkedHashMap<>();
|
||||
for (int i = 2; i < children.length; i += 17)
|
||||
{
|
||||
Widget child = children[i];
|
||||
Mould mould = Mould.forName(child.getText());
|
||||
if (mould != null && child.getTextColor() != DISABLED_TEXT_COLOR) {
|
||||
mouldToChild.put(mould, child);
|
||||
}
|
||||
}
|
||||
return mouldToChild;
|
||||
}
|
||||
private Map<Mould, Widget> getOptions(Widget[] children)
|
||||
{
|
||||
Map<Mould, Widget> mouldToChild = new LinkedHashMap<>();
|
||||
for (int i = 2; i < children.length; i += 17)
|
||||
{
|
||||
Widget child = children[i];
|
||||
Mould mould = Mould.forName(child.getText());
|
||||
if (mould != null && child.getTextColor() != DISABLED_TEXT_COLOR)
|
||||
{
|
||||
mouldToChild.put(mould, child);
|
||||
}
|
||||
}
|
||||
return mouldToChild;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
package com.toofifty.easygiantsfoundry.enums;
|
||||
|
||||
public enum CommissionType {
|
||||
NONE,
|
||||
NARROW, // 1
|
||||
LIGHT, // 2
|
||||
FLAT, // 3
|
||||
BROAD, // 4
|
||||
HEAVY, // 5
|
||||
SPIKED, // 6
|
||||
;
|
||||
public enum CommissionType
|
||||
{
|
||||
NONE,
|
||||
NARROW, // 1
|
||||
LIGHT, // 2
|
||||
FLAT, // 3
|
||||
BROAD, // 4
|
||||
HEAVY, // 5
|
||||
SPIKED, // 6
|
||||
;
|
||||
|
||||
public static final CommissionType[] values = CommissionType.values();
|
||||
public static final CommissionType[] values = CommissionType.values();
|
||||
|
||||
public static CommissionType forVarbit(int varbitValue) {
|
||||
if (varbitValue < 0 || varbitValue >= values.length) {
|
||||
return NONE;
|
||||
}
|
||||
return CommissionType.values[varbitValue];
|
||||
}
|
||||
public static CommissionType forVarbit(int varbitValue)
|
||||
{
|
||||
if (varbitValue < 0 || varbitValue >= values.length)
|
||||
{
|
||||
return NONE;
|
||||
}
|
||||
return CommissionType.values[varbitValue];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.toofifty.easygiantsfoundry.enums;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
|
||||
@@ -9,61 +9,66 @@ import static com.toofifty.easygiantsfoundry.enums.CommissionType.*;
|
||||
import static com.toofifty.easygiantsfoundry.enums.MouldType.*;
|
||||
|
||||
@AllArgsConstructor
|
||||
public enum Mould {
|
||||
CHOPPER_FORTE("Chopper Forte", FORTE, ImmutableMap.of(BROAD, 4, LIGHT, 4, FLAT, 4)),
|
||||
GALDIUS_RICASSO("Galdius Ricasso", FORTE, ImmutableMap.of(BROAD, 4, HEAVY, 4, FLAT, 4)),
|
||||
DISARMING_FORTE("Disarming Forte", FORTE, ImmutableMap.of(NARROW, 4, LIGHT, 4, SPIKED, 4)),
|
||||
MEDUSA_RICASSO("Medusa Ricasso", FORTE, ImmutableMap.of(BROAD, 8, HEAVY, 6, FLAT, 8)),
|
||||
SERPENT_RICASSO("Serpent Ricasso", FORTE, ImmutableMap.of(NARROW, 6, LIGHT, 8, FLAT, 8)),
|
||||
SERRATED_FORTE("Serrated Forte", FORTE, ImmutableMap.of(NARROW, 8, HEAVY, 8, SPIKED, 6)),
|
||||
STILETTO_FORTE("Stiletto Forte", FORTE, ImmutableMap.of(NARROW, 8, LIGHT, 10, FLAT, 8)),
|
||||
DEFENDER_BASE("Defender Base", FORTE, ImmutableMap.of(BROAD, 8, HEAVY, 10, FLAT, 8)),
|
||||
JUGGERNAUT_FORTE("Juggernaut Forte", FORTE, ImmutableMap.of(BROAD, 4, HEAVY, 4, SPIKED, 16)),
|
||||
CHOPPER_FORTE_1("Chopper Forte +1", FORTE, ImmutableMap.of(BROAD, 3, LIGHT, 4, FLAT, 18)),
|
||||
SPIKER("Spiker!", FORTE, ImmutableMap.of(NARROW, 1, HEAVY, 2, SPIKED, 22)),
|
||||
SAW_BLADE("Saw Blade", BLADE, ImmutableMap.of(BROAD, 4, LIGHT, 4, SPIKED, 4)),
|
||||
DEFENDERS_EDGE("Defenders Edge", BLADE, ImmutableMap.of(BROAD, 4, HEAVY, 4, SPIKED, 4)),
|
||||
FISH_BLADE("Fish Blade", BLADE, ImmutableMap.of(NARROW, 4, LIGHT, 4, FLAT, 4)),
|
||||
MEDUSA_BLADE("Medusa Blade", BLADE, ImmutableMap.of(BROAD, 8, HEAVY, 8, FLAT, 6)),
|
||||
STILETTO_BLADE("Stiletto Blade", BLADE, ImmutableMap.of(NARROW, 8, LIGHT, 6, FLAT, 8)),
|
||||
GLADIUS_EDGE("Gladius Edge", BLADE, ImmutableMap.of(NARROW, 6, HEAVY, 8, FLAT, 8)),
|
||||
FLAMBERGE_BLADE("Flamberge Blade", BLADE, ImmutableMap.of(NARROW, 8, LIGHT, 8, SPIKED, 10)),
|
||||
SERPENT_BLADE("Serpent Blade", BLADE, ImmutableMap.of(NARROW, 10, LIGHT, 8, FLAT, 8)),
|
||||
CLAYMORE_BLADE("Claymore Blade", BLADE, ImmutableMap.of(BROAD, 16, HEAVY, 4, FLAT, 4)),
|
||||
FLEUR_DE_BLADE("Fleur de Blade", BLADE, ImmutableMap.of(BROAD, 4, HEAVY, 18, SPIKED, 1)),
|
||||
CHOPPA("Choppa!", BLADE, ImmutableMap.of(BROAD, 1, LIGHT, 22, FLAT, 2)),
|
||||
PEOPLE_POKER_POINT("People Poker Point", TIP, ImmutableMap.of(NARROW, 4, HEAVY, 4, FLAT, 4)),
|
||||
CHOPPER_TIP("Chopper Tip", TIP, ImmutableMap.of(BROAD, 4, LIGHT, 4, SPIKED, 4)),
|
||||
MEDUSAS_HEAD("Medusa's Head", TIP, ImmutableMap.of(BROAD, 4, HEAVY, 4, SPIKED, 4)),
|
||||
SERPENTS_FANG("Serpent's Fang", TIP, ImmutableMap.of(NARROW, 8, LIGHT, 6, SPIKED, 8)),
|
||||
GLADIUS_POINT("Gladius Point", TIP, ImmutableMap.of(NARROW, 8, HEAVY, 8, FLAT, 6)),
|
||||
SAW_TIP("Saw Tip", TIP, ImmutableMap.of(BROAD, 6, HEAVY, 8, SPIKED, 8)),
|
||||
CORRUPTED_POINT("Corrupted Point", TIP, ImmutableMap.of(NARROW, 8, LIGHT, 10, SPIKED, 8)),
|
||||
DEFENDERS_TIP("Defenders Tip", TIP, ImmutableMap.of(BROAD, 10, HEAVY, 8, SPIKED, 8)),
|
||||
SERRATED_TIP("Serrated Tip", TIP, ImmutableMap.of(NARROW, 4, LIGHT, 16, SPIKED, 4)),
|
||||
NEEDLE_POINT("Needle Point", TIP, ImmutableMap.of(NARROW, 18, LIGHT, 3, FLAT, 4)),
|
||||
THE_POINT("The Point!", TIP, ImmutableMap.of(BROAD, 2, LIGHT, 1, FLAT, 22)),
|
||||
;
|
||||
public enum Mould
|
||||
{
|
||||
CHOPPER_FORTE("Chopper Forte", FORTE, ImmutableMap.of(BROAD, 4, LIGHT, 4, FLAT, 4)),
|
||||
GALDIUS_RICASSO("Galdius Ricasso", FORTE, ImmutableMap.of(BROAD, 4, HEAVY, 4, FLAT, 4)),
|
||||
DISARMING_FORTE("Disarming Forte", FORTE, ImmutableMap.of(NARROW, 4, LIGHT, 4, SPIKED, 4)),
|
||||
MEDUSA_RICASSO("Medusa Ricasso", FORTE, ImmutableMap.of(BROAD, 8, HEAVY, 6, FLAT, 8)),
|
||||
SERPENT_RICASSO("Serpent Ricasso", FORTE, ImmutableMap.of(NARROW, 6, LIGHT, 8, FLAT, 8)),
|
||||
SERRATED_FORTE("Serrated Forte", FORTE, ImmutableMap.of(NARROW, 8, HEAVY, 8, SPIKED, 6)),
|
||||
STILETTO_FORTE("Stiletto Forte", FORTE, ImmutableMap.of(NARROW, 8, LIGHT, 10, FLAT, 8)),
|
||||
DEFENDER_BASE("Defender Base", FORTE, ImmutableMap.of(BROAD, 8, HEAVY, 10, FLAT, 8)),
|
||||
JUGGERNAUT_FORTE("Juggernaut Forte", FORTE, ImmutableMap.of(BROAD, 4, HEAVY, 4, SPIKED, 16)),
|
||||
CHOPPER_FORTE_1("Chopper Forte +1", FORTE, ImmutableMap.of(BROAD, 3, LIGHT, 4, FLAT, 18)),
|
||||
SPIKER("Spiker!", FORTE, ImmutableMap.of(NARROW, 1, HEAVY, 2, SPIKED, 22)),
|
||||
SAW_BLADE("Saw Blade", BLADE, ImmutableMap.of(BROAD, 4, LIGHT, 4, SPIKED, 4)),
|
||||
DEFENDERS_EDGE("Defenders Edge", BLADE, ImmutableMap.of(BROAD, 4, HEAVY, 4, SPIKED, 4)),
|
||||
FISH_BLADE("Fish Blade", BLADE, ImmutableMap.of(NARROW, 4, LIGHT, 4, FLAT, 4)),
|
||||
MEDUSA_BLADE("Medusa Blade", BLADE, ImmutableMap.of(BROAD, 8, HEAVY, 8, FLAT, 6)),
|
||||
STILETTO_BLADE("Stiletto Blade", BLADE, ImmutableMap.of(NARROW, 8, LIGHT, 6, FLAT, 8)),
|
||||
GLADIUS_EDGE("Gladius Edge", BLADE, ImmutableMap.of(NARROW, 6, HEAVY, 8, FLAT, 8)),
|
||||
FLAMBERGE_BLADE("Flamberge Blade", BLADE, ImmutableMap.of(NARROW, 8, LIGHT, 8, SPIKED, 10)),
|
||||
SERPENT_BLADE("Serpent Blade", BLADE, ImmutableMap.of(NARROW, 10, LIGHT, 8, FLAT, 8)),
|
||||
CLAYMORE_BLADE("Claymore Blade", BLADE, ImmutableMap.of(BROAD, 16, HEAVY, 4, FLAT, 4)),
|
||||
FLEUR_DE_BLADE("Fleur de Blade", BLADE, ImmutableMap.of(BROAD, 4, HEAVY, 18, SPIKED, 1)),
|
||||
CHOPPA("Choppa!", BLADE, ImmutableMap.of(BROAD, 1, LIGHT, 22, FLAT, 2)),
|
||||
PEOPLE_POKER_POINT("People Poker Point", TIP, ImmutableMap.of(NARROW, 4, HEAVY, 4, FLAT, 4)),
|
||||
CHOPPER_TIP("Chopper Tip", TIP, ImmutableMap.of(BROAD, 4, LIGHT, 4, SPIKED, 4)),
|
||||
MEDUSAS_HEAD("Medusa's Head", TIP, ImmutableMap.of(BROAD, 4, HEAVY, 4, SPIKED, 4)),
|
||||
SERPENTS_FANG("Serpent's Fang", TIP, ImmutableMap.of(NARROW, 8, LIGHT, 6, SPIKED, 8)),
|
||||
GLADIUS_POINT("Gladius Point", TIP, ImmutableMap.of(NARROW, 8, HEAVY, 8, FLAT, 6)),
|
||||
SAW_TIP("Saw Tip", TIP, ImmutableMap.of(BROAD, 6, HEAVY, 8, SPIKED, 8)),
|
||||
CORRUPTED_POINT("Corrupted Point", TIP, ImmutableMap.of(NARROW, 8, LIGHT, 10, SPIKED, 8)),
|
||||
DEFENDERS_TIP("Defenders Tip", TIP, ImmutableMap.of(BROAD, 10, HEAVY, 8, SPIKED, 8)),
|
||||
SERRATED_TIP("Serrated Tip", TIP, ImmutableMap.of(NARROW, 4, LIGHT, 16, SPIKED, 4)),
|
||||
NEEDLE_POINT("Needle Point", TIP, ImmutableMap.of(NARROW, 18, LIGHT, 3, FLAT, 4)),
|
||||
THE_POINT("The Point!", TIP, ImmutableMap.of(BROAD, 2, LIGHT, 1, FLAT, 22)),
|
||||
;
|
||||
|
||||
private final String name;
|
||||
private final MouldType mouldType;
|
||||
private final Map<CommissionType, Integer> typeToScore;
|
||||
private final String name;
|
||||
private final MouldType mouldType;
|
||||
private final Map<CommissionType, Integer> typeToScore;
|
||||
|
||||
public static final Mould[] values = Mould.values();
|
||||
public static final Mould[] values = Mould.values();
|
||||
|
||||
public static Mould forName(String text) {
|
||||
for (Mould mould : values) {
|
||||
if (mould.name.equalsIgnoreCase(text)) {
|
||||
return mould;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static Mould forName(String text)
|
||||
{
|
||||
for (Mould mould : values)
|
||||
{
|
||||
if (mould.name.equalsIgnoreCase(text))
|
||||
{
|
||||
return mould;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getScore(CommissionType type1, CommissionType type2) {
|
||||
int score = 0;
|
||||
score += typeToScore.getOrDefault(type1, 0);
|
||||
score += typeToScore.getOrDefault(type2, 0);
|
||||
return score;
|
||||
}
|
||||
public int getScore(CommissionType type1, CommissionType type2)
|
||||
{
|
||||
int score = 0;
|
||||
score += typeToScore.getOrDefault(type1, 0);
|
||||
score += typeToScore.getOrDefault(type2, 0);
|
||||
return score;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package com.toofifty.easygiantsfoundry.enums;
|
||||
|
||||
public enum MouldType {
|
||||
FORTE,
|
||||
BLADE,
|
||||
TIP,
|
||||
public enum MouldType
|
||||
{
|
||||
FORTE,
|
||||
BLADE,
|
||||
TIP,
|
||||
}
|
||||
|
||||
@@ -15,4 +15,14 @@ public enum Stage
|
||||
private final Heat heat;
|
||||
private final int progressPerAction;
|
||||
private final int heatChange;
|
||||
|
||||
public boolean isHeating()
|
||||
{
|
||||
return heatChange > 0;
|
||||
}
|
||||
|
||||
public boolean isCooling()
|
||||
{
|
||||
return heatChange < 0;
|
||||
}
|
||||
}
|
||||
|
||||
178
src/test/java/com/toofifty/easygiantsfoundry/HeatSolverTest.java
Normal file
@@ -0,0 +1,178 @@
|
||||
package com.toofifty.easygiantsfoundry;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
// playground to test HeatSolver
|
||||
public class HeatSolverTest
|
||||
{
|
||||
// @Test
|
||||
// public void TestHeatSolver_dx2_Iterative()
|
||||
// {
|
||||
// final int[] answer =
|
||||
// {1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6};
|
||||
// List<Integer> produced = HeatActionSolver.generateDx2List(answer.length);
|
||||
//
|
||||
// System.err.println("Expected Length: " + answer.length + " Length: " + produced.size());
|
||||
// // print produced
|
||||
// for (Integer integer : produced)
|
||||
// {
|
||||
// System.err.print(integer + ",");
|
||||
// }
|
||||
// System.err.println();
|
||||
// // compare
|
||||
// for (int i = 0; i < answer.length; i++)
|
||||
// {
|
||||
// assertEquals("Asserting dx2 n=" + i, answer[i], produced.get(i).intValue());
|
||||
// }
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void TestHeatSolver_dx2_Numerical()
|
||||
{
|
||||
final int[] answer =
|
||||
{1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6};
|
||||
// test getDx2AtIndex
|
||||
for (int i = 0; i < answer.length; i++)
|
||||
{
|
||||
assertEquals("Asserting dx2 n=" + i, answer[i], HeatActionSolver.getDx2AtIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestHeatSolver_dx1()
|
||||
{
|
||||
final int c = 7;
|
||||
final int[] answer =
|
||||
// {1,1,2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6};
|
||||
{7, 8, 9, 11, 13, 15, 17, 19, 21, 24, 27, 30, 33, 37, 41, 45, 49, 53, 57, 62, 67, 72, 77, 83, 89};
|
||||
for (int i = 0; i < answer.length; i++)
|
||||
{
|
||||
assertEquals("Asserting dx1 n=" + i + " c=" + c + " answer=" + answer[i], answer[i], HeatActionSolver.getDx1AtIndex(i, c));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestHeatSolver_dx2_from_groundtruth()
|
||||
{
|
||||
// runelite-shell script for retrieving heating/cooling delta.
|
||||
// copy-paste into developer-tools -> Shell
|
||||
|
||||
|
||||
// ground-truth answer from game
|
||||
final int[] answer =
|
||||
{7, 8, 9, 11, 13, 15, 17, 19, 21, 24, 27, 30, 33, 37, 41, 45, 49, 53, 57, 62, 67, 72, 77, 83, 89};
|
||||
for (int i = 0; i < answer.length - 1; i++)
|
||||
{
|
||||
System.err.print(answer[i + 1] - answer[i] + ",");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestHeatSolver_Dx0()
|
||||
{
|
||||
final int[] answer_dx1 =
|
||||
{7, 8, 9, 11, 13, 15, 17, 19, 21, 24, 27, 30, 33, 37, 41, 45, 49, 53, 57, 62, 67, 72, 77, 83, 89};
|
||||
List<Integer> answer_dx0 = new ArrayList<>();
|
||||
|
||||
|
||||
int sum = 0;
|
||||
for (int i = 0; i < answer_dx1.length; i++)
|
||||
{
|
||||
sum += answer_dx1[i];
|
||||
answer_dx0.add(sum);
|
||||
}
|
||||
|
||||
System.err.println(answer_dx0);
|
||||
|
||||
for (int i = 0; i < answer_dx1.length; i++)
|
||||
{
|
||||
TestHeatSolver_Dx0_Helper(answer_dx0.get(i), answer_dx0.get(0), i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestHeatSolver_Dx0_Manual()
|
||||
{
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
System.err.println("[" + (350 + i) + "]" + HeatActionSolver.findDx0Index(350 + i, 7, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestHeatSolver_Dx0_2()
|
||||
{
|
||||
// 7->1,15->2,24->3,35->4,48->5,63->6,80->7,99->8,120->9,144->10,171->11,201->12,234->13,271->14,312->15,357->16,406->17,459->18,516->19,578->20,645->21,717->22,794->23,877->24,966->25
|
||||
final int[] answer_dx1 =
|
||||
{7, 8, 9, 11, 13, 15, 17, 19, 21, 24, 27, 30, 33, 37, 41, 45, 49, 53, 57, 62, 67, 72, 77, 83, 89};
|
||||
List<Integer> answer_dx0 = new ArrayList<>();
|
||||
|
||||
|
||||
int sum = 0;
|
||||
for (int i = 0; i < answer_dx1.length; i++)
|
||||
{
|
||||
sum += answer_dx1[i];
|
||||
answer_dx0.add(sum);
|
||||
}
|
||||
|
||||
System.err.println(answer_dx0);
|
||||
|
||||
// System.err.println(
|
||||
// HeatSolver.findDx0IndexContinue(406, 7, 0));
|
||||
// System.err.println(
|
||||
// HeatSolver.findDx0IndexContinue(406, 7, 10));
|
||||
// System.err.println(
|
||||
// HeatSolver.findDx0IndexContinue(406, 7, 17));
|
||||
//
|
||||
// System.err.println(
|
||||
// HeatSolver.findDx0IndexContinue(1000, 7, 0));
|
||||
System.err.println(
|
||||
HeatActionSolver.findDx0Index(1000, 7, 1));
|
||||
}
|
||||
|
||||
public void TestHeatSolver_Dx0_Helper(int dx0, int constant, int answer_index)
|
||||
{
|
||||
System.err.print(dx0 + "->" + HeatActionSolver.findDx0Index(dx0, constant, 0) + ",");
|
||||
|
||||
// test calcDx0Index
|
||||
assertEquals("Asserting dx0 index for " + answer_index,
|
||||
answer_index, HeatActionSolver.findDx0Index(dx0, constant, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void Calc()
|
||||
{
|
||||
int[] dx1 = {
|
||||
27,
|
||||
30,
|
||||
33,
|
||||
37,
|
||||
41,
|
||||
45,
|
||||
49,
|
||||
53,
|
||||
57,
|
||||
62,
|
||||
67,
|
||||
72,
|
||||
77,
|
||||
83,
|
||||
89,
|
||||
95,
|
||||
91,
|
||||
};
|
||||
|
||||
List<Integer> dx2 = new ArrayList<>();
|
||||
for (int i = 0; i < dx1.length - 1; i++)
|
||||
{
|
||||
dx2.add(dx1[i+1] - dx1[i]);
|
||||
}
|
||||
|
||||
System.err.println(dx2);
|
||||
}
|
||||
|
||||
}
|
||||