* add config for text outline, draw text over gameobject highlight * add configurable dynamic overlay font * space heat/action text according to font height * draw text manually * add configurable text background
589 lines
16 KiB
Java
589 lines
16 KiB
Java
package com.toofifty.easygiantsfoundry;
|
|
|
|
import static com.toofifty.easygiantsfoundry.EasyGiantsFoundryClientIDs.*;
|
|
import static com.toofifty.easygiantsfoundry.EasyGiantsFoundryHelper.getHeatColor;
|
|
import static com.toofifty.easygiantsfoundry.EasyGiantsFoundryHelper.renderTextLocation;
|
|
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.FontType;
|
|
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.MenuEntry;
|
|
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.outline.ModelOutlineRenderer;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
|
public class FoundryOverlay3D extends Overlay
|
|
{
|
|
|
|
private static final int HAND_IN_WIDGET = 49414221;
|
|
private static final int CRUCIBLE_CAPACITY = 28;
|
|
private final ModelOutlineRenderer modelOutlineRenderer;
|
|
|
|
GameObject tripHammer;
|
|
GameObject grindstone;
|
|
GameObject polishingWheel;
|
|
GameObject lavaPool;
|
|
GameObject waterfall;
|
|
GameObject mouldJig;
|
|
GameObject crucible;
|
|
GameObject storage;
|
|
NPC kovac;
|
|
|
|
private final Client client;
|
|
private final EasyGiantsFoundryState state;
|
|
private final EasyGiantsFoundryConfig 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();
|
|
}
|
|
|
|
if (BonusWidget.isActive(client))
|
|
{
|
|
return config.toolBonus();
|
|
}
|
|
|
|
int actionsLeft = state.getActionsLeftInStage();
|
|
int heatLeft = state.getActionsForHeatLevel();
|
|
if (actionsLeft <= 1 || heatLeft <= 1)
|
|
{
|
|
return config.toolCaution();
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
@Override
|
|
public Dimension render(Graphics2D graphics)
|
|
{
|
|
if (!state.isEnabled())
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (config.dynamicOverlayFont() != FontType.DEFAULT)
|
|
{
|
|
graphics.setFont(config.dynamicOverlayFont().getFont());
|
|
}
|
|
|
|
if (config.highlightKovac())
|
|
{
|
|
drawKovacIfHandIn(graphics);
|
|
}
|
|
|
|
if (client.getVarbitValue(VARBIT_PREFORM_STORED) == 1)
|
|
{
|
|
if (config.highlightStorage())
|
|
{
|
|
drawStorage(graphics);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
if (state.getCurrentStage() == null)
|
|
{
|
|
if (config.highlightMould())
|
|
{
|
|
drawMouldIfNotSet(graphics);
|
|
}
|
|
if (config.highlightCrucible())
|
|
{
|
|
drawCrucibleIfMouldSet(graphics);
|
|
}
|
|
if (config.drawMouldInfoOverlay())
|
|
{
|
|
drawMouldScoreIfMouldSet(graphics);
|
|
drawPreformScoreIfPoured(graphics);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
Stage stage = state.getCurrentStage();
|
|
GameObject stageObject = getStageObject(stage);
|
|
if (stageObject == null || graphics == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
// !state.heatingCoolingState.isIdle()
|
|
// if the stage heat is already in range, but player still wants to do heat changes
|
|
if ((stage.getHeat() != heat || !state.heatActionStateMachine.isIdle()) && config.highlightWaterAndLava())
|
|
{
|
|
drawHeatChangers(graphics);
|
|
}
|
|
// mouse hover over preview
|
|
else if (config.drawLavaWaterInfoOverlay())
|
|
{
|
|
MenuEntry[] menuEntries = client.getMenuEntries();
|
|
if (menuEntries.length != 0)
|
|
{
|
|
MenuEntry hoveredMenu = menuEntries[menuEntries.length - 1];
|
|
|
|
if (hoveredMenu.getIdentifier() == lavaPool.getId())
|
|
{
|
|
drawHeatChangerPreviewOverlay(graphics, lavaPool, true);
|
|
}
|
|
else if (hoveredMenu.getIdentifier() == waterfall.getId())
|
|
{
|
|
drawHeatChangerPreviewOverlay(graphics, waterfall, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
drawActionOverlay(graphics, stageObject);
|
|
|
|
return null;
|
|
}
|
|
|
|
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 drawHeatChangerPreviewOverlay(
|
|
Graphics2D graphics,
|
|
GameObject stageObject,
|
|
boolean isLava
|
|
)
|
|
{
|
|
|
|
HeatActionSolver.DurationResult fastResult =
|
|
HeatActionSolver.solve(
|
|
state.getCurrentStage(),
|
|
state.getCurrentHeatRange(),
|
|
state.getActionsLeftInStage(),
|
|
state.getHeatAmount(),
|
|
true,
|
|
isLava,
|
|
config.heatActionPadTicks(),
|
|
state.isPlayerRunning()
|
|
);
|
|
|
|
final int fastDuration = fastResult.getDuration();
|
|
HeatActionSolver.DurationResult slowResult =
|
|
HeatActionSolver.solve(
|
|
state.getCurrentStage(),
|
|
state.getCurrentHeatRange(),
|
|
state.getActionsLeftInStage(),
|
|
state.getHeatAmount(),
|
|
false,
|
|
isLava,
|
|
config.heatActionPadTicks(),
|
|
state.isPlayerRunning()
|
|
);
|
|
final int slowDuration = slowResult.getDuration();
|
|
|
|
final String fastName = isLava ? "dunks" : "quenches";
|
|
final String slowName = isLava ? "heats" : "cools";
|
|
|
|
String text;
|
|
if (config.debugging())
|
|
{
|
|
text = String.format("%d %s (predicted: %d) or %d %s (predicted: %d) (overshoot: %s goal-in-range: %s)",
|
|
fastDuration, fastName, fastResult.getPredictedHeat(), slowDuration, slowName, slowResult.getPredictedHeat(), slowResult.isOvershooting(), fastResult.isGoalInRange());
|
|
}
|
|
else
|
|
{
|
|
text = String.format("%d %s or %d %s ",
|
|
fastDuration, fastName, slowDuration, slowName);
|
|
}
|
|
|
|
LocalPoint stageLoc = stageObject.getLocalLocation();
|
|
stageLoc = new LocalPoint(stageLoc.getX(), stageLoc.getY());
|
|
|
|
Point pos = Perspective.getCanvasTextLocation(client, graphics, stageLoc, text, 50);
|
|
if (pos == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Color color = config.lavaWaterfallColour();
|
|
|
|
renderTextLocation(graphics, pos, text, color, config.textBackground(), config.textOutline());
|
|
}
|
|
|
|
private void drawHeatChangerOverlay(Graphics2D graphics, GameObject stageObject)
|
|
{
|
|
|
|
String text;
|
|
if (config.debugging())
|
|
{
|
|
text = String.format("%d %s (overshoot: %s) [goal-in-range: %s]",
|
|
state.heatActionStateMachine.getRemainingDuration(),
|
|
state.heatActionStateMachine.getActionname(),
|
|
state.heatActionStateMachine.isOverShooting(),
|
|
state.heatActionStateMachine.isGoalInRange()
|
|
);
|
|
}
|
|
else
|
|
{
|
|
text = String.format("%d %s",
|
|
state.heatActionStateMachine.getRemainingDuration(),
|
|
state.heatActionStateMachine.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();
|
|
|
|
renderTextLocation(graphics, pos, text, color, config.textBackground(), config.textOutline());
|
|
}
|
|
|
|
private void drawHeatChangers(Graphics2D graphics)
|
|
{
|
|
int change = state.getHeatChangeNeeded();
|
|
Shape shape = null;
|
|
|
|
boolean isLava = change > 0;
|
|
boolean isWaterfall = change < 0;
|
|
if (isWaterfall || state.heatActionStateMachine.isCooling())
|
|
{
|
|
shape = waterfall.getClickbox();
|
|
}
|
|
else if (isLava || state.heatActionStateMachine.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);
|
|
}
|
|
|
|
if (config.drawLavaWaterInfoOverlay())
|
|
{
|
|
if (state.heatActionStateMachine.isCooling())
|
|
{
|
|
drawHeatChangerOverlay(graphics, waterfall);
|
|
}
|
|
else if (isWaterfall)
|
|
{
|
|
drawHeatChangerPreviewOverlay(graphics, waterfall, false);
|
|
}
|
|
if (state.heatActionStateMachine.isHeating())
|
|
{
|
|
drawHeatChangerOverlay(graphics, lavaPool);
|
|
}
|
|
else if (isLava)
|
|
{
|
|
drawHeatChangerPreviewOverlay(graphics, lavaPool, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private void drawCrucibleContent(Graphics2D graphics)
|
|
{
|
|
if (!config.drawCrucibleInfoOverlay())
|
|
{
|
|
return;
|
|
}
|
|
String text = String.format("%d/%d score: %d", state.getCrucibleCount(), CRUCIBLE_CAPACITY, (int)state.getCrucibleScore());
|
|
|
|
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();
|
|
}
|
|
renderTextLocation(graphics, pos, text, color, config.textBackground(), config.textOutline());
|
|
}
|
|
|
|
private void drawMouldScoreIfMouldSet(Graphics2D graphics) {
|
|
if (client.getVarbitValue(SWORD_TYPE_1_VARBIT) == 0)
|
|
{
|
|
return;
|
|
}
|
|
if (client.getVarbitValue(VARBIT_GAME_STAGE) != 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (state.getMouldScore() < 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
String text = String.format("score: %d", state.getMouldScore());
|
|
LocalPoint mouldLoc = mouldJig.getLocalLocation();
|
|
Point pos = Perspective.getCanvasTextLocation(client, graphics, mouldLoc, text, 115);
|
|
Color color = config.generalHighlight();
|
|
|
|
renderTextLocation(graphics, pos, text, color, config.textBackground(), config.textOutline());
|
|
}
|
|
private void drawPreformScoreIfPoured(Graphics2D graphics) {
|
|
if (client.getVarbitValue(VARBIT_GAME_STAGE) != 2)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (state.getMouldScore() < 0 || state.getLastKnownCrucibleScore() < 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int preformScore = state.getLastKnownCrucibleScore() + state.getMouldScore();
|
|
String text = String.format("score: %d", preformScore);
|
|
LocalPoint mouldLoc = mouldJig.getLocalLocation();
|
|
Point pos = Perspective.getCanvasTextLocation(client, graphics, mouldLoc, text, 115);
|
|
|
|
Color color = config.generalHighlight();
|
|
|
|
renderTextLocation(graphics, pos, text, color, config.textBackground(), config.textOutline());
|
|
}
|
|
|
|
private void drawCrucibleIfMouldSet(Graphics2D graphics)
|
|
{
|
|
if (client.getVarbitValue(SWORD_TYPE_1_VARBIT) == 0)
|
|
{
|
|
return;
|
|
}
|
|
if (client.getVarbitValue(VARBIT_GAME_STAGE) != 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
drawCrucibleContent(graphics);
|
|
}
|
|
|
|
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);
|
|
renderTextLocation(graphics, canvasLocation, text, config.generalHighlight(), config.textBackground(), config.textOutline());
|
|
}
|
|
}
|
|
|
|
private void drawStorage(Graphics2D graphics)
|
|
{
|
|
Shape shape = storage.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 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 drawActionOverlay(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);
|
|
if (canvasLocation == null)
|
|
{
|
|
return;
|
|
}
|
|
renderTextLocation(graphics, canvasLocation, text, getHeatColor(actionsLeft, heatLeft), config.textBackground(), config.textOutline());
|
|
}
|
|
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);
|
|
if (canvasLocation == null)
|
|
{
|
|
return;
|
|
}
|
|
canvasLocation = new Point(canvasLocation.getX(), canvasLocation.getY() + graphics.getFontMetrics().getHeight());
|
|
renderTextLocation(graphics, canvasLocation, text, getHeatColor(actionsLeft, heatLeft), config.textBackground(), config.textOutline());
|
|
}
|
|
}
|
|
}
|