Jump to content

Switching states for incremental alcher script [Help please]


Lol_marcus

Recommended Posts

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);
	}
}

 

Link to comment
Share on other sites

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 by skillerkidos1
Link to comment
Share on other sites

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
 

Link to comment
Share on other sites

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 by BravoTaco
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...