Merge pull request #41 from TheLouisHong/master
heat/cool prediction: continued important algorithm bug fix for prediction
This commit is contained in:
@@ -23,6 +23,8 @@ public class EasyGiantsFoundryClientIDs
|
|||||||
// 3 -
|
// 3 -
|
||||||
protected static final int VARBIT_GAME_STAGE = 13914;
|
protected static final int VARBIT_GAME_STAGE = 13914;
|
||||||
|
|
||||||
|
protected static final int VARBIT_PREFORM_STORED = 13947;
|
||||||
|
|
||||||
protected static final int WIDGET_HEAT_PARENT = 49414153;
|
protected static final int WIDGET_HEAT_PARENT = 49414153;
|
||||||
protected static final int WIDGET_LOW_HEAT_PARENT = 49414163;
|
protected static final int WIDGET_LOW_HEAT_PARENT = 49414163;
|
||||||
protected static final int WIDGET_MED_HEAT_PARENT = 49414164;
|
protected static final int WIDGET_MED_HEAT_PARENT = 49414164;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.toofifty.easygiantsfoundry;
|
package com.toofifty.easygiantsfoundry;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
|
||||||
import net.runelite.client.config.Config;
|
import net.runelite.client.config.Config;
|
||||||
import net.runelite.client.config.ConfigGroup;
|
import net.runelite.client.config.ConfigGroup;
|
||||||
import net.runelite.client.config.ConfigItem;
|
import net.runelite.client.config.ConfigItem;
|
||||||
@@ -247,6 +246,18 @@ public interface EasyGiantsFoundryConfig extends Config
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "storageHighlight",
|
||||||
|
name = "Highlight Preform Storage",
|
||||||
|
description = "Highlight Storage when it contains a preform.",
|
||||||
|
position = 10,
|
||||||
|
section = highlightList
|
||||||
|
)
|
||||||
|
default boolean highlightStorage()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@ConfigSection(
|
@ConfigSection(
|
||||||
name = "Info Panel",
|
name = "Info Panel",
|
||||||
description = "Settings for the Info Panel overlay",
|
description = "Settings for the Info Panel overlay",
|
||||||
@@ -502,6 +513,34 @@ public interface EasyGiantsFoundryConfig extends Config
|
|||||||
description = "Advanced Settings",
|
description = "Advanced Settings",
|
||||||
position = 5
|
position = 5
|
||||||
)
|
)
|
||||||
String generalSettings = "generalSettings";
|
String advancedSettings = "generalSettings";
|
||||||
|
|
||||||
|
|
||||||
|
@Range(
|
||||||
|
max = 50
|
||||||
|
)
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "heatActionBuffer", // renamed to reset player's settings for previous bugged implementation
|
||||||
|
name = "Lava/Waterfall Padding Ticks",
|
||||||
|
description = "Units in ticks; buffers more than optimal heat when in lava/waterfall calculations to compensate for heat decay when the player is afk or running/walking slower than optimal.",
|
||||||
|
position = 0,
|
||||||
|
section = advancedSettings
|
||||||
|
)
|
||||||
|
default int heatActionPadTicks()
|
||||||
|
{
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "debugging",
|
||||||
|
name = "Show Debugging",
|
||||||
|
description = "Shows debugging visuals used for development",
|
||||||
|
position = 0,
|
||||||
|
section = advancedSettings,
|
||||||
|
warning = "Only used for development."
|
||||||
|
)
|
||||||
|
default boolean debugging()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,18 +17,9 @@ import net.runelite.api.GameState;
|
|||||||
import net.runelite.api.InventoryID;
|
import net.runelite.api.InventoryID;
|
||||||
import net.runelite.api.Item;
|
import net.runelite.api.Item;
|
||||||
import net.runelite.api.ItemContainer;
|
import net.runelite.api.ItemContainer;
|
||||||
|
import net.runelite.api.MenuAction;
|
||||||
import net.runelite.api.Skill;
|
import net.runelite.api.Skill;
|
||||||
import net.runelite.api.events.GameObjectDespawned;
|
import net.runelite.api.events.*;
|
||||||
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;
|
|
||||||
import net.runelite.api.events.StatChanged;
|
|
||||||
import net.runelite.api.events.VarbitChanged;
|
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
import net.runelite.client.Notifier;
|
import net.runelite.client.Notifier;
|
||||||
import net.runelite.client.callback.ClientThread;
|
import net.runelite.client.callback.ClientThread;
|
||||||
@@ -58,6 +49,7 @@ public class EasyGiantsFoundryPlugin extends Plugin
|
|||||||
|
|
||||||
private static final int CRUCIBLE = 44776;
|
private static final int CRUCIBLE = 44776;
|
||||||
private static final int MOULD_JIG = 44777;
|
private static final int MOULD_JIG = 44777;
|
||||||
|
private static final int STORAGE = 44778;
|
||||||
|
|
||||||
private static final int KOVAC_NPC = 11472;
|
private static final int KOVAC_NPC = 11472;
|
||||||
|
|
||||||
@@ -156,10 +148,47 @@ public class EasyGiantsFoundryPlugin extends Plugin
|
|||||||
case CRUCIBLE:
|
case CRUCIBLE:
|
||||||
overlay3d.crucible = gameObject;
|
overlay3d.crucible = gameObject;
|
||||||
break;
|
break;
|
||||||
|
case STORAGE:
|
||||||
|
overlay3d.storage = gameObject;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onGameObjectDespawned(GameObjectDespawned event)
|
||||||
|
{
|
||||||
|
GameObject gameObject = event.getGameObject();
|
||||||
|
switch (gameObject.getId())
|
||||||
|
{
|
||||||
|
case POLISHING_WHEEL:
|
||||||
|
state.setEnabled(false);
|
||||||
|
overlay3d.polishingWheel = null;
|
||||||
|
break;
|
||||||
|
case GRINDSTONE:
|
||||||
|
overlay3d.grindstone = null;
|
||||||
|
break;
|
||||||
|
case LAVA_POOL:
|
||||||
|
overlay3d.lavaPool = null;
|
||||||
|
break;
|
||||||
|
case WATERFALL:
|
||||||
|
overlay3d.waterfall = null;
|
||||||
|
break;
|
||||||
|
case TRIP_HAMMER:
|
||||||
|
overlay3d.tripHammer = null;
|
||||||
|
break;
|
||||||
|
case MOULD_JIG:
|
||||||
|
overlay3d.mouldJig = null;
|
||||||
|
break;
|
||||||
|
case CRUCIBLE:
|
||||||
|
overlay3d.crucible = null;
|
||||||
|
break;
|
||||||
|
case STORAGE:
|
||||||
|
overlay3d.storage = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onGameStateChanged(GameStateChanged event)
|
public void onGameStateChanged(GameStateChanged event)
|
||||||
{
|
{
|
||||||
@@ -202,36 +231,6 @@ public class EasyGiantsFoundryPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
public void onGameObjectDespawned(GameObjectDespawned event)
|
|
||||||
{
|
|
||||||
GameObject gameObject = event.getGameObject();
|
|
||||||
switch (gameObject.getId())
|
|
||||||
{
|
|
||||||
case POLISHING_WHEEL:
|
|
||||||
state.setEnabled(false);
|
|
||||||
overlay3d.polishingWheel = null;
|
|
||||||
break;
|
|
||||||
case GRINDSTONE:
|
|
||||||
overlay3d.grindstone = null;
|
|
||||||
break;
|
|
||||||
case LAVA_POOL:
|
|
||||||
overlay3d.lavaPool = null;
|
|
||||||
break;
|
|
||||||
case WATERFALL:
|
|
||||||
overlay3d.waterfall = null;
|
|
||||||
break;
|
|
||||||
case TRIP_HAMMER:
|
|
||||||
overlay3d.tripHammer = null;
|
|
||||||
break;
|
|
||||||
case MOULD_JIG:
|
|
||||||
overlay3d.mouldJig = null;
|
|
||||||
break;
|
|
||||||
case CRUCIBLE:
|
|
||||||
overlay3d.crucible = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onNpcSpawned(NpcSpawned event)
|
public void onNpcSpawned(NpcSpawned event)
|
||||||
@@ -268,50 +267,74 @@ public class EasyGiantsFoundryPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onMenuEntryAdded(MenuEntryAdded event)
|
||||||
|
{
|
||||||
|
if (event.getOption().startsWith("Heat-preform") || event.getOption().startsWith("Dunk-preform"))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (event.getOption().startsWith("Cool-preform") || event.getOption().startsWith("Quench-preform")) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onMenuOptionClicked(MenuOptionClicked event)
|
public void onMenuOptionClicked(MenuOptionClicked event)
|
||||||
{
|
{
|
||||||
if (!state.isEnabled()) return;
|
clientThread.invokeAtTickEnd(() ->
|
||||||
|
|
||||||
if (event.getMenuTarget().contains("Crucible "))
|
|
||||||
{
|
{
|
||||||
if (event.getMenuOption().equals("Pour"))
|
if (!(event.getMenuAction() == MenuAction.GAME_OBJECT_FIRST_OPTION
|
||||||
|
|| event.getMenuAction() == MenuAction.GAME_OBJECT_SECOND_OPTION
|
||||||
|
|| event.getMenuAction() == MenuAction.GAME_OBJECT_THIRD_OPTION
|
||||||
|
|| event.getMenuAction() == MenuAction.GAME_OBJECT_FOURTH_OPTION
|
||||||
|
|| event.getMenuAction() == MenuAction.GAME_OBJECT_FIFTH_OPTION
|
||||||
|
|| event.getMenuAction() == MenuAction.WIDGET_TARGET_ON_GAME_OBJECT
|
||||||
|
|| event.getMenuAction() == MenuAction.WALK))
|
||||||
{
|
{
|
||||||
if (client.getVarbitValue(VARBIT_GAME_STAGE) == 1)
|
return;
|
||||||
{
|
|
||||||
state.setLastKnownCrucibleScore((int) state.getCrucibleScore());
|
|
||||||
}
|
|
||||||
// add persistent game message of the alloy value so user can reference later.
|
|
||||||
client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "The score of the preform is <col=00FFFF>" + ((int) state.getCrucibleScore() + state.getMouldScore()), null);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Could not find a varbit to capture, so capture the menu-option directly.
|
if (!state.isEnabled()) return;
|
||||||
// start the HeatActionStateMachine when varbit begins to update in onVarbitChanged()
|
|
||||||
if (event.getMenuOption().startsWith("Heat-preform"))
|
if (event.getMenuTarget().contains("Crucible "))
|
||||||
{
|
{
|
||||||
state.heatingCoolingState.stop();
|
if (event.getMenuOption().equals("Pour"))
|
||||||
state.heatingCoolingState.setup(7, 0, "heats");
|
{
|
||||||
}
|
if (client.getVarbitValue(VARBIT_GAME_STAGE) == 1)
|
||||||
else if (event.getMenuOption().startsWith("Dunk-preform"))
|
{
|
||||||
{
|
state.setLastKnownCrucibleScore((int) state.getCrucibleScore());
|
||||||
state.heatingCoolingState.stop();
|
}
|
||||||
state.heatingCoolingState.setup(27, 2, "dunks");
|
// add persistent game message of the alloy value so user can reference later.
|
||||||
}
|
client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "The score of the preform is <col=00FFFF>" + ((int) state.getCrucibleScore() + state.getMouldScore()), null);
|
||||||
else if (event.getMenuOption().startsWith("Cool-preform"))
|
}
|
||||||
{
|
}
|
||||||
state.heatingCoolingState.stop();
|
|
||||||
state.heatingCoolingState.setup(-7, 0, "cools");
|
// Could not find a varbit to capture, so capture the menu-option directly.
|
||||||
}
|
// start the HeatActionStateMachine when varbit begins to update in onVarbitChanged()
|
||||||
else if (event.getMenuOption().startsWith("Quench-preform"))
|
if (event.getMenuOption().startsWith("Heat-preform"))
|
||||||
{
|
{
|
||||||
state.heatingCoolingState.stop();
|
state.heatActionStateMachine.stop();
|
||||||
state.heatingCoolingState.setup(-27, -2, "quenches");
|
state.heatActionStateMachine.setup(false, true, "heats");
|
||||||
}
|
}
|
||||||
else // canceled heating/cooling, stop the heating state-machine
|
else if (event.getMenuOption().startsWith("Dunk-preform"))
|
||||||
{
|
{
|
||||||
state.heatingCoolingState.stop();
|
state.heatActionStateMachine.stop();
|
||||||
}
|
state.heatActionStateMachine.setup(true, true, "dunks");
|
||||||
|
}
|
||||||
|
else if (event.getMenuOption().startsWith("Cool-preform"))
|
||||||
|
{
|
||||||
|
state.heatActionStateMachine.stop();
|
||||||
|
state.heatActionStateMachine.setup(false, false, "cools");
|
||||||
|
}
|
||||||
|
else if (event.getMenuOption().startsWith("Quench-preform"))
|
||||||
|
{
|
||||||
|
state.heatActionStateMachine.stop();
|
||||||
|
state.heatActionStateMachine.setup(true, false, "quenches");
|
||||||
|
}
|
||||||
|
else if (!state.heatActionStateMachine.isIdle()) // canceled heating/cooling, stop the heating state-machine
|
||||||
|
{
|
||||||
|
state.heatActionStateMachine.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
@@ -333,8 +356,8 @@ public class EasyGiantsFoundryPlugin extends Plugin
|
|||||||
|
|
||||||
// show mould score on Mould UI Title
|
// show mould score on Mould UI Title
|
||||||
Widget mouldParent = client.getWidget(47054850);
|
Widget mouldParent = client.getWidget(47054850);
|
||||||
Integer mouldScore = state.getMouldScore();
|
int mouldScore = state.getMouldScore();
|
||||||
if (mouldParent != null && mouldScore != null)
|
if (mouldParent != null && mouldScore >= 0)
|
||||||
{
|
{
|
||||||
Widget title = Objects.requireNonNull(mouldParent.getChild(1));
|
Widget title = Objects.requireNonNull(mouldParent.getChild(1));
|
||||||
|
|
||||||
@@ -362,23 +385,40 @@ public class EasyGiantsFoundryPlugin extends Plugin
|
|||||||
state.setMouldScore(-1);
|
state.setMouldScore(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// start the heating state-machine when the varbit updates
|
// start the heating state-machine when the varbit updates
|
||||||
// if heat varbit updated and the user clicked, start the state-machine
|
// if heat varbit updated and the user clicked, start the state-machine
|
||||||
if (event.getVarbitId() == VARBIT_HEAT && state.heatingCoolingState.getActionName() != null)
|
if (event.getVarbitId() == VARBIT_HEAT)
|
||||||
{
|
{
|
||||||
// ignore passive heat decay, one heat per two ticks
|
// ignore passive heat decay, one heat per two ticks
|
||||||
if (event.getValue() - previousHeat != -1)
|
int delta = event.getValue() - previousHeat;
|
||||||
|
// sign check: num * num > 0 == same sign
|
||||||
|
if (delta != -1)
|
||||||
{
|
{
|
||||||
// if the state-machine is idle, start it
|
if (state.heatActionStateMachine.getActionname() != null)
|
||||||
if (state.heatingCoolingState.isIdle())
|
|
||||||
{
|
{
|
||||||
state.heatingCoolingState.start(state, config, state.getHeatAmount());
|
// if the state-machine is idle, start it
|
||||||
|
if (state.heatActionStateMachine.isIdle())
|
||||||
|
{
|
||||||
|
state.heatActionStateMachine.start(state, config, previousHeat);
|
||||||
|
}
|
||||||
|
state.heatActionStateMachine.onTick();
|
||||||
}
|
}
|
||||||
|
|
||||||
state.heatingCoolingState.onTick();
|
if (config.debugging())
|
||||||
|
{
|
||||||
|
client.addChatMessage(ChatMessageType.GAMEMESSAGE, "",
|
||||||
|
"Heat: <col=FF0000>" + event.getValue() + "</col>" +
|
||||||
|
"Delta: <col=00FFFF>" + delta + "</col> " +
|
||||||
|
"Heating Ticks: <col=00FFFF>" + state.heatActionStateMachine.heatingTicks + "</col>" +
|
||||||
|
" Cooling Ticks: <col=00FFFF>" + state.heatActionStateMachine.coolingTicks + "</col>" +
|
||||||
|
" Remaining Ticks: <col=00FFFF>" + state.heatActionStateMachine.getRemainingDuration(), "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "Delta: <col=00FFFF>" + delta + "</col> ", "");
|
||||||
|
previousHeat = event.getValue();
|
||||||
}
|
}
|
||||||
previousHeat = event.getValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class EasyGiantsFoundryState
|
|||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@Getter
|
@Getter
|
||||||
private int lastKnownCrucibleScore = -1; // will be set when "Pour"ed
|
private int lastKnownCrucibleScore = -1; // will be set when "Pour"ed (because the crucible will be empty then)
|
||||||
|
|
||||||
private final List<Stage> stages = new ArrayList<>();
|
private final List<Stage> stages = new ArrayList<>();
|
||||||
private double heatRangeRatio = 0;
|
private double heatRangeRatio = 0;
|
||||||
@@ -153,19 +153,19 @@ public class EasyGiantsFoundryState
|
|||||||
int heat = getHeatAmount();
|
int heat = getHeatAmount();
|
||||||
|
|
||||||
int[] low = getLowHeatRange();
|
int[] low = getLowHeatRange();
|
||||||
if (heat > low[0] && heat < low[1])
|
if (heat >= low[0] && heat <= low[1])
|
||||||
{
|
{
|
||||||
return Heat.LOW;
|
return Heat.LOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
int[] med = getMedHeatRange();
|
int[] med = getMedHeatRange();
|
||||||
if (heat > med[0] && heat < med[1])
|
if (heat >= med[0] && heat <= med[1])
|
||||||
{
|
{
|
||||||
return Heat.MED;
|
return Heat.MED;
|
||||||
}
|
}
|
||||||
|
|
||||||
int[] high = getHighHeatRange();
|
int[] high = getHighHeatRange();
|
||||||
if (heat > high[0] && heat < high[1])
|
if (heat >= high[0] && heat <= high[1])
|
||||||
{
|
{
|
||||||
return Heat.HIGH;
|
return Heat.HIGH;
|
||||||
}
|
}
|
||||||
@@ -326,7 +326,7 @@ public class EasyGiantsFoundryState
|
|||||||
int[] range = getCurrentHeatRange();
|
int[] range = getCurrentHeatRange();
|
||||||
int actions = 0;
|
int actions = 0;
|
||||||
int heat = getHeatAmount();
|
int heat = getHeatAmount();
|
||||||
while (heat > range[0] && heat < range[1])
|
while (heat >= range[0] && heat <= range[1])
|
||||||
{
|
{
|
||||||
actions++;
|
actions++;
|
||||||
heat += stage.getHeatChange();
|
heat += stage.getHeatChange();
|
||||||
@@ -335,5 +335,5 @@ public class EasyGiantsFoundryState
|
|||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HeatActionStateMachine heatingCoolingState = new HeatActionStateMachine();
|
public HeatActionStateMachine heatActionStateMachine = new HeatActionStateMachine();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.toofifty.easygiantsfoundry;
|
package com.toofifty.easygiantsfoundry;
|
||||||
|
|
||||||
import static com.toofifty.easygiantsfoundry.EasyGiantsFoundryClientIDs.VARBIT_GAME_STAGE;
|
import static com.toofifty.easygiantsfoundry.EasyGiantsFoundryClientIDs.*;
|
||||||
import static com.toofifty.easygiantsfoundry.EasyGiantsFoundryClientIDs.WIDGET_PROGRESS_PARENT;
|
|
||||||
import static com.toofifty.easygiantsfoundry.EasyGiantsFoundryHelper.getHeatColor;
|
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_1_VARBIT;
|
||||||
import static com.toofifty.easygiantsfoundry.MouldHelper.SWORD_TYPE_2_VARBIT;
|
import static com.toofifty.easygiantsfoundry.MouldHelper.SWORD_TYPE_2_VARBIT;
|
||||||
@@ -17,6 +16,7 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import net.runelite.api.GameObject;
|
import net.runelite.api.GameObject;
|
||||||
|
import net.runelite.api.MenuEntry;
|
||||||
import net.runelite.api.NPC;
|
import net.runelite.api.NPC;
|
||||||
import net.runelite.api.Perspective;
|
import net.runelite.api.Perspective;
|
||||||
import net.runelite.api.Point;
|
import net.runelite.api.Point;
|
||||||
@@ -32,6 +32,7 @@ public class FoundryOverlay3D extends Overlay
|
|||||||
{
|
{
|
||||||
|
|
||||||
private static final int HAND_IN_WIDGET = 49414221;
|
private static final int HAND_IN_WIDGET = 49414221;
|
||||||
|
private static final int CRUCIBLE_CAPACITY = 28;
|
||||||
private final ModelOutlineRenderer modelOutlineRenderer;
|
private final ModelOutlineRenderer modelOutlineRenderer;
|
||||||
|
|
||||||
GameObject tripHammer;
|
GameObject tripHammer;
|
||||||
@@ -41,6 +42,7 @@ public class FoundryOverlay3D extends Overlay
|
|||||||
GameObject waterfall;
|
GameObject waterfall;
|
||||||
GameObject mouldJig;
|
GameObject mouldJig;
|
||||||
GameObject crucible;
|
GameObject crucible;
|
||||||
|
GameObject storage;
|
||||||
NPC kovac;
|
NPC kovac;
|
||||||
|
|
||||||
private final Client client;
|
private final Client client;
|
||||||
@@ -110,6 +112,15 @@ public class FoundryOverlay3D extends Overlay
|
|||||||
drawKovacIfHandIn(graphics);
|
drawKovacIfHandIn(graphics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (client.getVarbitValue(VARBIT_PREFORM_STORED) == 1)
|
||||||
|
{
|
||||||
|
if (config.highlightStorage())
|
||||||
|
{
|
||||||
|
drawStorage(graphics);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (state.getCurrentStage() == null)
|
if (state.getCurrentStage() == null)
|
||||||
{
|
{
|
||||||
if (config.highlightMould())
|
if (config.highlightMould())
|
||||||
@@ -126,13 +137,12 @@ public class FoundryOverlay3D extends Overlay
|
|||||||
drawPreformScoreIfPoured(graphics);
|
drawPreformScoreIfPoured(graphics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stage stage = state.getCurrentStage();
|
Stage stage = state.getCurrentStage();
|
||||||
GameObject stageObject = getStageObject(stage);
|
GameObject stageObject = getStageObject(stage);
|
||||||
if (stageObject == null)
|
if (stageObject == null || graphics == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -151,20 +161,30 @@ public class FoundryOverlay3D extends Overlay
|
|||||||
drawObjectOutline(graphics, stageObject, color);
|
drawObjectOutline(graphics, stageObject, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((stage.getHeat() != heat || !state.heatingCoolingState.isIdle()) && config.highlightWaterAndLava())
|
// !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);
|
drawHeatChangers(graphics);
|
||||||
}
|
}
|
||||||
|
// mouse hover over preview
|
||||||
if (state.heatingCoolingState.isCooling())
|
else if (config.drawLavaWaterInfoOverlay())
|
||||||
{
|
{
|
||||||
drawHeatingCoolingOverlay(graphics, waterfall);
|
MenuEntry[] menuEntries = client.getMenuEntries();
|
||||||
}
|
if (menuEntries.length != 0)
|
||||||
if (state.heatingCoolingState.isHeating())
|
{
|
||||||
{
|
MenuEntry hoveredMenu = menuEntries[menuEntries.length - 1];
|
||||||
drawHeatingCoolingOverlay(graphics, lavaPool);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (hoveredMenu.getIdentifier() == lavaPool.getId())
|
||||||
|
{
|
||||||
|
drawHeatChangerPreviewOverlay(graphics, lavaPool, true);
|
||||||
|
}
|
||||||
|
else if (hoveredMenu.getIdentifier() == waterfall.getId())
|
||||||
|
{
|
||||||
|
drawHeatChangerPreviewOverlay(graphics, waterfall, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -195,26 +215,87 @@ public class FoundryOverlay3D extends Overlay
|
|||||||
modelOutlineRenderer.drawOutline(stageObject, config.borderThickness(), _color, config.borderFeather());
|
modelOutlineRenderer.drawOutline(stageObject, config.borderThickness(), _color, config.borderFeather());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawHeatingCoolingOverlay(
|
private void drawHeatChangerPreviewOverlay(
|
||||||
Graphics2D graphics,
|
Graphics2D graphics,
|
||||||
GameObject stageObject
|
GameObject stageObject,
|
||||||
|
boolean isLava
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (!config.drawLavaWaterInfoOverlay())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.heatingCoolingState.isIdle())
|
int sign = isLava ? 1 : -1;
|
||||||
{
|
int fastVelocity = 27 * sign;
|
||||||
return;
|
int slowVelocity = 7 * sign;
|
||||||
}
|
int fastAccelBonus = 2 * sign;
|
||||||
|
int slowAccelBonus = 0;
|
||||||
|
|
||||||
|
HeatActionSolver.DurationResult fastResult =
|
||||||
|
HeatActionSolver.solve(
|
||||||
|
state.getCurrentStage(),
|
||||||
|
state.getCurrentHeatRange(),
|
||||||
|
state.getActionsLeftInStage(),
|
||||||
|
state.getHeatAmount(),
|
||||||
|
true,
|
||||||
|
isLava,
|
||||||
|
config.heatActionPadTicks() * 2
|
||||||
|
);
|
||||||
|
|
||||||
|
final int fastDuration = fastResult.getDuration();
|
||||||
|
HeatActionSolver.DurationResult slowResult =
|
||||||
|
HeatActionSolver.solve(
|
||||||
|
state.getCurrentStage(),
|
||||||
|
state.getCurrentHeatRange(),
|
||||||
|
state.getActionsLeftInStage(),
|
||||||
|
state.getHeatAmount(),
|
||||||
|
false,
|
||||||
|
isLava,
|
||||||
|
config.heatActionPadTicks() * 2
|
||||||
|
);
|
||||||
|
final int slowDuration = slowResult.getDuration();
|
||||||
|
|
||||||
|
final String fastName = isLava ? "dunks" : "quenches";
|
||||||
|
final String slowName = isLava ? "heats" : "cools";
|
||||||
|
|
||||||
String text;
|
String text;
|
||||||
text = String.format("%d %s",
|
if (config.debugging())
|
||||||
state.heatingCoolingState.getRemainingDuration(),
|
{
|
||||||
state.heatingCoolingState.getActionName()
|
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);
|
||||||
|
Color color = config.lavaWaterfallColour();
|
||||||
|
|
||||||
|
OverlayUtil.renderTextLocation(graphics, pos, text, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
LocalPoint stageLoc = stageObject.getLocalLocation();
|
||||||
stageLoc = new LocalPoint(stageLoc.getX(), stageLoc.getY());
|
stageLoc = new LocalPoint(stageLoc.getX(), stageLoc.getY());
|
||||||
@@ -230,11 +311,13 @@ public class FoundryOverlay3D extends Overlay
|
|||||||
int change = state.getHeatChangeNeeded();
|
int change = state.getHeatChangeNeeded();
|
||||||
Shape shape = null;
|
Shape shape = null;
|
||||||
|
|
||||||
if (change < 0 || state.heatingCoolingState.isCooling())
|
boolean isLava = change > 0;
|
||||||
|
boolean isWaterfall = change < 0;
|
||||||
|
if (isWaterfall || state.heatActionStateMachine.isCooling())
|
||||||
{
|
{
|
||||||
shape = waterfall.getClickbox();
|
shape = waterfall.getClickbox();
|
||||||
}
|
}
|
||||||
else if (change > 0 || state.heatingCoolingState.isHeating())
|
else if (isLava || state.heatActionStateMachine.isHeating())
|
||||||
{
|
{
|
||||||
shape = lavaPool.getClickbox();
|
shape = lavaPool.getClickbox();
|
||||||
}
|
}
|
||||||
@@ -254,9 +337,28 @@ public class FoundryOverlay3D extends Overlay
|
|||||||
graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20));
|
graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20));
|
||||||
graphics.fill(shape);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static final int CRUCIBLE_CAPACITY = 28;
|
|
||||||
|
|
||||||
private void drawCrucibleContent(Graphics2D graphics)
|
private void drawCrucibleContent(Graphics2D graphics)
|
||||||
{
|
{
|
||||||
@@ -411,6 +513,19 @@ public class FoundryOverlay3D extends Overlay
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
private void drawKovacIfHandIn(Graphics2D graphics)
|
||||||
{
|
{
|
||||||
Widget handInWidget = client.getWidget(HAND_IN_WIDGET);
|
Widget handInWidget = client.getWidget(HAND_IN_WIDGET);
|
||||||
@@ -430,6 +545,8 @@ public class FoundryOverlay3D extends Overlay
|
|||||||
|
|
||||||
private void drawActionOverlay(Graphics2D graphics, GameObject gameObject)
|
private void drawActionOverlay(Graphics2D graphics, GameObject gameObject)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
int actionsLeft = state.getActionsLeftInStage();
|
int actionsLeft = state.getActionsLeftInStage();
|
||||||
int heatLeft = state.getActionsForHeatLevel();
|
int heatLeft = state.getActionsForHeatLevel();
|
||||||
|
|
||||||
@@ -440,6 +557,10 @@ public class FoundryOverlay3D extends Overlay
|
|||||||
LocalPoint textLocation = gameObject.getLocalLocation();
|
LocalPoint textLocation = gameObject.getLocalLocation();
|
||||||
textLocation = new LocalPoint(textLocation.getX(), textLocation.getY());
|
textLocation = new LocalPoint(textLocation.getX(), textLocation.getY());
|
||||||
Point canvasLocation = Perspective.getCanvasTextLocation(client, graphics, textLocation, text, 250);
|
Point canvasLocation = Perspective.getCanvasTextLocation(client, graphics, textLocation, text, 250);
|
||||||
|
if (canvasLocation == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
OverlayUtil.renderTextLocation(graphics, canvasLocation, text, getHeatColor(actionsLeft, heatLeft));
|
OverlayUtil.renderTextLocation(graphics, canvasLocation, text, getHeatColor(actionsLeft, heatLeft));
|
||||||
}
|
}
|
||||||
if (config.drawActionLeftOverlay())
|
if (config.drawActionLeftOverlay())
|
||||||
@@ -449,6 +570,10 @@ public class FoundryOverlay3D extends Overlay
|
|||||||
LocalPoint textLocation = gameObject.getLocalLocation();
|
LocalPoint textLocation = gameObject.getLocalLocation();
|
||||||
textLocation = new LocalPoint(textLocation.getX(), textLocation.getY());
|
textLocation = new LocalPoint(textLocation.getX(), textLocation.getY());
|
||||||
Point canvasLocation = Perspective.getCanvasTextLocation(client, graphics, textLocation, text, 250);
|
Point canvasLocation = Perspective.getCanvasTextLocation(client, graphics, textLocation, text, 250);
|
||||||
|
if (canvasLocation == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
canvasLocation = new Point(canvasLocation.getX(), canvasLocation.getY() + 10);
|
canvasLocation = new Point(canvasLocation.getX(), canvasLocation.getY() + 10);
|
||||||
OverlayUtil.renderTextLocation(graphics, canvasLocation, text, getHeatColor(actionsLeft, heatLeft));
|
OverlayUtil.renderTextLocation(graphics, canvasLocation, text, getHeatColor(actionsLeft, heatLeft));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,16 @@ package com.toofifty.easygiantsfoundry;
|
|||||||
//import java.util.ArrayList;
|
//import java.util.ArrayList;
|
||||||
//import java.util.List;
|
//import java.util.List;
|
||||||
|
|
||||||
|
import com.toofifty.easygiantsfoundry.enums.Stage;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Solves the heating/cooling action and predicts tick duration (index)
|
* Solves the heating/cooling action and predicts tick duration (index)
|
||||||
* the naming convention is focused on the algorithm rather than in-game terminology for the context.
|
* the naming convention is focused on the algorithm rather than in-game terminology for the context.
|
||||||
* <p>
|
* <p>
|
||||||
* the dx_n refers to successive derivatives of an ordinary-differential-equations
|
* the dx_n refers to successive derivatives of an ordinary-differential-equations
|
||||||
* https://en.wikipedia.org/wiki/Ordinary_differential_equation
|
* https://en.wikipedia.org/wiki/Ordinary_differential_equation
|
||||||
* also known as distance (dx0), speed (dx1), and acceleration (dx2).
|
* also known as position (dx0), speed (dx1), and acceleration (dx2).
|
||||||
* <p>
|
* <p>
|
||||||
* dx0 - players current heat at tick
|
* dx0 - players current heat at tick
|
||||||
* dx1 - dx0_current - dx0_last_tick, aka the first derivative
|
* dx1 - dx0_current - dx0_last_tick, aka the first derivative
|
||||||
@@ -18,7 +21,17 @@ package com.toofifty.easygiantsfoundry;
|
|||||||
* for context, here's what dx1 extracted directly from in-game dunking looks like.
|
* 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.
|
* the purpose of the HeatActionSolver.java is to accurately model this data.
|
||||||
* int[] dx1 = {
|
* int[] dx1 = {
|
||||||
* 27,
|
* 7,
|
||||||
|
* 8,
|
||||||
|
* 9,
|
||||||
|
* 11,
|
||||||
|
* 13,
|
||||||
|
* 15,
|
||||||
|
* 17,
|
||||||
|
* 19,
|
||||||
|
* 21,
|
||||||
|
* 24,
|
||||||
|
* 27, -- dunk/quench starts here
|
||||||
* 30,
|
* 30,
|
||||||
* 33,
|
* 33,
|
||||||
* 37,
|
* 37,
|
||||||
@@ -77,148 +90,255 @@ subscribe(VarbitChanged.class, ev ->
|
|||||||
public class HeatActionSolver
|
public class HeatActionSolver
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
public static final int[] DX_1 = new int[]{
|
||||||
* <b>Warning:</b> this method prefers overshooting goal. For example, if goal is 957,
|
7,
|
||||||
* it will return index that reaches >957.<br>
|
8,
|
||||||
* This may be desirable if we're aiming to heat over range minimum,
|
9,
|
||||||
* but undesirable when cooling below range maximum; make sure to -1 the index if so.
|
11,
|
||||||
*
|
13,
|
||||||
*
|
15,
|
||||||
*
|
17,
|
||||||
* @param goal the desired heat destination
|
19,
|
||||||
* @param init_dx1 initial speed of heating/cooling. currently 7 for heat/cool, 27 for dunk/quench.
|
21,
|
||||||
* @param dx2_offset bonus acceleration. currently, 0 for heat/cool, 2 for dunk/quench.
|
24,
|
||||||
* @return Index here refers to tick. So an index of 10 means the goal can be reached in 10 ticks.
|
27, // -- dunk/quench starts here
|
||||||
*/
|
30,
|
||||||
public static int findDx0Index(int goal, int init_dx1, int dx2_offset)
|
33,
|
||||||
|
37,
|
||||||
|
41,
|
||||||
|
45,
|
||||||
|
49,
|
||||||
|
53,
|
||||||
|
57,
|
||||||
|
62,
|
||||||
|
67,
|
||||||
|
72,
|
||||||
|
77,
|
||||||
|
83,
|
||||||
|
89,
|
||||||
|
95,
|
||||||
|
91, // last one will always overshoot 1000
|
||||||
|
};
|
||||||
|
public static final int MAX_INDEX = DX_1.length;
|
||||||
|
public static final int FAST_INDEX = 10;
|
||||||
|
|
||||||
|
@Value(staticConstructor = "of")
|
||||||
|
public static class SolveResult
|
||||||
{
|
{
|
||||||
|
int index;
|
||||||
|
int dx0;
|
||||||
|
int dx1;
|
||||||
|
int dx2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SolveResult heatingSolve(int start, int goal, boolean overshoot, int max, boolean isFast)
|
||||||
|
{
|
||||||
|
return relativeSolve(goal - start, overshoot, max - start, isFast, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SolveResult coolingSolve(int start, int goal, boolean overshoot, int min, boolean isFast)
|
||||||
|
{
|
||||||
|
return relativeSolve(start - goal, overshoot, start - min, isFast, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SolveResult relativeSolve(int goal, boolean overshoot, int max, boolean isFast, int decayValue)
|
||||||
|
{
|
||||||
|
|
||||||
|
int index = isFast ? FAST_INDEX : 0;
|
||||||
int dx0 = 0;
|
int dx0 = 0;
|
||||||
int dx1 = init_dx1;
|
|
||||||
int count_index = 0;
|
boolean decay = false;
|
||||||
for (int dx2 = 1; dx0 <= goal; dx2++)
|
|
||||||
{ // Start from 1 up to the count inclusive
|
while (true) {
|
||||||
int repetitions;
|
|
||||||
if (dx2 == 1)
|
if (index > MAX_INDEX)
|
||||||
{
|
{
|
||||||
repetitions = 2; // The first number appears twice
|
break;
|
||||||
}
|
}
|
||||||
else if (dx2 % 2 == 0)
|
|
||||||
|
if (!overshoot && dx0 + DX_1[index] > goal)
|
||||||
{
|
{
|
||||||
repetitions = 6; // Even numbers appear six times
|
break;
|
||||||
}
|
}
|
||||||
else
|
else if (overshoot && dx0 >= goal)
|
||||||
{
|
{
|
||||||
repetitions = 4; // Odd numbers (after 1) appear four times
|
break;
|
||||||
}
|
}
|
||||||
for (int j = 0; j < repetitions && dx0 <= goal; j++)
|
|
||||||
|
if (dx0 + DX_1[index] >= max)
|
||||||
{
|
{
|
||||||
dx0 += dx1;
|
break;
|
||||||
dx1 += dx2 + dx2_offset; // Sum the current number 'repetitions' times
|
|
||||||
count_index += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (decay)
|
||||||
|
{
|
||||||
|
dx0 -= decayValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dx0 += DX_1[index];
|
||||||
|
++index;
|
||||||
|
decay = !decay;
|
||||||
}
|
}
|
||||||
return count_index;
|
|
||||||
|
if (isFast)
|
||||||
|
{
|
||||||
|
index -= FAST_INDEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SolveResult.of(index, dx0, DX_1[index], -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
@Value(staticConstructor = "of")
|
||||||
* We can use the pattern to get the dx2 at a specific index numerically
|
public static class DurationResult
|
||||||
*
|
|
||||||
* @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;
|
int duration;
|
||||||
|
boolean goalInRange;
|
||||||
index -= 2;
|
boolean overshooting;
|
||||||
// 0 1 2 3 4 5 6 7 8 9
|
int predictedHeat;
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DurationResult solve(
|
||||||
/**
|
Stage stage,
|
||||||
* We can use the pattern to get the dx1 at a specific index numerically
|
int[] range,
|
||||||
*
|
int actionLeftInStage,
|
||||||
* @param index the index/tick we want to calculate the speed of heating/cooling
|
int start,
|
||||||
* @param constant the initial speed of heating/cooling.
|
boolean isFast,
|
||||||
* @return the speed of heating at index/tick
|
boolean isActionHeating,
|
||||||
*/
|
int padding)
|
||||||
public static int getDx1AtIndex(int index, int constant)
|
|
||||||
{
|
{
|
||||||
int _dx1 = constant;
|
|
||||||
for (int i = 0; i < index; ++i)
|
final boolean isStageHeating = stage.isHeating();
|
||||||
|
|
||||||
|
// adding 2.4s/8ticks worth of padding so preform doesn't decay out of range
|
||||||
|
// average distance from lava+waterfall around 8 ticks
|
||||||
|
// preform decays 1 heat every 2 ticks
|
||||||
|
final int min = Math.max(0, Math.min(1000, range[0] + padding));
|
||||||
|
final int max = Math.max(0, Math.min(1000, range[1] + padding));
|
||||||
|
|
||||||
|
final int actionsLeft_DeltaHeat = actionLeftInStage * stage.getHeatChange();
|
||||||
|
|
||||||
|
int estimatedDuration = 0;
|
||||||
|
|
||||||
|
final boolean goalInRange;
|
||||||
|
boolean overshoot = false;
|
||||||
|
|
||||||
|
SolveResult result = null;
|
||||||
|
|
||||||
|
// case actions are all cooling, heating is mirrored version
|
||||||
|
|
||||||
|
// goal: in-range // stage: heating
|
||||||
|
// overshoot goal
|
||||||
|
// <----------|stop|<---------------- heat
|
||||||
|
// ------|min|----------goal-------|max|
|
||||||
|
// stage ---------------->
|
||||||
|
|
||||||
|
// goal: out-range // stage: heating
|
||||||
|
// undershoot min
|
||||||
|
// ...----------|stop|<--------------------- heat
|
||||||
|
// -goal---|min|---------------------|max|
|
||||||
|
// stage ----------------->
|
||||||
|
|
||||||
|
// goal: in-range // stage: cooling
|
||||||
|
// undershoot goal
|
||||||
|
// <-------------------------|stop|<--------------- heat
|
||||||
|
// ------|min|----------goal-------|max|
|
||||||
|
// <---------------- stage
|
||||||
|
|
||||||
|
// goal: out-range // stage: cooling
|
||||||
|
// overshoot max
|
||||||
|
// <--------------------|stop|<--------------- heat
|
||||||
|
// --------|min|---------------------|max|----goal
|
||||||
|
// <---------------- stage
|
||||||
|
|
||||||
|
if (isActionHeating)
|
||||||
{
|
{
|
||||||
_dx1 += getDx2AtIndex(i);
|
int goal = min - actionsLeft_DeltaHeat;
|
||||||
|
goalInRange = goal >= min && goal <= max;
|
||||||
|
|
||||||
|
if (isStageHeating)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (start <= max)
|
||||||
|
{
|
||||||
|
overshoot = !goalInRange;
|
||||||
|
|
||||||
|
if (!goalInRange)
|
||||||
|
{
|
||||||
|
goal = min;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = heatingSolve(start, goal, overshoot, max, isFast);
|
||||||
|
|
||||||
|
estimatedDuration = result.index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // cooling stage
|
||||||
|
{
|
||||||
|
// actionsLeft_DeltaHeat is negative here
|
||||||
|
if (start <= max)
|
||||||
|
{
|
||||||
|
overshoot = goalInRange;
|
||||||
|
|
||||||
|
if (!goalInRange)
|
||||||
|
{
|
||||||
|
goal = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = heatingSolve(start, goal, overshoot, max, isFast);
|
||||||
|
|
||||||
|
estimatedDuration = result.index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // cooling action
|
||||||
|
{
|
||||||
|
int goal = max - actionsLeft_DeltaHeat;
|
||||||
|
goalInRange = goal >= min && goal <= max;
|
||||||
|
|
||||||
|
if (isStageHeating)
|
||||||
|
{
|
||||||
|
if (start >= min)
|
||||||
|
{
|
||||||
|
overshoot = goalInRange;
|
||||||
|
|
||||||
|
if (!goalInRange)
|
||||||
|
{
|
||||||
|
goal = min;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = coolingSolve(start, goal, overshoot, min, isFast);
|
||||||
|
|
||||||
|
estimatedDuration = result.index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // cooling stage cooling action
|
||||||
|
{
|
||||||
|
if (start >= min)
|
||||||
|
{
|
||||||
|
overshoot = !goalInRange;
|
||||||
|
if (!goalInRange)
|
||||||
|
{
|
||||||
|
goal = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = coolingSolve(start, goal, overshoot, min, isFast);
|
||||||
|
|
||||||
|
estimatedDuration = result.index;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _dx1;
|
int dx0 = result == null ? 0 : result.dx0;
|
||||||
|
if (!isActionHeating)
|
||||||
|
{
|
||||||
|
dx0 *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return DurationResult.of(estimatedDuration, goalInRange, overshoot, start + dx0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.toofifty.easygiantsfoundry;
|
package com.toofifty.easygiantsfoundry;
|
||||||
|
|
||||||
import com.toofifty.easygiantsfoundry.enums.Stage;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@@ -14,46 +13,45 @@ public class HeatActionStateMachine
|
|||||||
/**
|
/**
|
||||||
* Tick counter for heating, -1 means not currently heating.
|
* Tick counter for heating, -1 means not currently heating.
|
||||||
*/
|
*/
|
||||||
int HeatingTicks = -1;
|
int heatingTicks = -1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tick counter for cooling, -1 means not currently cooling.
|
* Tick counter for cooling, -1 means not currently cooling.
|
||||||
*/
|
*/
|
||||||
int CoolingTicks = -1;
|
int coolingTicks = -1;
|
||||||
|
|
||||||
/**
|
boolean actionFast;
|
||||||
* The velocity of the heating/cooling action.
|
|
||||||
*/
|
|
||||||
int Velocity;
|
|
||||||
|
|
||||||
/**
|
boolean actionHeating;
|
||||||
* The acceleration bonus of the heating/cooling action.
|
|
||||||
*/
|
|
||||||
int AccelerationBonus;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The starting heat amount of the heating/cooling action.
|
* The starting heat amount of the heating/cooling action.
|
||||||
*/
|
*/
|
||||||
int StartingHeat;
|
int startingHeat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The estimated tick duration of the heating/cooling action.
|
* The estimated tick duration of the heating/cooling action.
|
||||||
*/
|
*/
|
||||||
int EstimatedDuration;
|
int estimatedDuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The goal heat amount of the heating/cooling action.
|
* The goal heat amount of the heating/cooling action.
|
||||||
*/
|
*/
|
||||||
int GoalHeat = 0;
|
int goalHeat = 0;
|
||||||
|
|
||||||
|
// debug
|
||||||
|
boolean goalInRange;
|
||||||
|
boolean isOverShooting;
|
||||||
|
int predictedHeat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The last action the player clicked on. Used for ui overlay to display.
|
* The last action the player clicked on. Used for ui overlay to display.
|
||||||
* When null, the state-machine will stop() and reset.
|
* When null, the state-machine will stop() and reset.
|
||||||
*/
|
*/
|
||||||
String ActionName = null;
|
String actionname = null;
|
||||||
|
|
||||||
private EasyGiantsFoundryState State;
|
private EasyGiantsFoundryState state;
|
||||||
private EasyGiantsFoundryConfig Config;
|
private EasyGiantsFoundryConfig config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the state-machine with the given parameters.
|
* Start the state-machine with the given parameters.
|
||||||
@@ -64,26 +62,27 @@ public class HeatActionStateMachine
|
|||||||
* @param state the current state of the foundry
|
* @param state the current state of the foundry
|
||||||
* @param config the current configuration of the plugin
|
* @param config the current configuration of the plugin
|
||||||
* @param startingHeat the starting heat amount
|
* @param startingHeat the starting heat amount
|
||||||
* @see HeatActionStateMachine#setup(int, int, String)
|
* @see HeatActionStateMachine#setup(boolean, boolean, String)
|
||||||
*/
|
*/
|
||||||
public void start(EasyGiantsFoundryState state, EasyGiantsFoundryConfig config, int startingHeat)
|
public void start(EasyGiantsFoundryState state, EasyGiantsFoundryConfig config, int startingHeat)
|
||||||
{
|
{
|
||||||
// use Velocity to determine if heating or cooling
|
// use Velocity to determine if heating or cooling
|
||||||
if (Velocity > 0)
|
if (actionHeating)
|
||||||
{
|
{
|
||||||
HeatingTicks = 0;
|
heatingTicks = 0;
|
||||||
CoolingTicks = -1;
|
coolingTicks = -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CoolingTicks = 0;
|
heatingTicks = -1;
|
||||||
HeatingTicks = -1;
|
coolingTicks = 0;
|
||||||
}
|
}
|
||||||
StartingHeat = startingHeat - Velocity;
|
|
||||||
State = state;
|
|
||||||
Config = config;
|
|
||||||
|
|
||||||
calculateEstimates();
|
this.startingHeat = startingHeat;
|
||||||
|
this.state = state;
|
||||||
|
this.config = config;
|
||||||
|
|
||||||
|
updateEstimates();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -95,11 +94,11 @@ public class HeatActionStateMachine
|
|||||||
{
|
{
|
||||||
if (isHeating())
|
if (isHeating())
|
||||||
{
|
{
|
||||||
return Math.max(0, EstimatedDuration - HeatingTicks);
|
return Math.max(0, (estimatedDuration - heatingTicks));
|
||||||
}
|
}
|
||||||
else if (isCooling())
|
else if (isCooling())
|
||||||
{
|
{
|
||||||
return Math.max(0, EstimatedDuration - CoolingTicks);
|
return Math.max(0, (estimatedDuration - coolingTicks));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -111,125 +110,38 @@ public class HeatActionStateMachine
|
|||||||
* Core logic. Runs once on {@link HeatActionStateMachine#start} and assumes synchronization with the game.
|
* 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.
|
* Calculate the estimated duration and goal heat amount of the heating/cooling action.
|
||||||
*/
|
*/
|
||||||
public void calculateEstimates()
|
public void updateEstimates()
|
||||||
{
|
{
|
||||||
// 0: left/min 1: right/max
|
|
||||||
int[] range = State.getCurrentHeatRange();
|
|
||||||
int stageMin = range[0];
|
|
||||||
int stageMax = range[1];
|
|
||||||
|
|
||||||
Stage stage = State.getCurrentStage();
|
HeatActionSolver.DurationResult result =
|
||||||
int actionsLeft = State.getActionsLeftInStage();
|
HeatActionSolver.solve(
|
||||||
int actionsLeft_DeltaHeat = (actionsLeft+1) * stage.getHeatChange();
|
getState().getCurrentStage(),
|
||||||
if (isHeating())
|
getState().getCurrentHeatRange(),
|
||||||
{
|
getState().getActionsLeftInStage(),
|
||||||
if (stage.isHeating())
|
getStartingHeat(),
|
||||||
{
|
actionFast,
|
||||||
GoalHeat = Math.max(stageMin, stageMax - actionsLeft_DeltaHeat);
|
isHeating(),
|
||||||
if (StartingHeat < GoalHeat)
|
config.heatActionPadTicks() * 2
|
||||||
{
|
);
|
||||||
int duration = HeatActionSolver.findDx0Index(
|
|
||||||
GoalHeat - StartingHeat,
|
|
||||||
Velocity, AccelerationBonus
|
|
||||||
);
|
|
||||||
|
|
||||||
GoalHeat += duration / 2;
|
goalInRange = result.isGoalInRange();
|
||||||
|
isOverShooting = result.isOvershooting();
|
||||||
|
|
||||||
EstimatedDuration = HeatActionSolver.findDx0Index(
|
predictedHeat = result.getPredictedHeat();
|
||||||
GoalHeat - StartingHeat,
|
|
||||||
Velocity, AccelerationBonus
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else // overheating
|
|
||||||
{
|
|
||||||
EstimatedDuration = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // is cooling
|
|
||||||
{
|
|
||||||
// actionsLeft_DeltaHeat is negative here
|
|
||||||
GoalHeat = Math.min(stageMax, stageMin - actionsLeft_DeltaHeat);
|
|
||||||
if (StartingHeat < GoalHeat)
|
|
||||||
{
|
|
||||||
int duration = HeatActionSolver.findDx0Index(
|
|
||||||
GoalHeat - StartingHeat,
|
|
||||||
Velocity, AccelerationBonus
|
|
||||||
) - 1;
|
|
||||||
|
|
||||||
GoalHeat -= duration / 2;
|
estimatedDuration = result.getDuration();
|
||||||
|
|
||||||
EstimatedDuration = HeatActionSolver.findDx0Index(
|
|
||||||
GoalHeat - StartingHeat,
|
|
||||||
Velocity, AccelerationBonus
|
|
||||||
) - 1;
|
|
||||||
}
|
|
||||||
else // cold enough
|
|
||||||
{
|
|
||||||
EstimatedDuration = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (isCooling())
|
|
||||||
{
|
|
||||||
if (stage.isHeating()) {
|
|
||||||
GoalHeat = Math.max(stageMin, stageMax - actionsLeft_DeltaHeat);
|
|
||||||
if (StartingHeat > GoalHeat)
|
|
||||||
{
|
|
||||||
int duration = HeatActionSolver.findDx0Index(
|
|
||||||
StartingHeat - GoalHeat,
|
|
||||||
Math.abs(Velocity), Math.abs(AccelerationBonus)
|
|
||||||
) - 1;
|
|
||||||
|
|
||||||
GoalHeat += duration / 2;
|
|
||||||
|
|
||||||
EstimatedDuration = HeatActionSolver.findDx0Index(
|
|
||||||
(StartingHeat - GoalHeat),
|
|
||||||
Math.abs(Velocity), Math.abs(AccelerationBonus)
|
|
||||||
) - 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EstimatedDuration = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Heating Stage
|
|
||||||
else {
|
|
||||||
GoalHeat = Math.max(stageMax, stageMin + actionsLeft_DeltaHeat);
|
|
||||||
if (StartingHeat > GoalHeat) // too hot
|
|
||||||
{
|
|
||||||
int duration = HeatActionSolver.findDx0Index(
|
|
||||||
StartingHeat - GoalHeat,
|
|
||||||
Math.abs(Velocity), Math.abs(AccelerationBonus)
|
|
||||||
);
|
|
||||||
|
|
||||||
GoalHeat -= duration / 2;
|
|
||||||
|
|
||||||
EstimatedDuration = HeatActionSolver.findDx0Index(
|
|
||||||
StartingHeat - GoalHeat,
|
|
||||||
Math.abs(Velocity), Math.abs(AccelerationBonus)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else // hot enough
|
|
||||||
{
|
|
||||||
EstimatedDuration = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to remind the neccessary parameters to start the state-machine.
|
* 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
|
* @param actionName the name of the action to display in the ui overlay
|
||||||
*/
|
*/
|
||||||
public void setup(int velocity, int accelerationBonus, String actionName)
|
public void setup(boolean isFast, boolean isHeating, String actionName)
|
||||||
{
|
{
|
||||||
Velocity = velocity;
|
actionFast = isFast;
|
||||||
AccelerationBonus = accelerationBonus;
|
actionHeating = isHeating;
|
||||||
ActionName = actionName;
|
actionname = actionName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -237,9 +149,9 @@ public class HeatActionStateMachine
|
|||||||
*/
|
*/
|
||||||
public void stop()
|
public void stop()
|
||||||
{
|
{
|
||||||
HeatingTicks = -1;
|
heatingTicks = -1;
|
||||||
CoolingTicks = -1;
|
coolingTicks = -1;
|
||||||
ActionName = null;
|
actionname = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -249,7 +161,7 @@ public class HeatActionStateMachine
|
|||||||
*/
|
*/
|
||||||
public boolean isHeating()
|
public boolean isHeating()
|
||||||
{
|
{
|
||||||
return HeatingTicks >= 0;
|
return heatingTicks >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -259,7 +171,7 @@ public class HeatActionStateMachine
|
|||||||
*/
|
*/
|
||||||
public boolean isCooling()
|
public boolean isCooling()
|
||||||
{
|
{
|
||||||
return CoolingTicks >= 0;
|
return coolingTicks >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -277,25 +189,30 @@ public class HeatActionStateMachine
|
|||||||
*/
|
*/
|
||||||
public void onTick()
|
public void onTick()
|
||||||
{
|
{
|
||||||
|
if (isIdle()) return;
|
||||||
|
|
||||||
if (isHeating())
|
if (isHeating())
|
||||||
{
|
{
|
||||||
HeatingTicks++;
|
if (heatingTicks >= estimatedDuration)
|
||||||
if (HeatingTicks >= EstimatedDuration)
|
|
||||||
{
|
{
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
heatingTicks++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (isCooling())
|
else if (isCooling())
|
||||||
{
|
{
|
||||||
CoolingTicks++;
|
if (coolingTicks >= estimatedDuration)
|
||||||
if (CoolingTicks >= EstimatedDuration)
|
|
||||||
{
|
{
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
coolingTicks++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// log.info("\nReal Heat: " + State.getHeatAmount()
|
|
||||||
// + "\nGoal Heat - StartingHeat: " + (GoalHeat - StartingHeat)
|
|
||||||
// + "\nDuration: " + EstimatedDuration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ public class MouldHelper
|
|||||||
int height = scrollList.getHeight();
|
int height = scrollList.getHeight();
|
||||||
int scrollMax = scrollList.getScrollHeight();
|
int scrollMax = scrollList.getScrollHeight();
|
||||||
Widget finalBestWidget = bestWidget;
|
Widget finalBestWidget = bestWidget;
|
||||||
clientThread.invokeLater(() ->
|
clientThread.invokeAtTickEnd(() ->
|
||||||
{
|
{
|
||||||
if (finalBestWidget != null)
|
if (finalBestWidget != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,180 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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(957, 27, 2));
|
|
||||||
// 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 for index " + 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user