Jump to content
View in the app

A better way to browse. Learn more.

OSBot :: 2007 OSRS Botting

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

[Snippet] My Fairy Ring Handler

Featured Replies

Decided that I don't want to use webwalking for fairy rings in a script of mine, so I made my own handler. This will efficiently use fairy rings. I gave it a few tests and didn't find any problems. If you do encounter any issue do tell me. Criticism welcome :)

What it does do:

  • Retrieve nearby fairy ring
  • Check for staff equipped/diary completion
  • Use last destination if possible
  • Open fairy rings for configuration if needed
  • Use the travel log to configure code, if the needed code is among the top (like favorited codes)
  • Efficiently set the code using both the clockwise and the counter-clockwise rotators
  • Confirm selection
  • Return if teleported successfully (based on animation, not location. Can be easily changed)

What it doesn't do:

  • Check for specific fairy ring requirements
  • Attempt to equip a staff, even if it's in the inventory
  • Find you love

Example:

FairyRing fairyTravel = new FairyRing(getBot().getMethods());
/*some code
...
*/
fairyTravel.teleTo("DIS"); //If a fairy ring is nearby it will use it and teleport to the ring near Wizards' Tower

//Alternatively:
fairyTravel.teleTo(WIZARDSTOWER); // Will do the same as using the code "DIS"


FairyRing preview:

Spoiler

import org.osbot.rs07.api.Diaries;
import org.osbot.rs07.api.model.Entity;
import org.osbot.rs07.api.model.Item;
import org.osbot.rs07.api.ui.EquipmentSlot;
import org.osbot.rs07.api.ui.RS2Widget;
import org.osbot.rs07.script.MethodProvider;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;

import static org.osbot.rs07.script.MethodProvider.random;

public class FairyRing {
    private final MethodProvider api;
    private final HashMap<String, Integer> indexByLetter;
    private final HashMap<Integer, String> letterByIndex;
    private final Comparator<RS2Widget> widgetXComparator = Comparator.comparingInt(RS2Widget::getAbsX);
    private final WidgetActionFilter leftFilter = new WidgetActionFilter("Rotate counter-clockwise");
    private final WidgetActionFilter rightFilter = new WidgetActionFilter("Rotate clockwise");
    private final WidgetActionFilter confirmFilter = new WidgetActionFilter("Confirm");

    public FairyRing (MethodProvider api) {
        this.api = api;
        indexByLetter = new HashMap<>();
        letterByIndex = new HashMap<>();
        String[] letters = new String[]{"A", "D", "C", "B", "I", "L", "K", "J", "P", "S", "R", "Q"};
        for (int i = 0; i < letters.length; i++) {
            indexByLetter.put(letters[i], i);
            letterByIndex.put(i, letters[i]);
        }
    }

    public boolean isOpen() {
        return api.getWidgets().singleFilter(leftFilter) != null;
    }

    public boolean open() {
        return getFairyRing().interact("Configure");
    }

    private String getCurrentCode() {
        if (isOpen()) {
            return convertCodeIDToString();
        } else {
            return null;
        }
    }

    public Entity getFairyRing() {
        Entity ring = api.getObjects().closest("Fairy ring");
        if (ring != null && ring.isVisible()) {
            return ring;
        } else {
            return null;
        }
    }

    public boolean teleTo(Destination dest) {
        return teleTo(dest.code);
    }

    public boolean teleTo(String code) {
        Entity ring = getFairyRing();
        if (ring != null && code != null && canUseRing()) {
            if (!isOpen()) {
                if (code.equals(Destination.ZANARIS.code)) {
                    return teleToZanaris();
                } else if (isLastDest(code)){
                    return teleToLastDest();
                } else if (open()) {
                    Sleep.sleepUntil(this::isOpen, random(7000, 10000));
                }
            }
            if (isOpen()) {
                if (getCurrentCode() != null && !getCurrentCode().equals(code)) {
                    configureCode(code);
                }
                if (getCurrentCode() != null && getCurrentCode().equals(code) && confirm()) {
                    return waitForTele();
                }
            }
        }
        return false;
    }

    private boolean canUseRing() {
        return isStaffEquipped() || isDiaryComplete();
    }

    private boolean isDiaryComplete() {
        return api.getDiaries().isComplete(Diaries.Diary.LUMBRIDGE_ELITE);
    }

