Lol_marcus Posted March 6, 2021 Share Posted March 6, 2021 Hi guys, I've tried doing this without states and enums, and then thought that maybe it would be easier doing it with them. I'm trying to make an incremental alcher, basically what it does is it buys an X amount of a certain item, alches it, and then buys an X amount of another item. The reason is that I don't want to (nor can I afford on multiple accounts) to buy the limit of a lot of alches at one time, like rune items, etc. So the script should: if 0 alches for item 1 buy item 1 alch item 1 if X alches for item 1 is done buy item 2 alch item 2 if X alches for item 1 & 2 done buy item 3 alch item 3 Any guidance would be fantastic. Here's what I have, but I can't for the life of me get it to work: package core; import org.osbot.rs07.api.GrandExchange; import org.osbot.rs07.api.Magic; import org.osbot.rs07.api.model.NPC; import org.osbot.rs07.api.model.Player; import org.osbot.rs07.api.model.RS2Object; import org.osbot.rs07.api.ui.MagicSpell; import org.osbot.rs07.api.ui.Spells; import org.osbot.rs07.input.mouse.RectangleDestination; import org.osbot.rs07.script.Script; import org.osbot.rs07.script.ScriptManifest; import org.osbot.rs07.utility.Condition; import org.osbot.rs07.utility.ConditionalSleep; import java.awt.*; @ScriptManifest(name = "Incremental Alcher", version = 1, author = "Marcus", logo = "", info = "Buys items in increments to high alch.") public class Main extends Script { private long startTime = System.currentTimeMillis(); int rune2h; int runepl8; int runelegs; @Override public void onStart() throws InterruptedException { rune2h = 0; runepl8 = 0; runelegs = 0; } private enum State { BUY_R2H, ALCH_R2H, BUY_RPL8, ALCH_RPL8, EXIT } private State getState() { if (rune2h == 0 && !getInventory().contains("Rune 2h Sword")) return State.BUY_R2H; if (rune2h == 0 && getInventory().contains("Rune 2h Sword")) return State.ALCH_R2H; if (rune2h == 2 && runepl8 == 0 && !getInventory().contains("Rune platebody")) return State.BUY_RPL8; if (rune2h == 2 && runepl8 == 0 && getInventory().contains("Rune platebody")) return State.ALCH_RPL8; return State.EXIT; } @Override public int onLoop() throws InterruptedException { switch (getState()) { case BUY_R2H: buyRune2h(); break; case ALCH_R2H: alchR2h(); break; case BUY_RPL8: buyRunepl8(); break; case ALCH_RPL8: alchRpl8(); break; case EXIT: stop(false); break; } return 700; } public void buyRune2h() throws InterruptedException { NPC clerk = getNpcs().closest("Grand Exchange clerk"); if (clerk != null && clerk.isVisible()) { clerk.interact("Exchange"); Sleep.sleepUntil(() -> grandExchange.isOpen(), 5000); grandExchange.buyItem(1319, "Rune 2h", 38000, 2); Sleep.sleepUntil( () -> (grandExchange.getStatus(GrandExchange.Box.BOX_1) == GrandExchange.Status.FINISHED_BUY), 5000); grandExchange.collect(false); Sleep.sleepUntil(() -> (grandExchange.getStatus(GrandExchange.Box.BOX_1) == GrandExchange.Status.EMPTY), 5000); } } public void alchR2h() throws InterruptedException { while (getInventory().contains("Rune 2h Sword")) { if (!getPlayers().myPlayer().isAnimating()) { magic.castSpell(Spells.NormalSpells.HIGH_LEVEL_ALCHEMY); Sleep.sleepUntil(() -> magic.isSpellSelected(), 5000); getInventory().interact("cast", "Rune 2h Sword"); rune2h =+ 1; } } } public void buyRunepl8() throws InterruptedException { NPC clerk = getNpcs().closest("Grand Exchange clerk"); if (clerk != null && clerk.isVisible()) { clerk.interact("Exchange"); Sleep.sleepUntil(() -> grandExchange.isOpen(), 5000); grandExchange.buyItem(1127, "Rune plate", 38500, 2); Sleep.sleepUntil( () -> (grandExchange.getStatus(GrandExchange.Box.BOX_1) == GrandExchange.Status.FINISHED_BUY), 5000); grandExchange.collect(false); Sleep.sleepUntil(() -> (grandExchange.getStatus(GrandExchange.Box.BOX_1) == GrandExchange.Status.EMPTY), 5000); } } public void alchRpl8() throws InterruptedException { if (getInventory().contains("Rune platebody")) { if (!getPlayers().myPlayer().isAnimating()) { magic.castSpell(Spells.NormalSpells.HIGH_LEVEL_ALCHEMY); Sleep.sleepUntil(() -> magic.isSpellSelected(), 5000); getInventory().interact("cast", "Rune platebody"); runepl8 =+ 1; } } } @Override public void onPaint(Graphics2D g) { g.setColor(new Color(0, 0, 0, 155)); g.fillRect(5, 258, 200, 80); g.setColor(new Color(255, 255, 255)); g.drawRect(5, 258, 200, 80); super.onPaint(g); g.drawString("Essence Runner", 65, 275); g.drawString("Run time: " + String.valueOf(formatTime(System.currentTimeMillis() - startTime)), 15, 295); g.drawString("Rune 2h Alches: " + rune2h, 15, 305); g.drawString("Rune Platebody Alches: " + runepl8, 15, 320); } private String formatTime(final long ms) { long s = ms / 1000, m = s / 60, h = m / 60; s %= 60; m %= 60; h %= 24; return String.format("%02d:%02d:%02d", h, m, s); } } Quote Link to comment Share on other sites More sharing options...
skillerkidos1 Posted March 6, 2021 Share Posted March 6, 2021 (edited) for not using states all you have to do is like private boolean alch1 = true; private boolean alch2 = false; private boolean buy1 = false; private boolean buy2 = false; @Override public int onLoop() throws InterruptedException { if (alch1) { if (!buy1 && !getInventory().contains("Rune longsword")) { //buy from ge buy1 = true; } else if (getInventory().contains("Rune longsword")) { //alch } else { alch1 = false; buy1 = false; alch2 = true; } } if (!buy2 && !getInventory().contains("Rune full helm")) { //buy from ge buy2 = true; } else if (getInventory().contains("Rune full helm")) { //alch } else { alch2 = false; buy2 = false; alch1 = true; } return 1000; //The amount of time in milliseconds before the loop starts over } maybe? Edited March 7, 2021 by skillerkidos1 Quote Link to comment Share on other sites More sharing options...
PTY Botting Posted March 7, 2021 Share Posted March 7, 2021 So much duplicated code, I think you need to try break it down more. There are 3 states Alching Buying Exiting There are X Number of items which you are iterating in order Rune2h -> Rune Plate -> Rune Legs Heres is what I would try to do Create an array which which holds the data for the item I wish to alch(Only name right now, but could hold things such as Times alched etc) The initial state would be alching until no items buy items (Trigger a flag saying bought items for current item once done) alch until done Switch the reference to the index of the array(Reset bought flag etc) continue until x number of items done reset index to 0, repeat. Using this way of having the current item stored in an array you can reduce duplicated code y taking a parameter into the method EG public void alchRpl8() throws InterruptedException { if (getInventory().contains("Rune platebody")) { if (!getPlayers().myPlayer().isAnimating()) { magic.castSpell(Spells.NormalSpells.HIGH_LEVEL_ALCHEMY); Sleep.sleepUntil(() -> magic.isSpellSelected(), 5000); getInventory().interact("cast", "Rune platebody"); runepl8 =+ 1; } } } could become public void alchItem(String itemName) throws InterruptedException { if (getInventory().contains(itemName)) { if (!getPlayers().myPlayer().isAnimating()) { magic.castSpell(Spells.NormalSpells.HIGH_LEVEL_ALCHEMY); Sleep.sleepUntil(() -> magic.isSpellSelected(), 5000); getInventory().interact("cast", itemName); } } } That way you don't need a separate method for each item you wish to alch Quote Link to comment Share on other sites More sharing options...
BravoTaco Posted March 7, 2021 Share Posted March 7, 2021 (edited) I wrote up a quick example script. Not everything is implemented I left the buyItem() method blank so that you can implement that. It uses an Array of strings for the different items to alch, and a HashMap<String, Integer> that holds the alched count for each item. If you have any questions let me know. Also this code is untested. So it may be broken public class UCAlcher extends Script { private BotState botState; // This is used to keep track of how many of each item that can be alched, has been alched. private final HashMap<String, Integer> alchsMap = new HashMap<>(); // The different items you want to alch. private final String[] itemNames = new String[]{"Rune 2h Sword", "Rune platebody", "Rune platelegs"}; // This value represents how many items will be alched/bought for each item. private int alchLimitForEachItem = 2; private String currentAlchItemName; @Override public void onStart() throws InterruptedException { // Initialize the HashMap with the values from the itemNames array. for (String s : itemNames) { alchsMap.put(s, 0); } } @Override public int onLoop() throws InterruptedException { botState = setBotState(); if (botState != null) { switch (botState) { case ALCH_ITEM: { alchItem(); } case BUY_ITEM: { buyItem(); } } } else { warn("The botState is null."); stop(false); } return random(800, 3600); } private BotState setBotState() { currentAlchItemName = null; // for (Item item : getInventory().getItems()) { if (item != null && alchsMap.containsKey(item.getName()) && alchsMap.get(item.getName()) < alchLimitForEachItem) { currentAlchItemName = item.getName(); return BotState.ALCH_ITEM; } } // If the currentAlchItemName is null here than that means we need to possibly buy a new item to alch // or we need to reset the alch count on each item. if (currentAlchItemName == null) { for (String s : alchsMap.keySet()) { if (alchsMap.get(s) < alchLimitForEachItem) { currentAlchItemName = s; return BotState.BUY_ITEM; } } } // If the currentAlchItemName is still null than that means we have bought and alched all items. // So now we have to reset the alch count on each item and set the currentAlchItemName to the first index in the itemNames array. if (currentAlchItemName == null) { for (String s : alchsMap.keySet()) { alchsMap.replace(s, 0); } currentAlchItemName = itemNames[0]; return BotState.BUY_ITEM; } return null; } private void buyItem() { // Implement the buying of the item here. } private void alchItem() throws InterruptedException { Item alchItem = getInventory().getItem(currentAlchItemName); if (alchItem != null) { if (getMagic().canCast(Spells.NormalSpells.HIGH_LEVEL_ALCHEMY)) { if (getMagic().castSpell(Spells.NormalSpells.HIGH_LEVEL_ALCHEMY)) { if (sleepUntil(() -> alchItem.interact("cast"), 5000, 20)) { alchsMap.replace(currentAlchItemName, alchsMap.get(currentAlchItemName) + 1); } else { warn("Unable to alch item."); } } } else { warn("Unable to cast high level alchemy. Stopping script."); stop(false); } } else { warn("The inventory does not contain the required item to alch. Something must have gone wrong when calculating the botState."); } } private boolean sleepUntil(BooleanSupplier condition, int maxTime, int checkInterval) throws InterruptedException { long startTime = System.currentTimeMillis(); while (System.currentTimeMillis() - startTime < maxTime) { if (condition.getAsBoolean()) { return true; } Thread.sleep(checkInterval); } return false; } private enum BotState { BUY_ITEM, ALCH_ITEM } } Edited March 7, 2021 by BravoTaco Quote Link to comment Share on other sites More sharing options...