The client is offline due to RuneScape update. You may see instance errors but this is due to the update and not actual instance errors. This should be resolved soon. Join our Discord for more information.

My first script attempt need pointers

  • Hello all,

    Been reading a few posts on the forums and found good informations to help me start.
    Now I have this simple Cannonball smelter script project that is my first goal and I am kind of stuck in my logic.

    If you will, please provide me with any pointers on how to make this kind of script work well. This is messing up at a few places and I can't get my hand on precise info to help my noob head understand the missing aspects.

    So here is my script project :

    import org.rspeer.runetek.adapter.scene.Player;
    import org.rspeer.runetek.adapter.scene.SceneObject;
    import org.rspeer.runetek.api.commons.Time;
    import org.rspeer.runetek.api.component.Bank;
    import org.rspeer.runetek.api.component.Production;
    import org.rspeer.runetek.api.movement.Movement;
    import org.rspeer.runetek.api.movement.position.Area;
    import org.rspeer.runetek.api.scene.Npcs;
    import org.rspeer.runetek.api.scene.Players;
    import org.rspeer.runetek.api.scene.SceneObjects;
    import org.rspeer.script.Script;
    import org.rspeer.script.ScriptMeta;
    import org.rspeer.script.ScriptCategory;
    import org.rspeer.ui.Log;
    @ScriptMeta(name = "DCannonballer",  desc = "Smelts cannon balls in Edgeville.", developer = "Alex1234567", category = ScriptCategory.SMITHING)
    public class DCannonballer extends Script {
    private static final Area BANK_AREA = Area.rectangular(3095,3496, 3098, 3494); //makes a rectangular area of all the tiles from the first tile that's most northern and western to the tile that is most southern and eastern
    private static final Area FURNACE_AREA = Area.rectangular(3105, 3499, 3108, 3497);
    private boolean MakingCannonballs = false;
       // @Override
        public void onStart() {
            //When the script is first started the segment of code in this method will be ran once.
            MakingCannonballs = false;
        public int loop() {
            //Code in here starting from the top-down will be ran and repeated.
            Player local = Players.getLocal(); //my runescape character
            //if player not moving and not interacting {
            if (!local.isMoving() && !local.isAnimating()) {
                //if inventory has Steel bars and a mould {
                if (Inventory.contains("Ammo mould") && Inventory.contains("Steel bar")) {
                    //if I'm at the furnace
                    if (FURNACE_AREA.contains(local) && !MakingCannonballs) {
                        //Smelt all Steel bars available (make cannonballs)
                        SceneObject Furnace = SceneObjects.getNearest("Furnace");
              "Interacted with furnace to pop-up Smelting actions menu");
                        Time.sleep(500, 700); //account for possible in-game lag
                        if (Production.isOpen()) {
                            Time.sleep(10, 200);
                            MakingCannonballs = true;
                  "Started making cannonballs...");
                            Time.sleep(20, 40);
                    } else if (!MakingCannonballs) {
                        //Walk to furnace
              "Walking to furnace's area");
                        Time.sleep(500, 4000);
                } else {
                    MakingCannonballs = false;
                    //if I'm at the bank {
                    if (BANK_AREA.contains(local)) {
                        if (!Bank.isOpen()) {
                            SceneObject Bank_booth = SceneObjects.getNearest("Bank booth");
                  "Opening RS bank account.");
                            Time.sleep(300, 600);
                        } else if(Bank.isOpen()) {
                            //if mould or Steel bars are not found in the bank, stop script
                            if (!Bank.contains("Ammo mould") || !Bank.contains("Steel bar")) {
                                // stop script
                      "Ammo mould and/or Steel bars not found in bank - Stopping script.");
                                // !!!
                            } else {
                                if (!Inventory.isEmpty()) {
                                    //empty inventory before withdrawing mould and steel bars
                                    Time.sleep(200, 400);
                                //if mould not in inventory already
                                if (!Inventory.contains("Ammo mould")) {
                                    // Withdraw mould
                                    Bank.withdraw("Ammo mould", 1);
                                    Time.sleep(200, 400);
                                //Withdraw Steel bars
                                Bank.withdrawAll("Steel bar");
                                Time.sleep(300, 500);
                                if (Inventory.contains("Ammo mould") && Inventory.contains("Steel bar")) {
                          "We banked and are now ready to go smelting cannonballs.");
                                    Time.sleep(10, 700);
                                } else {
                                    // stop script
                          "Oops, inventory does not contain mould and Steel bars after interacting with the bank - Stopping script.");
                                    // !!!
                    } else {
                        //Walk to bank
            } else {
                // Running mode
                if (!Movement.isRunEnabled() && Movement.getRunEnergy() > 40 && !Bank.isOpen()) {
          "Player's energy is above 40, run mode activated.");
            return 1000; // The rate of repeat is defined by the returning int, this number represents milliseconds. 1000ms = 1 second.
        public void onStop() {
            //When the script is stopped the segment of code in this method will be ran once.
  "Script successfully stopped.");

    Thanks in advance for any tip

  • Script Writer

    I highly suggest consolidating everything you've thrown into loop into concise working sets. This could be done through use of either smaller private methods within this class, or better yet - a structure that would contain the logic and flow of your script (Iterable, Graph, etc.)

    The downside would be having to restructure all of your current work; however, you'll be able to read your code much more efficiently and if you happen to encounter any wonky bugs, it'll be easier to pinpoint the working set that would be causing your issue.

  • Thank you for your time and reply I appreciate it.
    Do you have a link in mind that could illustrate this ?
    I'm new to RSPeer AND Java so I'm not able to make a picture of your suggestion.

    Do you mean individual files, or another kind of coding style ?

  • Script Writer

    As a first step, I'd do a bit of reading through the RSPeer documentation to make good use of the already-existing iterative implementation.

    TaskScript already extends the Script class - the Script class, which is what I assume you are currently extending from your main class.
    I'd have you look into its functionality, how you can submit tasks, how a Task is defined in the API, and making your own Tasks.

  • Interesting man... I did not know about TaskScript. I basically followed other user's examples which were extending script class. So I'll keep on reading forum posts and try to get around the JavaDocs (whats hard is that there are no friendly examples. EDIT: in the docs).
    Thanks for the tips.

  • Script Writer

    Hey man,

    I quickly skimmed your code and have a couple of pointers...

    1. You need to leave the @Override uncommented for onStart() to work as expected. Not a big deal as currently it looks like it's redundant (the value you're setting is already false)

    2. variables that are not static final should be like this: makingCannonballs instead of this MakingCannonBalls

    3. as dungeon mentioned try to simplify and break apart your loop method. The easiest to implement in this script would be creating a validation method and an execute method for each step. Something like the below.

    public int loop() {
         if(shouldBank()) {    
         return 250;
    private boolean shouldBank() {
         // Validates banking
         return !Inventory.containsAll("Ammo mould", "Steel bar");
    private void bank() {
         // Does banking stuff

  • @2147M Wow. Ok, this is helping me a lot to understand. I'm really a visual learner. Thanks so much and I agree that it would end-up being cleaner and easier to maintain.

    I'll be testing out things based on that

    thank you very much

  • Script Writer