    private boolean isStaffEquipped() {
        Item weapon = api.getEquipment().getItemInSlot(EquipmentSlot.WEAPON.slot);
        if (weapon != null) {
            String weaponName = weapon.getName();
            return weaponName.equals("Dramen staff") || weaponName.equals("Lunar staff");
        } else {
            return false;
        }
    }

    private boolean confirm() {
        RS2Widget confirmButton = api.getWidgets().singleFilter(confirmFilter);
        return confirmButton != null && confirmButton.interact("Confirm");
    }

    private void configureCode(String code) {
        RS2Widget reuseWidg = getCodeFromLog(addSpaces(code));
        if (reuseWidg != null) {
            if (reuseWidg.interact("Use code")) {
                Sleep.sleepUntil(() -> isCodeSet(code), random(1000, 2000));
            }
        } else {
            for (int i = 0; i < 3; i++) {
                String currentLetter = getLetterAtIndex(i);
                String wantedLetter = ""+code.charAt(i);
                if (!currentLetter.equals(wantedLetter)) {
                    int rotations = 2 + (getLetterMapIndex(currentLetter) - getLetterMapIndex(wantedLetter));
                    if (rotations == 0) {
                        rotations = (random(2) == 1? 2 : -2);
                    }
                    rotateBy(i, rotations, code);
                }
            }
            Sleep.sleepUntil(() -> isCodeSet(code), random(500, 1000));
        }
    }

    private RS2Widget getCodeFromLog(String code) {
        RS2Widget reuseWidg = api.getWidgets().getWidgetContainingText(code);
        if (reuseWidg != null && canClickCode(reuseWidg)) {
            return reuseWidg;
        } else {
            return null;
        }
    }

    private void rotateBy(int letterIndex, int amount, String code) {
        WidgetActionFilter sideFilter = (amount > 0 ? rightFilter : leftFilter);
        amount = Math.abs(amount);
        RS2Widget rotator = getRotator(letterIndex, sideFilter);
        if (rotator != null) {
            for (int i=0; i<amount; i++) {
                if (rotator.interact(sideFilter.getAction())) {
                    Sleep.sleepUntil(() -> isCodeSet(code), random(100, 200));
                }
            }
        }
    }

    private RS2Widget getRotator(int letterIndex, WidgetActionFilter sideFilter) {
        List<RS2Widget> rotators = api.getWidgets().filter(sideFilter);
        if (rotators != null && letterIndex < rotators.size()) {
            rotators.sort(widgetXComparator);
            return rotators.get(letterIndex);
        } else {
            return null;
        }
    }

    private String addSpaces(String code) {
        return code.replace("", " ").trim();
    }

    private boolean canClickCode(RS2Widget reuseWidg) {
        RS2Widget logWidg = api.getWidgets().getWidgetContainingText("Travel log");
        int minY = logWidg.getAbsY() + logWidg.getHeight();
        int maxY = minY + 200;
        int minX = logWidg.getAbsX();
        int codeY = reuseWidg.getAbsY();
        return codeY >= minY && codeY <= maxY && reuseWidg.getAbsX() >= minX;
    }

    private boolean isCodeSet(String code) {
        return getCurrentCode() != null && getCurrentCode().equals(code);
    }

    private boolean isLastDest(String code) {
        return getLastDest() != null && getLastDest().contains(code);
    }

    private boolean teleToLastDest() {
        Entity ring = getFairyRing();
        if (ring.interact(getLastDest())) {
            return waitForTele();
        } else {
            return false;
        }
    }

    private String getLastDest() {
        Entity ring = getFairyRing();
        for (String action : ring.getActions()) {
            if (action != null && action.length() > 0 && action.contains("Last-destination (")) {
                return action;
            }
        }
        return null;
    }

    private boolean waitForTele() {
        boolean startedTele = false;
        Sleep.sleepUntil(() -> api.myPlayer().getAnimation() == 3265, random(3000, 5000));
        if (api.myPlayer().getAnimation() == 3265) {
            startedTele = true;
            Sleep.sleepUntil(() -> api.myPlayer().getAnimation() == -1, random(7000, 10000));
        }
        return startedTele;
    }

    private boolean teleToZanaris() {
        Entity ring = api.getObjects().closest("Fairy ring");
        if (ring.hasAction("Zanaris")) {
            if (ring.interact("Zanaris")) {
                Sleep.sleepUntil(this::isNearFixit, random(7000, 10000));
            }
        }
        return isNearFixit();
    }

    public boolean isNearFixit() {
        return api.getNpcs().closest("Fairy Fixit") != null;
    }

    private String convertCodeIDToString() {
        return convertCodeIDToString(api.getConfigs().get(816));
    }

    private String convertCodeIDToString(int codeID) {
        StringBuilder code = new StringBuilder();
        for (int i=0; i<3; i++) {
            code.append(getLetterAtIndex(i, codeID));
        }
        return code.toString();
    }

    private String getLetterAtIndex(int index) {
        return getLetterAtIndex(index, api.getConfigs().get(816));
    }

    private String getLetterAtIndex(int index, int codeID) {
        return letterByIndex.get(4*index + ((codeID / (int) Math.pow(4, index)) % 4));
    }

    private int getLetterMapIndex(String letter) {
        return indexByLetter.get(letter);
    }
}

enum Destination {
    MUDSKIPPER("AIQ"),
    ARDOUGNEISLAND("AIR"),
    DORGESHKAAN("AJQ"),
    RELLEKACAVE("AJR"),
    PENGUINS("AJS"),
    PISCATORIS("AKQ"),
    FELDIPHUNTER("AKS"),
    LIGHTHOUSE("ALP"),
    HAUNTEDWOODS("ALQ"),
    ABYSSALAREA("ALR"),
    MCGRUBOR("ALS"),
    MORTMYREISLAND("BIP"),
    KALPHITELAIR("BIQ"),
    ARDOUGNEZOO("BIS"),
    FISHERKING("BJR"),
    ZULANDRA("BJS"),
    CASTLEWARSSOUTH("BKP"),
    ENCHANTEDVALLEY("BKQ"),
    MORTMYRESWAMP("BKR"),
    ZANARIS("BKS"),
    TZHAAR("BLP"),
    LEGENDSGUILD("BLR"),
    MISCELLANIA("CIP"),
    YANILLE("CIQ"),
    MOUNTKARUULM("CIR"),
    ARCEUSSLIBRARY("CIS"),
    SINCLAIRMANSION("CJR"),
    COSMICENTITY("CKP"),
    TAIBWOWANNAISOUTH("CKR"),
    CANIFIS("CKS"),
    DRAYNORISLAND("CLP"),
    APEATOLL("CLR"),
    HAZELMEREHOME("CLS"),
    ABYSSALNEXUS("DIP"),
    PLAYERGARDEN("DIQ"),
    GORAKSPLANE("DIR"),
    WIZARDSTOWER("DIS"),
    TOWEROFLIFE("DJP"),
    CHASMOFFIRE("DJR"),
    MUSAPOINTSOUTH("DKP"),
    EDGEVILLE("DKR"),
    POLARAREA("DKS"),
    NARDAHNORTH("DLQ"),
    POISONWASTE("DLR"),
    MYREQUEHIDEOUT("DLS");
    public String code;

    Destination(String code) {
        this.code = code;
    }
}

 

 

Sleep (made not by me) preview:

Spoiler


import org.osbot.rs07.utility.ConditionalSleep;
import java.util.function.BooleanSupplier;

class Sleep extends ConditionalSleep {
    private final BooleanSupplier condition;

    public Sleep(final BooleanSupplier condition, final int timeout) {
        super(timeout);
        this.condition = condition;
    }

    @Override
    public final boolean condition() {
        return condition.getAsBoolean();
    }

    public static boolean sleepUntil(final BooleanSupplier condition, final int timeout) {
        return new Sleep(condition, timeout).sleep();
    }
}

 


WidgetActionFilter preview:

Spoiler


import org.osbot.rs07.api.filter.Filter;
import org.osbot.rs07.api.ui.RS2Widget;

public class WidgetActionFilter implements Filter<RS2Widget> {

    private final String action;

    public WidgetActionFilter(String filter) {
        this.action = filter;
    }

    @Override
    public boolean match(RS2Widget widg) {
        if (widg == null) {
            return false;
        } else if (widg.getInteractActions() == null) {
            return false;
        } else {
            for (String action : widg.getInteractActions()) {
                if (action == null || action.length() < 1 || this.action == null) {
                    return false;
                } else if (action.toLowerCase().contains(this.action.toLowerCase())) {
                    return true;
                }
            }
            return false;
        }
    }

    public String getAction() {
        return action;
    }
}

 

Edited by myOSBaccount

  • myOSBaccount changed the title to [Snippet] My Fairy Ring Handler
  • 1 year later...

Create an account or sign in to comment

Recently Browsing 0

  • No registered users viewing this page.

Account

Navigation

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.