├── README.md └── src └── org └── rspeer └── runetek └── api ├── bot_management ├── BotManagementFileHelper.java ├── data │ ├── UserInfo.java │ ├── Launcher.java │ ├── LaunchedClient.java │ └── QuickLaunch.java ├── RsPeerDownloader.java └── BotManagement.java └── component ├── ExWorlds.java ├── MTAShop.java ├── ExWorldHopper.java ├── ExGrandExchange.java ├── ExPriceCheck.java ├── ExSpells.java ├── ExClanChat.java └── ExWilderness.java /README.md: -------------------------------------------------------------------------------- 1 | # RSPeer Extended API 2 | 3 | Community developed API functions which can be used to assist in the production of scripts for RSPeer. This is separate from RSPeers core API 4 | 5 | 6 | ## Contribution Guidelines 7 | Contributions from the community are what is responsible for shaping this repository. With that being said, there are some guidelines that should be followed to keep this repository in a nice state. 8 | 9 | 10 | Prior to submission, you should ensure that what you have doesn't already exist. Check existing pull requests, both open and closed. 11 | 12 | 13 | ### Standards 14 | * Follow Java code conventions, including formatting 15 | 16 | * Packages must start with `org.rspeer.runetek.api` 17 | 18 | * Class names must be clear and must not collide with existing classes in the RSPeer core API. As an example, inventory extensions would be named ExInventory instead of Inventory 19 | 20 | * Try to keep method bodies at a maximum of 20 lines unless deemed appropriate 21 | -------------------------------------------------------------------------------- /src/org/rspeer/runetek/api/bot_management/BotManagementFileHelper.java: -------------------------------------------------------------------------------- 1 | package org.rspeer.runetek.api.bot_management; 2 | 3 | import org.rspeer.script.Script; 4 | 5 | import java.io.File; 6 | import java.io.FileNotFoundException; 7 | import java.io.IOException; 8 | import java.nio.file.Files; 9 | 10 | public class BotManagementFileHelper { 11 | 12 | public static File getCurrentVersionFile() { 13 | return getFile("cache" + File.separator + "current_version"); 14 | } 15 | 16 | public static File getFile(String path) { 17 | return new File(Script.getDataDirectory().getParent().getParent() + File.separator + path); 18 | } 19 | 20 | public static String getApiKeyOrThrow() throws IOException { 21 | String message = "Api key not found in rspeer_me."; 22 | final File file = getFile("cache" + File.separator + "rspeer_me"); 23 | if (!file.exists()) { 24 | throw new FileNotFoundException(message); 25 | } 26 | final String key = Files.lines(file.toPath()).findFirst().orElse(null); 27 | if(key == null || key.length() == 0) { 28 | throw new FileNotFoundException(message); 29 | } 30 | return key; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/org/rspeer/runetek/api/bot_management/data/UserInfo.java: -------------------------------------------------------------------------------- 1 | package org.rspeer.runetek.api.bot_management.data; 2 | 3 | public class UserInfo { 4 | private int uid; 5 | private int gid; 6 | private String username; 7 | private String homedir; 8 | private String shell; 9 | 10 | public UserInfo(int uid, int gid, String username, String homedir, String shell) { 11 | this.uid = uid; 12 | this.gid = gid; 13 | this.username = username; 14 | this.homedir = homedir; 15 | this.shell = shell; 16 | } 17 | 18 | public int getUid() { 19 | return uid; 20 | } 21 | 22 | public int getGid() { 23 | return gid; 24 | } 25 | 26 | public String getUsername() { 27 | return username; 28 | } 29 | 30 | public String getHomedir() { 31 | return homedir; 32 | } 33 | 34 | public String getShell() { 35 | return shell; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "UserInfo{" + 41 | "uid=" + uid + 42 | ", gid=" + gid + 43 | ", username='" + username + '\'' + 44 | ", homedir='" + homedir + '\'' + 45 | ", shell='" + shell + '\'' + 46 | '}'; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/org/rspeer/runetek/api/component/ExWorlds.java: -------------------------------------------------------------------------------- 1 | package org.rspeer.runetek.api.component; 2 | 3 | import org.rspeer.runetek.api.Game; 4 | import org.rspeer.runetek.api.Worlds; 5 | import org.rspeer.runetek.api.commons.math.Random; 6 | import org.rspeer.runetek.providers.RSWorld; 7 | 8 | import java.util.function.Predicate; 9 | 10 | /** 11 | * @author Typically 12 | */ 13 | public final class ExWorlds { 14 | 15 | /** 16 | * Get a random world from the loaded worlds (excludes the current world) 17 | * 18 | * @return the random world 19 | */ 20 | public static RSWorld getRandom() { 21 | final int currentWorld = Game.getClient().getCurrentWorld(); 22 | final RSWorld[] worlds = Worlds.getLoaded(); 23 | 24 | RSWorld world = worlds[Random.nextInt(worlds.length)]; 25 | 26 | while (world.getId() == currentWorld) { 27 | world = worlds[Random.nextInt(worlds.length)]; 28 | } 29 | 30 | return world; 31 | } 32 | 33 | /** 34 | * Get a random world from the loaded worlds with a predicate (excludes the current world) 35 | * 36 | * @param predicate the world predicate 37 | * @return the random world 38 | */ 39 | public static RSWorld getRandom(Predicate predicate) { 40 | final int currentWorld = Game.getClient().getCurrentWorld(); 41 | final RSWorld[] worlds = Worlds.getLoaded(predicate); 42 | 43 | RSWorld world = worlds[Random.nextInt(worlds.length)]; 44 | 45 | while (world.getId() == currentWorld) { 46 | world = worlds[Random.nextInt(worlds.length)]; 47 | } 48 | 49 | return world; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/org/rspeer/runetek/api/bot_management/data/Launcher.java: -------------------------------------------------------------------------------- 1 | package org.rspeer.runetek.api.bot_management.data; 2 | 3 | import java.util.Arrays; 4 | 5 | public class Launcher { 6 | private String socketAddress; 7 | private String host; 8 | private String platform; 9 | private String type; 10 | private UserInfo userInfo; 11 | private String ip; 12 | private String linkKey; 13 | private String[] errors; 14 | private String[] messages; 15 | 16 | public Launcher(String host, String platform, String type, UserInfo userInfo, String ip, String linkKey, String[] errors, String[] messages) { 17 | this.host = host; 18 | this.platform = platform; 19 | this.type = type; 20 | this.userInfo = userInfo; 21 | this.ip = ip; 22 | this.linkKey = linkKey; 23 | this.errors = errors; 24 | this.messages = messages; 25 | } 26 | 27 | public String getSocketAddress() { 28 | return socketAddress; 29 | } 30 | 31 | public void setSocketAddress(String socketAddress) { 32 | this.socketAddress = socketAddress; 33 | } 34 | 35 | public String getHost() { 36 | return host; 37 | } 38 | 39 | public String getPlatform() { 40 | return platform; 41 | } 42 | 43 | public String getType() { 44 | return type; 45 | } 46 | 47 | public UserInfo getUserInfo() { 48 | return userInfo; 49 | } 50 | 51 | public String getIp() { 52 | return ip; 53 | } 54 | 55 | public String getLinkKey() { 56 | return linkKey; 57 | } 58 | 59 | public String[] getErrors() { 60 | return errors; 61 | } 62 | 63 | public String[] getMessages() { 64 | return messages; 65 | } 66 | 67 | @Override 68 | public String toString() { 69 | return "Launcher{" + 70 | "socketAddress='" + socketAddress + '\'' + 71 | ", host='" + host + '\'' + 72 | ", platform='" + platform + '\'' + 73 | ", type='" + type + '\'' + 74 | ", userInfo=" + userInfo.toString() + 75 | ", ip='" + ip + '\'' + 76 | ", linkKey='" + linkKey + '\'' + 77 | ", errors=" + Arrays.toString(errors) + 78 | ", messages=" + Arrays.toString(messages) + 79 | '}'; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/org/rspeer/runetek/api/bot_management/data/LaunchedClient.java: -------------------------------------------------------------------------------- 1 | package org.rspeer.runetek.api.bot_management.data; 2 | 3 | import okhttp3.*; 4 | import org.rspeer.runetek.api.bot_management.BotManagementFileHelper; 5 | 6 | import java.io.IOException; 7 | 8 | public class LaunchedClient { 9 | 10 | private static final OkHttpClient HTTP_CLIENT = new OkHttpClient(); 11 | 12 | private String lastUpdate; 13 | private String proxyIp; 14 | private String machineName; 15 | private String scriptName; 16 | private String rsn; 17 | private String runescapeEmail; 18 | private String tag; 19 | 20 | public LaunchedClient(String lastUpdate, String proxyIp, String machineName, String scriptName, String rsn, String runescapeEmail, String tag) { 21 | this.lastUpdate = lastUpdate; 22 | this.proxyIp = proxyIp; 23 | this.machineName = machineName; 24 | this.scriptName = scriptName; 25 | this.rsn = rsn; 26 | this.runescapeEmail = runescapeEmail; 27 | this.tag = tag; 28 | } 29 | 30 | public String getLastUpdate() { 31 | return lastUpdate; 32 | } 33 | 34 | public String getProxyIp() { 35 | return proxyIp; 36 | } 37 | 38 | public String getMachineName() { 39 | return machineName; 40 | } 41 | 42 | public String getScriptName() { 43 | return scriptName; 44 | } 45 | 46 | public String getRsn() { 47 | return rsn; 48 | } 49 | 50 | public String getRunescapeEmail() { 51 | return runescapeEmail; 52 | } 53 | 54 | public String getTag() { 55 | return tag; 56 | } 57 | 58 | public boolean kill() throws IOException { 59 | final String apiKey = BotManagementFileHelper.getApiKeyOrThrow(); 60 | 61 | final Request request = new Request.Builder() 62 | .url("https://services.rspeer.org/api/botLauncher/sendNew?message=:kill&tag=" + tag) 63 | .header("ApiClient", apiKey) 64 | .post(RequestBody.create(MediaType.parse(""), "")) 65 | .build(); 66 | 67 | final Response response = HTTP_CLIENT.newCall(request).execute(); 68 | return response.isSuccessful(); 69 | } 70 | 71 | @Override 72 | public String toString() { 73 | return "Client{" + 74 | "lastUpdate='" + lastUpdate + '\'' + 75 | ", proxyIp='" + proxyIp + '\'' + 76 | ", machineName='" + machineName + '\'' + 77 | ", scriptName='" + scriptName + '\'' + 78 | ", rsn='" + rsn + '\'' + 79 | ", runescapeEmail='" + runescapeEmail + '\'' + 80 | ", tag='" + tag + '\'' + 81 | '}'; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/org/rspeer/runetek/api/bot_management/RsPeerDownloader.java: -------------------------------------------------------------------------------- 1 | package org.rspeer.runetek.api.bot_management; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonObject; 5 | import okhttp3.OkHttpClient; 6 | import okhttp3.Request; 7 | import okhttp3.Response; 8 | import okhttp3.ResponseBody; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.nio.file.Files; 14 | import java.nio.file.Paths; 15 | 16 | public class RsPeerDownloader { 17 | 18 | private static final OkHttpClient HTTP_CLIENT = new OkHttpClient(); 19 | 20 | private static boolean downloadNewJar() throws IOException { 21 | if (!shouldDownload()) 22 | return true; 23 | 24 | final String apiKey = BotManagementFileHelper.getApiKeyOrThrow(); 25 | 26 | final Request request = new Request.Builder() 27 | .url("https://services.rspeer.org/api/bot/currentJar") 28 | .header("ApiClient", apiKey) 29 | .get() 30 | .build(); 31 | 32 | final Response response = HTTP_CLIENT.newCall(request).execute(); 33 | if (!response.isSuccessful()) 34 | return false; 35 | 36 | final ResponseBody body = response.body(); 37 | if (body == null) 38 | return false; 39 | 40 | final InputStream is = body.byteStream(); 41 | 42 | Files.copy(is, Paths.get(BotManagementFileHelper.getFile("cache" + File.separator + "rspeer.jar").toURI())); 43 | is.close(); 44 | 45 | saveVersionFile(getCurrentJarVersion()); 46 | return true; 47 | } 48 | 49 | private static void saveVersionFile(String version) throws IOException { 50 | final File file = BotManagementFileHelper.getCurrentVersionFile(); 51 | Files.write(file.toPath(), version.getBytes()); 52 | } 53 | 54 | public static boolean shouldDownload() throws IOException { 55 | final File file = BotManagementFileHelper.getCurrentVersionFile(); 56 | if (!file.exists()) 57 | return true; 58 | final String currentJarVersion = getCurrentJarVersion(); 59 | final String localJarVersion = Files.lines(file.toPath()).findFirst().orElse(""); 60 | return !currentJarVersion.isEmpty() && !currentJarVersion.equals(localJarVersion); 61 | } 62 | 63 | public static String getCurrentJarVersion() throws IOException { 64 | final Request request = new Request.Builder() 65 | .url("https://services.rspeer.org/api/bot/currentVersion") 66 | .get() 67 | .build(); 68 | final Response response = HTTP_CLIENT.newCall(request).execute(); 69 | if (!response.isSuccessful()) 70 | return ""; 71 | 72 | final ResponseBody body = response.body(); 73 | if (body == null) 74 | return ""; 75 | 76 | final Gson gson = new Gson().newBuilder().create(); 77 | return gson.fromJson(body.string(), JsonObject.class) 78 | .get("version") 79 | .getAsString(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/org/rspeer/runetek/api/component/MTAShop.java: -------------------------------------------------------------------------------- 1 | package org.rspeer.runetek.api.component; 2 | 3 | import org.rspeer.runetek.adapter.component.InterfaceComponent; 4 | import org.rspeer.runetek.adapter.component.Item; 5 | import org.rspeer.runetek.api.component.InterfaceAddress; 6 | import org.rspeer.runetek.api.component.Interfaces; 7 | import org.rspeer.runetek.api.component.ItemTables; 8 | import org.rspeer.runetek.api.input.menu.ActionOpcodes; 9 | import org.rspeer.runetek.providers.RSItemTable; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Arrays; 13 | import java.util.List; 14 | import java.util.function.Predicate; 15 | 16 | /** 17 | * Created by Man16 18 | * Date: 17/03/2019 19 | */ 20 | public final class MTAShop { 21 | 22 | private static final int TABLE_KEY = 347; 23 | private static final InterfaceAddress INTERFACE_COMP = new InterfaceAddress(197, 3); 24 | 25 | private MTAShop() { 26 | throw new IllegalAccessError(); 27 | } 28 | 29 | public static boolean isOpen() { 30 | return Interfaces.isOpen(INTERFACE_COMP.getRoot()); 31 | } 32 | 33 | private static RSItemTable getItemTable() { 34 | return ItemTables.lookup(TABLE_KEY); 35 | } 36 | 37 | public static boolean contains(int... ids) { 38 | RSItemTable rsItemTable = getItemTable(); 39 | if (rsItemTable == null) return false; 40 | 41 | return rsItemTable.contains(ids); 42 | } 43 | 44 | public static boolean containsAll(int... ids) { 45 | RSItemTable rsItemTable = getItemTable(); 46 | if (rsItemTable == null) return false; 47 | 48 | return rsItemTable.containsAll(ids); 49 | } 50 | 51 | private static InterfaceComponent getItemContainer() { 52 | return INTERFACE_COMP.resolve(); 53 | } 54 | 55 | public static Item[] getItems(Predicate predicate) { 56 | InterfaceComponent interfaceComponent = getItemContainer(); 57 | if (interfaceComponent == null) return new Item[0]; 58 | 59 | List list = new ArrayList<>(); 60 | 61 | for (int i = 0; i < interfaceComponent.getItemIds().length; i++) { 62 | Item item = new Item(interfaceComponent, i); 63 | if (predicate.test(item)) 64 | list.add(item); 65 | } 66 | 67 | return list.toArray(new Item[0]); 68 | } 69 | 70 | public static Item[] getItems() { 71 | return getItems(x -> true); 72 | } 73 | 74 | public static Item getFirst(Predicate predicate) { 75 | return Arrays.stream(getItems(predicate)).findFirst().orElse(null); 76 | } 77 | 78 | public static Item getFirst(int id) { 79 | return getFirst(item -> item.getId() == id); 80 | } 81 | 82 | public static Item getFirst(String name) { 83 | return getFirst(item -> item.getName().equalsIgnoreCase(name)); 84 | } 85 | 86 | public static boolean buy(Predicate predicate) { 87 | Item item = getFirst(predicate); 88 | return item != null && item.interact(ActionOpcodes.TABLE_ACTION_1); 89 | } 90 | 91 | public static boolean buy(int id) { 92 | return buy(item -> item.getId() == id); 93 | } 94 | 95 | public static boolean buy(String name) { 96 | return buy(item -> item.getName().equalsIgnoreCase(name)); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/org/rspeer/runetek/api/component/ExWorldHopper.java: -------------------------------------------------------------------------------- 1 | package org.rspeer.runetek.api.component; 2 | 3 | import org.rspeer.runetek.api.Game; 4 | import org.rspeer.runetek.api.Worlds; 5 | import org.rspeer.runetek.api.commons.Time; 6 | import org.rspeer.runetek.api.commons.math.Random; 7 | import org.rspeer.runetek.providers.RSWorld; 8 | 9 | import java.util.Arrays; 10 | import java.util.List; 11 | import java.util.function.Predicate; 12 | 13 | /** 14 | * @author Typically 15 | */ 16 | public final class ExWorldHopper { 17 | 18 | private static final Predicate PURE_WORLD_PREDICATE = 19 | rsWorld -> !rsWorld.isDeadman() 20 | && !rsWorld.isHighRisk() 21 | && !rsWorld.isLastManStanding() 22 | && !rsWorld.isSkillTotal() 23 | && !rsWorld.isSeasonDeadman() 24 | && !rsWorld.isTournament() 25 | && !rsWorld.isPVP() 26 | && !rsWorld.isBounty(); 27 | 28 | private static final Predicate PURE_MEMBER_WORLD_PREDICATE = PURE_WORLD_PREDICATE.and(RSWorld::isMembers); 29 | 30 | /** 31 | * Insta hops to a target world 32 | * 33 | * @param world the world 34 | * @return true if it succeeds to insta hop; false otherwise 35 | */ 36 | public static boolean instaHopTo(RSWorld world) { 37 | final int currentWorld = Game.getClient().getCurrentWorld(); 38 | 39 | if (Game.isLoggedIn() && Game.logout()) { 40 | Game.getClient().setWorld(world); 41 | } 42 | 43 | return Time.sleepUntil(() -> Game.getClient().getCurrentWorld() != currentWorld, Random.high(2000, 3000)); 44 | } 45 | 46 | /** 47 | * Insta hops to a target world with a predicate 48 | * 49 | * @param predicate the predicate for the world 50 | * @return true if it succeeds to insta hop; false otherwise 51 | */ 52 | public static boolean instaHopTo(Predicate predicate) { 53 | return instaHopTo(Worlds.get(predicate)); 54 | } 55 | 56 | /** 57 | * Insta hops to a target world 58 | * 59 | * @param worldId the worldId 60 | * @return true if it succeeds to insta hop; false otherwise 61 | */ 62 | public static boolean instaHopTo(int worldId) { 63 | return instaHopTo(Worlds.get(worldId)); 64 | } 65 | 66 | /** 67 | * Insta hops to a random world with a predicate 68 | * 69 | * @param predicate the predicate for the random world 70 | * @param excluded the world id's to exclude from the predicate 71 | * @return true if it succeeds to insta hop; false otherwise 72 | */ 73 | public static boolean randomInstaHop(Predicate predicate, Integer... excluded) { 74 | if (excluded != null) { 75 | final List excludedList = Arrays.asList(excluded); 76 | predicate = predicate.and(rsWorld -> !excludedList.contains(rsWorld.getId())); 77 | } 78 | 79 | return instaHopTo(ExWorlds.getRandom(predicate)); 80 | } 81 | 82 | /** 83 | * Insta hops to a random free to play world 84 | * 85 | * @return true if it succeeds to insta hop; false otherwise 86 | */ 87 | public static boolean randomInstaHopInF2p() { 88 | return randomInstaHop(rsWorld -> !rsWorld.isMembers()); 89 | } 90 | 91 | /** 92 | * Insta hops to a random pure free to play world (excludes all flags) 93 | * 94 | * @return true if it succeeds to insta hop; false otherwise 95 | */ 96 | public static boolean randomInstaHopInPureF2p() { 97 | return randomInstaHop(PURE_WORLD_PREDICATE); 98 | } 99 | 100 | 101 | /** 102 | * Insta hops to a random pay to play world 103 | * 104 | * @return true if it succeeds to insta hop; false otherwise 105 | */ 106 | public static boolean randomInstaHopInP2p() { 107 | return randomInstaHop(RSWorld::isMembers); 108 | } 109 | 110 | /** 111 | * Insta hops to a random pure pay to play world (excludes all flags) 112 | * 113 | * @return true if it succeeds to insta hop; false otherwise 114 | */ 115 | public static boolean randomInstaHopInPureP2p() { 116 | return randomInstaHop(PURE_MEMBER_WORLD_PREDICATE, 318, 319); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/org/rspeer/runetek/api/component/ExGrandExchange.java: -------------------------------------------------------------------------------- 1 | package org.rspeer.runetek.api.component; 2 | 3 | import org.rspeer.runetek.adapter.scene.Npc; 4 | import org.rspeer.runetek.api.Definitions; 5 | import org.rspeer.runetek.api.commons.BankLocation; 6 | import org.rspeer.runetek.api.commons.Time; 7 | import org.rspeer.runetek.api.movement.Movement; 8 | import org.rspeer.runetek.api.scene.Npcs; 9 | import org.rspeer.runetek.providers.RSGrandExchangeOffer; 10 | import org.rspeer.runetek.providers.RSItemDefinition; 11 | 12 | import java.util.Arrays; 13 | 14 | /** 15 | * @author burak 16 | */ 17 | public final class ExGrandExchange { 18 | private static final int SELL_ALL = 0; 19 | private static final int TIMEOUT = 3000; 20 | private static final String EXCHANGE_ACTION = "Exchange"; 21 | private static final String GE_NPC_NAME = "Grand Exchange Clerk"; 22 | 23 | private static boolean exchange(RSGrandExchangeOffer.Type type, RSItemDefinition item, int quantity, int price, boolean toBank) { 24 | return exchange(type, quantity, price, toBank, item); 25 | } 26 | 27 | private static boolean exchange(RSGrandExchangeOffer.Type type, int quantity, int price, boolean toBank, RSItemDefinition item) { 28 | if (!GrandExchange.isOpen()) { 29 | //GrandExchange.open(); 30 | 31 | // placeholder 32 | Npc clerk = Npcs.getNearest(GE_NPC_NAME); 33 | return clerk != null ? clerk.interact(EXCHANGE_ACTION) : Movement.walkToRandomized(BankLocation.GRAND_EXCHANGE.getPosition()); 34 | } 35 | 36 | return collectFinishedOffers(toBank) 37 | && createOffer(type) 38 | && setItem(item) 39 | && setItemPrice(price) 40 | && setItemQuantity(quantity) 41 | && GrandExchangeSetup.confirm(); 42 | 43 | } 44 | 45 | private static boolean setItem(RSItemDefinition item) { 46 | return GrandExchangeSetup.setItem(item.getId()); 47 | } 48 | 49 | private static boolean collectFinishedOffers(boolean toBank) { 50 | if (hasNotAnyFinishedOffers()) return true; 51 | GrandExchange.collectAll(toBank); 52 | return Time.sleepUntil(ExGrandExchange::hasNotAnyFinishedOffers, TIMEOUT); 53 | } 54 | 55 | private static boolean createOffer(RSGrandExchangeOffer.Type offerType) { 56 | if (GrandExchangeSetup.isOpen()) return true; 57 | return GrandExchange.createOffer(offerType) 58 | && Time.sleepUntil(GrandExchangeSetup::isOpen, TIMEOUT); 59 | } 60 | 61 | private static boolean hasNotAnyFinishedOffers() { 62 | return Arrays.stream(GrandExchange.getOffers()) 63 | .noneMatch(it -> it.getProgress() == RSGrandExchangeOffer.Progress.FINISHED); 64 | } 65 | 66 | private static boolean isItemPriceSettled(int desired) { 67 | return GrandExchangeSetup.getPricePerItem() == desired; 68 | } 69 | 70 | private static boolean isItemQuantitySettled(int desired) { 71 | return GrandExchangeSetup.getQuantity() == desired; 72 | } 73 | 74 | private static boolean setItemPrice(int price) { 75 | return GrandExchangeSetup.setPrice(price) 76 | && Time.sleepUntil(() -> isItemPriceSettled(price), TIMEOUT); 77 | } 78 | 79 | private static boolean setItemQuantity(int quantity) { 80 | if (quantity == SELL_ALL) return true; 81 | 82 | return GrandExchangeSetup.setQuantity(quantity) 83 | && Time.sleepUntil(() -> isItemQuantitySettled(quantity), TIMEOUT); 84 | } 85 | 86 | public static boolean buy(int id, int quantity, int price, boolean toBank) { 87 | return exchange(RSGrandExchangeOffer.Type.BUY, Definitions.getItem(id), quantity, price, toBank); 88 | } 89 | 90 | public static boolean buy(String name, int quantity, int price, boolean toBank) { 91 | return exchange(RSGrandExchangeOffer.Type.BUY, Definitions.getItem(name, x -> x.isTradable() || x.isNoted()), quantity, price, toBank); 92 | } 93 | 94 | public static boolean sell(int id, int quantity, int price, boolean toBank) { 95 | return exchange(RSGrandExchangeOffer.Type.SELL, Definitions.getItem(id), quantity, price, toBank); 96 | } 97 | 98 | public static boolean sell(String name, int quantity, int price, boolean toBank) { 99 | return exchange(RSGrandExchangeOffer.Type.SELL, Definitions.getItem(name, x -> x.isTradable() || x.isNoted()), quantity, price, toBank); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/org/rspeer/runetek/api/component/ExPriceCheck.java: -------------------------------------------------------------------------------- 1 | package org.rspeer.runetek.api.component; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonElement; 5 | import com.google.gson.JsonObject; 6 | import okhttp3.OkHttpClient; 7 | import okhttp3.Request; 8 | import okhttp3.Response; 9 | 10 | import java.io.IOException; 11 | import java.util.Map; 12 | 13 | public class ExPriceCheck { 14 | 15 | private static final OkHttpClient HTTP_CLIENT = new OkHttpClient(); 16 | private static final Gson GSON = new Gson().newBuilder().create(); 17 | 18 | private static final String OLDSCHOOL_RUNESCAPE_API_URL = "http://services.runescape.com/m=itemdb_oldschool/api/"; 19 | private static final String OSBUDDY_EXCHANGE_SUMMARY_URL = "https://storage.googleapis.com/osb-exchange/summary.json"; 20 | 21 | private static JsonObject OSBUDDY_SUMMARY_JSON; 22 | 23 | /** 24 | * Fetches the price of an item from the RuneScape services catalogue details 25 | * 26 | * @param id the id of the item 27 | * @return the price of the item; -1 if failed 28 | */ 29 | public static int getRSPrice(int id) throws IOException { 30 | final Request request = new Request.Builder() 31 | .url(OLDSCHOOL_RUNESCAPE_API_URL + "catalogue/detail.json?item=" + id) 32 | .get() 33 | .build(); 34 | 35 | final Response response = HTTP_CLIENT.newCall(request).execute(); 36 | 37 | if (!response.isSuccessful() || response.body() == null) 38 | return -1; 39 | 40 | final String priceText = GSON.fromJson(response.body().string(), JsonObject.class) 41 | .getAsJsonObject("item") 42 | .getAsJsonObject("current") 43 | .get("price") 44 | .getAsString(); 45 | 46 | final int price = Integer.parseInt(priceText.replaceAll("\\D+", "")); 47 | 48 | return priceText.matches("[0-9]+") ? price : price * (priceText.charAt(0) == 'k' ? 1000 : 1000000); 49 | } 50 | 51 | /** 52 | * Fetches the price of an item from the RuneScape services graph. 53 | * 54 | * @param id the id of the item 55 | * @return the price of the item; -1 if failed 56 | */ 57 | @SuppressWarnings("unchecked") 58 | public static int getAccurateRSPrice(int id) throws IOException { 59 | final Request request = new Request.Builder() 60 | .url(OLDSCHOOL_RUNESCAPE_API_URL + "graph/" + id + ".json") 61 | .get() 62 | .build(); 63 | 64 | final Response response = HTTP_CLIENT.newCall(request).execute(); 65 | 66 | if (!response.isSuccessful() || response.body() == null) 67 | return -1; 68 | 69 | final JsonObject jsonObject = GSON.fromJson(response.body().string(), JsonObject.class) 70 | .getAsJsonObject("daily") 71 | .getAsJsonObject(); 72 | 73 | final int size = jsonObject.entrySet().size(); 74 | final Map.Entry entry = ((Map.Entry) jsonObject.entrySet().toArray()[size - 1]); 75 | 76 | return Integer.parseInt(entry.getValue().getAsString()); 77 | } 78 | 79 | /** 80 | * Sets the OSBuddy price summary json 81 | */ 82 | private static void setOSBuddySummaryJson() throws IOException { 83 | final Request request = new Request.Builder() 84 | .url(OSBUDDY_EXCHANGE_SUMMARY_URL) 85 | .get() 86 | .build(); 87 | 88 | final Response response = HTTP_CLIENT.newCall(request).execute(); 89 | 90 | if (!response.isSuccessful() || response.body() == null) 91 | return; 92 | 93 | OSBUDDY_SUMMARY_JSON = GSON.fromJson(response.body().string(), JsonObject.class); 94 | } 95 | 96 | /** 97 | * Fetches the price of an item from the OSBuddy price summary json. The entire summary data is stored upon first 98 | * retrieval 99 | * 100 | * @param id the id of the item 101 | * @return the price of the item; -1 if failed 102 | */ 103 | public static int getOSBuddyPrice(int id) throws IOException { 104 | if (OSBUDDY_SUMMARY_JSON == null) 105 | setOSBuddySummaryJson(); 106 | 107 | if (OSBUDDY_SUMMARY_JSON == null) 108 | return -1; 109 | 110 | final JsonObject jsonObject = OSBUDDY_SUMMARY_JSON.getAsJsonObject(Integer.toString(id)); 111 | 112 | if (jsonObject == null) 113 | return -1; 114 | 115 | return jsonObject.get("sell_average").getAsInt(); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/org/rspeer/runetek/api/bot_management/BotManagement.java: -------------------------------------------------------------------------------- 1 | package org.rspeer.runetek.api.bot_management; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonElement; 5 | import com.google.gson.JsonObject; 6 | import com.google.gson.reflect.TypeToken; 7 | import okhttp3.*; 8 | import org.rspeer.runetek.api.bot_management.data.LaunchedClient; 9 | import org.rspeer.runetek.api.bot_management.data.Launcher; 10 | import org.rspeer.runetek.api.bot_management.data.QuickLaunch; 11 | 12 | import java.io.IOException; 13 | import java.lang.reflect.Type; 14 | import java.util.*; 15 | 16 | public class BotManagement { 17 | 18 | private static final OkHttpClient HTTP_CLIENT = new OkHttpClient(); 19 | private static final String DEFAULT_JVM_ARGS = "-Xmx768m -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv4Addresses=true -Xss2m"; 20 | 21 | public static boolean startDefaultClient(int pcIndex) throws IOException { 22 | return startClient(pcIndex, 23 | null, 24 | DEFAULT_JVM_ARGS, 25 | 10, 26 | null, 27 | 1 28 | ); 29 | } 30 | 31 | public static boolean startClient(int pcIndex, int sleep, String proxy, int count) throws IOException { 32 | return startClient(pcIndex, "", sleep, proxy, count); 33 | } 34 | 35 | public static boolean startClient(int pcIndex, int sleep, int count) throws IOException { 36 | return startClient(pcIndex, "", sleep, "", count); 37 | } 38 | 39 | public static boolean startClient(int pcIndex, String qs, int sleep, String proxy, int count) throws IOException { 40 | return startClient( 41 | pcIndex, 42 | qs, 43 | DEFAULT_JVM_ARGS, 44 | sleep, 45 | proxy, 46 | count 47 | ); 48 | } 49 | 50 | public static boolean startClient(int pcIndex, String qs, String jvmArgs, int sleep, String proxy, int count) throws IOException { 51 | final String apiKey = BotManagementFileHelper.getApiKeyOrThrow(); 52 | 53 | List launchers = getLaunchers(); 54 | final Headers headers = new Headers.Builder() 55 | .add("ApiClient", apiKey) 56 | .add("Content-Type", "application/json") 57 | .build(); 58 | 59 | String body = "{\"payload\":" + 60 | "{" + 61 | "\"type\":\"start:client\"," + 62 | "\"session\":\"" + apiKey + "\"," + 63 | "\"qs\":" + (qs == null ? "null" : qs) + "," + 64 | "\"jvmArgs\":\"" + jvmArgs + "\"," + 65 | "\"sleep\":" + sleep + "," + 66 | "\"proxy\":" + proxy + "" + 67 | (count > 0 ? ",\"count\":" + count : "") + 68 | "}," + 69 | "\"socket\":\"" + launchers.get(pcIndex).getSocketAddress() + "\"" + 70 | "}"; 71 | 72 | final RequestBody requestBody = RequestBody.create( 73 | MediaType.parse("application/json"), 74 | body 75 | ); 76 | 77 | final Request request = new Request.Builder() 78 | .url("https://services.rspeer.org/api/botLauncher/send") 79 | .headers(headers) 80 | .post(requestBody) 81 | .build(); 82 | 83 | final Response response = HTTP_CLIENT.newCall(request).execute(); 84 | return response.isSuccessful(); 85 | } 86 | 87 | public static boolean addProxy(String name, String ip, String port, String username, String password) throws Exception { 88 | final String apiKey = BotManagementFileHelper.getApiKeyOrThrow(); 89 | 90 | final Headers headers = new Headers.Builder() 91 | .add("ApiClient", apiKey) 92 | .add("Content-Type", "application/json") 93 | .build(); 94 | 95 | final String body = 96 | "{" + 97 | "\"Name\":\"" + name + "\"," + 98 | "\"Ip\":\"" + ip + "\"," + 99 | "\"Port\":\"" + port + "\"," + 100 | "\"Username\":\"" + username + "\"," + 101 | "\"Password\":\"" + password + "\"" + 102 | "}"; 103 | 104 | final RequestBody requestBody = RequestBody.create( 105 | MediaType.parse("application/json"), 106 | body 107 | ); 108 | 109 | final Request request = new Request.Builder() 110 | .url("https://services.rspeer.org/api/botLauncher/saveProxy") 111 | .headers(headers) 112 | .post(requestBody) 113 | .build(); 114 | 115 | final Response response = HTTP_CLIENT.newCall(request).execute(); 116 | return response.isSuccessful(); 117 | } 118 | 119 | public static List getQuickLaunchers() throws IOException { 120 | final String apiKey = BotManagementFileHelper.getApiKeyOrThrow(); 121 | 122 | final Request request = new Request.Builder() 123 | .url("https://services.rspeer.org/api/botLauncher/getQuickLaunch") 124 | .header("ApiClient", apiKey) 125 | .get() 126 | .build(); 127 | 128 | final Response response = HTTP_CLIENT.newCall(request).execute(); 129 | 130 | if (!response.isSuccessful()) 131 | return Collections.emptyList(); 132 | 133 | final ResponseBody body = response.body(); 134 | if (body == null) 135 | return Collections.emptyList(); 136 | 137 | final Gson gson = new Gson().newBuilder().create(); 138 | final Type clientType = new TypeToken>() { 139 | }.getType(); 140 | 141 | return gson.fromJson(body.string(), clientType); 142 | } 143 | 144 | public static List getRunningClients() throws IOException { 145 | final String apiKey = BotManagementFileHelper.getApiKeyOrThrow(); 146 | 147 | final Request request = new Request.Builder() 148 | .url("https://services.rspeer.org/api/botLauncher/connectedClients") 149 | .header("ApiClient", apiKey) 150 | .get() 151 | .build(); 152 | 153 | final Response response = HTTP_CLIENT.newCall(request).execute(); 154 | 155 | if (!response.isSuccessful()) 156 | return Collections.emptyList(); 157 | 158 | final ResponseBody body = response.body(); 159 | if (body == null) 160 | return Collections.emptyList(); 161 | 162 | final Gson gson = new Gson().newBuilder().create(); 163 | final Type type = new TypeToken>() { 164 | }.getType(); 165 | return gson.fromJson(body.string(), type); 166 | } 167 | 168 | public static List getLaunchers() throws IOException { 169 | final String apiKey = BotManagementFileHelper.getApiKeyOrThrow(); 170 | 171 | final Request request = new Request.Builder() 172 | .url("https://services.rspeer.org/api/botLauncher/connected") 173 | .header("ApiClient", apiKey) 174 | .get() 175 | .build(); 176 | 177 | final Response response = HTTP_CLIENT.newCall(request).execute(); 178 | 179 | if (!response.isSuccessful()) 180 | return Collections.emptyList(); 181 | 182 | final ResponseBody body = response.body(); 183 | if (body == null) 184 | return Collections.emptyList(); 185 | 186 | final Gson gson = new Gson().newBuilder().create(); 187 | final JsonObject jsonObject = gson.fromJson(body.string(), JsonObject.class); 188 | Set> entries = jsonObject.entrySet(); 189 | final List launchers = new ArrayList<>(); 190 | for (Map.Entry entry : entries) { 191 | Launcher launcher = gson.fromJson(entry.getValue().getAsJsonObject(), Launcher.class); 192 | launcher.setSocketAddress(entry.getKey()); 193 | launchers.add(launcher); 194 | } 195 | return launchers; 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /src/org/rspeer/runetek/api/bot_management/data/QuickLaunch.java: -------------------------------------------------------------------------------- 1 | package org.rspeer.runetek.api.bot_management.data; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonArray; 5 | import com.google.gson.JsonObject; 6 | 7 | import java.util.List; 8 | 9 | public class QuickLaunch { 10 | private String quickLaunchId; 11 | private String name; 12 | private List clients; 13 | private String dateAdded; 14 | private String lastUpdated; 15 | 16 | public String getQuickLaunchId() { 17 | return quickLaunchId; 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | public List getClients() { 25 | return clients; 26 | } 27 | 28 | public void setClients(List clients) { 29 | this.clients = clients; 30 | } 31 | 32 | public String getDateAdded() { 33 | return dateAdded; 34 | } 35 | 36 | public String getLastUpdated() { 37 | return lastUpdated; 38 | } 39 | 40 | public JsonObject get() { 41 | final Gson gson = new Gson(); 42 | final JsonObject obj = new JsonObject(); 43 | obj.addProperty("name", name); 44 | obj.addProperty("dateAdded", dateAdded); 45 | obj.addProperty("lastUpdated", lastUpdated); 46 | final JsonArray jsonClients = new JsonArray(); 47 | for (Client client : clients) { 48 | jsonClients.add(gson.toJsonTree(client)); 49 | } 50 | obj.add("clients", jsonClients); 51 | return obj; 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return "QuickLaunch{" + 57 | "quickLaunchId='" + quickLaunchId + '\'' + 58 | ", name='" + name + '\'' + 59 | ", clients=" + clients.toString() + 60 | ", dateAdded='" + dateAdded + '\'' + 61 | ", lastUpdated='" + lastUpdated + '\'' + 62 | '}'; 63 | } 64 | 65 | public class Client { 66 | private String rsUsername; 67 | private String rsPassword; 68 | private int world; 69 | private Proxy proxy; 70 | private Script script; 71 | private Config config; 72 | 73 | public Client(String rsUsername, String rsPassword, int world, Proxy proxy, Script script, Config config) { 74 | this.rsUsername = rsUsername; 75 | this.rsPassword = rsPassword; 76 | this.world = world; 77 | this.proxy = proxy; 78 | this.script = script; 79 | this.config = config; 80 | } 81 | 82 | public String getRsUsername() { 83 | return rsUsername; 84 | } 85 | 86 | public String getRsPassword() { 87 | return rsPassword; 88 | } 89 | 90 | public int getWorld() { 91 | return world; 92 | } 93 | 94 | public Proxy getProxy() { 95 | return proxy; 96 | } 97 | 98 | public Script getScript() { 99 | return script; 100 | } 101 | 102 | public Config getConfig() { 103 | return config; 104 | } 105 | 106 | 107 | @Override 108 | public String toString() { 109 | return "Client{" + 110 | "rsUsername='" + rsUsername + '\'' + 111 | ", rsPassword='" + rsPassword + '\'' + 112 | ", world=" + world + 113 | ", proxy=" + proxy.toString() + 114 | ", script=" + script.toString() + 115 | ", config=" + config.toString() + 116 | '}'; 117 | } 118 | } 119 | 120 | public class Config { 121 | private boolean lowCpuMode; 122 | private boolean superLowCpuMode; 123 | private int engineTickDelay; 124 | private boolean disableModelRendering; 125 | private boolean disableSceneRendering; 126 | 127 | public Config(boolean lowCpuMode, boolean superLowCpuMode, int engineTickDelay, boolean disableModelRendering, boolean disableSceneRendering) { 128 | this.lowCpuMode = lowCpuMode; 129 | this.superLowCpuMode = superLowCpuMode; 130 | this.engineTickDelay = engineTickDelay; 131 | this.disableModelRendering = disableModelRendering; 132 | this.disableSceneRendering = disableSceneRendering; 133 | } 134 | 135 | public boolean isLowCpuMode() { 136 | return lowCpuMode; 137 | } 138 | 139 | public boolean isSuperLowCpuMode() { 140 | return superLowCpuMode; 141 | } 142 | 143 | public int getEngineTickDelay() { 144 | return engineTickDelay; 145 | } 146 | 147 | public boolean isDisableModelRendering() { 148 | return disableModelRendering; 149 | } 150 | 151 | public boolean isDisableSceneRendering() { 152 | return disableSceneRendering; 153 | } 154 | 155 | @Override 156 | public String toString() { 157 | return "Config{" + 158 | "lowCpuMode=" + lowCpuMode + 159 | ", superLowCpuMode=" + superLowCpuMode + 160 | ", engineTickDelay=" + engineTickDelay + 161 | ", disableModelRendering=" + disableModelRendering + 162 | ", disableSceneRendering=" + disableSceneRendering + 163 | '}'; 164 | } 165 | } 166 | 167 | public class Proxy { 168 | private String proxyId; 169 | private String date; 170 | private String userId; 171 | private String name; 172 | private String ip; 173 | private int port; 174 | private String username; 175 | private String password; 176 | 177 | public Proxy(String proxyId, String date, String userId, String name, String ip, int port, String username, String password) { 178 | this.proxyId = proxyId; 179 | this.date = date; 180 | this.userId = userId; 181 | this.name = name; 182 | this.ip = ip; 183 | this.port = port; 184 | this.username = username; 185 | this.password = password; 186 | } 187 | 188 | public String getProxyId() { 189 | return proxyId; 190 | } 191 | 192 | public String getDate() { 193 | return date; 194 | } 195 | 196 | public String getUserId() { 197 | return userId; 198 | } 199 | 200 | public String getName() { 201 | return name; 202 | } 203 | 204 | public String getIp() { 205 | return ip; 206 | } 207 | 208 | public int getPort() { 209 | return port; 210 | } 211 | 212 | public String getUsername() { 213 | return username; 214 | } 215 | 216 | public String getPassword() { 217 | return password; 218 | } 219 | 220 | @Override 221 | public String toString() { 222 | return "Proxy{" + 223 | "proxyId='" + proxyId + '\'' + 224 | ", date='" + date + '\'' + 225 | ", userId='" + userId + '\'' + 226 | ", name='" + name + '\'' + 227 | ", ip='" + ip + '\'' + 228 | ", port=" + port + 229 | ", username='" + username + '\'' + 230 | ", password='" + password + '\'' + 231 | '}'; 232 | } 233 | } 234 | 235 | public class Script { 236 | private String scriptArgs; 237 | private String name; 238 | private String scriptId; 239 | private boolean isRepoScript; 240 | 241 | public Script(String scriptArgs, String name, String scriptId, boolean isRepoScript) { 242 | this.scriptArgs = scriptArgs; 243 | this.name = name; 244 | this.scriptId = scriptId; 245 | this.isRepoScript = isRepoScript; 246 | } 247 | 248 | public String getScriptArgs() { 249 | return scriptArgs; 250 | } 251 | 252 | public String getName() { 253 | return name; 254 | } 255 | 256 | public String getScriptId() { 257 | return scriptId; 258 | } 259 | 260 | public boolean isRepoScript() { 261 | return isRepoScript; 262 | } 263 | 264 | @Override 265 | public String toString() { 266 | return "Script{" + 267 | "scriptArgs='" + scriptArgs + '\'' + 268 | ", name='" + name + '\'' + 269 | ", scriptId='" + scriptId + '\'' + 270 | ", isRepoScript=" + isRepoScript + 271 | '}'; 272 | } 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /src/org/rspeer/runetek/api/component/ExSpells.java: -------------------------------------------------------------------------------- 1 | package org.rspeer.runetek.api.component; 2 | 3 | import org.rspeer.runetek.adapter.component.InterfaceComponent; 4 | import org.rspeer.runetek.api.Varps; 5 | import org.rspeer.runetek.api.commons.Time; 6 | import org.rspeer.runetek.api.commons.math.Random; 7 | import org.rspeer.runetek.api.component.tab.*; 8 | 9 | /** 10 | * @author qverkk and Typically 11 | */ 12 | 13 | public final class ExSpells { 14 | 15 | private static final int COMBAT_TAB_INTERFACE_ID = 593; 16 | 17 | private static final int AUTO_CAST_MENU_INTERFACE_ID = 201; 18 | private static final int AUTO_CAST_VARP = 108; 19 | private static final InterfaceAddress AUTO_CAST_ROOT_MENU = new InterfaceAddress(() -> { 20 | final InterfaceComponent[] components = Interfaces.get(AUTO_CAST_MENU_INTERFACE_ID); 21 | 22 | if (components.length == 0) 23 | return null; 24 | 25 | return components[0]; 26 | }); 27 | 28 | /** 29 | * Returns the best spell the local player can cast 30 | * 31 | * @return the best spell 32 | */ 33 | public static ExSpell getBestSpell() { 34 | final ExSpell[] allSpells = ExSpell.values(); 35 | 36 | ExSpell currentSpell = ExSpell.WIND_STRIKE; 37 | 38 | for (ExSpell currentlyChecked : allSpells) { 39 | if (currentlyChecked == currentSpell) { 40 | continue; 41 | } 42 | 43 | if (currentlyChecked.getLevelRequired() > currentSpell.getLevelRequired() && currentlyChecked.canCast()) { 44 | currentSpell = currentlyChecked; 45 | } 46 | } 47 | return currentSpell; 48 | } 49 | 50 | /** 51 | * Returns the currently selected spell 52 | * 53 | * @return the currently selected spell 54 | */ 55 | public static ExSpell getSelectedSpell() { 56 | for (ExSpell spell : ExSpell.values()) { 57 | if (spell.isAutoCasted()) { 58 | return spell; 59 | } 60 | } 61 | return null; 62 | } 63 | 64 | /** 65 | * Checks if the target spell is auto-casted 66 | * 67 | * @param spell the spell 68 | * @return true if the spell is auto-casted; false otherwise 69 | */ 70 | public static boolean isAutoCasted(ExSpell spell) { 71 | return spell.isAutoCasted(); 72 | } 73 | 74 | /** 75 | * Checks if the target spell is auto-casted 76 | * 77 | * @param spell the spell 78 | * @return true if the spell is auto-casted; false otherwise 79 | */ 80 | public static boolean isAutoCasted(Spell spell) { 81 | for (ExSpell exSpell : ExSpell.values()) { 82 | if (exSpell.getSpell().equals(spell)) { 83 | return isAutoCasted(exSpell); 84 | } 85 | } 86 | return false; 87 | } 88 | 89 | /** 90 | * Checks if the best spell is auto-casted 91 | * 92 | * @return true if the best spell is auto-casted; false otherwise 93 | */ 94 | public static boolean isBestSpellAutoCasted() { 95 | return getBestSpell().isAutoCasted(); 96 | } 97 | 98 | /** 99 | * Auto-casts a target spell 100 | * 101 | * @param spell the spell 102 | * @param defensive defensive auto-cast 103 | * @return true if auto-cast succeeded; false otherwise 104 | */ 105 | public static boolean autoCast(Spell spell, boolean defensive) { 106 | for (ExSpell exSpell : ExSpell.values()) { 107 | if (exSpell.getSpell() == spell) { 108 | return autoCast(exSpell, defensive); 109 | } 110 | } 111 | return false; 112 | } 113 | 114 | /** 115 | * Auto-casts a target spell 116 | * 117 | * @param spell the spell 118 | * @return true if auto-cast succeeded; false otherwise 119 | */ 120 | public static boolean autoCast(Spell spell) { 121 | return autoCast(spell, false); 122 | } 123 | 124 | /** 125 | * Auto-casts a target spell 126 | * 127 | * @param spell the spell 128 | * @param defensive defensive auto-cast 129 | * @return true if auto-cast succeeded; false otherwise 130 | */ 131 | public static boolean autoCast(ExSpell spell, boolean defensive) { 132 | return openAutoCastSettings(defensive) && selectSpell(spell); 133 | } 134 | 135 | /** 136 | * Auto-casts a target spell 137 | * 138 | * @param spell the spell 139 | * @return true if auto-cast succeeded; false otherwise 140 | */ 141 | public static boolean autoCast(ExSpell spell) { 142 | return autoCast(spell, false); 143 | } 144 | 145 | /** 146 | * Opens the auto-cast settings 147 | * 148 | * @param defensive defensive auto-cast 149 | * @return true if auto-cast settings is open; false otherwise 150 | */ 151 | public static boolean openAutoCastSettings(boolean defensive) { 152 | if (AUTO_CAST_ROOT_MENU.resolve() != null) 153 | return true; 154 | 155 | InterfaceComponent chooseSpellComponent = getChooseSpellComponent(defensive); 156 | 157 | if (chooseSpellComponent == null) 158 | return false; 159 | 160 | return openCombatTab() 161 | && chooseSpellComponent.click() 162 | && Time.sleepUntil(() -> AUTO_CAST_ROOT_MENU.resolve() != null, Random.low(600, 1600)); 163 | } 164 | 165 | /** 166 | * Opens the auto-cast settings 167 | * 168 | * @return true if auto-cast settings is open; false otherwise 169 | */ 170 | public static boolean openAutoCastSettings() { 171 | return openAutoCastSettings(false); 172 | } 173 | /** 174 | * Selects a target spell 175 | * 176 | * @param spell the spell 177 | * @return true if the target spell is selected; false otherwise 178 | */ 179 | 180 | public static boolean selectSpell(ExSpell spell) { 181 | final InterfaceComponent spellComponent = Interfaces.getComponent(AUTO_CAST_MENU_INTERFACE_ID, 1, spell.getSpellIndex()); 182 | 183 | return spellComponent != null 184 | && spellComponent.interact(action -> action.toLowerCase().equals(spell.getName())) 185 | && Time.sleepUntil(spell::isAutoCasted, Random.low(600, 1600)); 186 | } 187 | 188 | private static boolean openCombatTab() { 189 | if (Tabs.isOpen(Tab.COMBAT)) 190 | return true; 191 | 192 | return Tabs.open(Tab.COMBAT) 193 | && Time.sleepUntil(() -> Tabs.isOpen(Tab.COMBAT), Random.low(600, 1600)); 194 | } 195 | 196 | private static InterfaceComponent getChooseSpellComponent(boolean defensive) { 197 | final int index = defensive ? 0 : 1; 198 | 199 | final InterfaceComponent[] components = Interfaces.get(COMBAT_TAB_INTERFACE_ID, 200 | interfaceComponent -> interfaceComponent.containsAction("Choose spell")); 201 | 202 | if (components.length < 2) 203 | return null; 204 | 205 | return components[index]; 206 | } 207 | 208 | public enum ExSpell { 209 | WIND_STRIKE(Spell.Modern.WIND_STRIKE, 3, 1), 210 | WATER_STRIKE(Spell.Modern.WATER_STRIKE, 5, 2), 211 | EARTH_STRIKE(Spell.Modern.EARTH_STRIKE, 7, 3), 212 | FIRE_STRIKE(Spell.Modern.FIRE_STRIKE, 9, 4), 213 | WIND_BOLT(Spell.Modern.WIND_BOLT, 11, 5), 214 | WATER_BOLT(Spell.Modern.WATER_BOLT, 13, 6), 215 | EARTH_BOLT(Spell.Modern.EARTH_BOLT, 15, 7), 216 | FIRE_BOLT(Spell.Modern.FIRE_BOLT, 17, 8); 217 | 218 | private final Spell spell; 219 | private final int varpIndex; 220 | private final int spellIndex; 221 | 222 | ExSpell(Spell spell, int varpIndex, int spellIndex) { 223 | this.spell = spell; 224 | this.varpIndex = varpIndex; 225 | this.spellIndex = spellIndex; 226 | } 227 | 228 | public String getName() { 229 | return this.name().toLowerCase().replace("_", " "); 230 | } 231 | 232 | public boolean isAutoCasted() { 233 | return Varps.get(AUTO_CAST_VARP) == varpIndex; 234 | } 235 | 236 | public boolean canCast() { 237 | return getLevelRequired() <= Skills.getCurrentLevel(Skill.MAGIC); 238 | } 239 | 240 | public int getLevelRequired() { 241 | return spell.getLevelRequired(); 242 | } 243 | 244 | public Spell getSpell() { 245 | return spell; 246 | } 247 | 248 | public int getVarpIndex() { 249 | return varpIndex; 250 | } 251 | 252 | public int getSpellIndex() { 253 | return spellIndex; 254 | } 255 | 256 | public boolean onCorrectBook() { 257 | return spell.getBook().equals(Magic.getBook()); 258 | } 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /src/org/rspeer/runetek/api/component/ExClanChat.java: -------------------------------------------------------------------------------- 1 | package org.rspeer.runetek.api.component; 2 | 3 | import org.rspeer.runetek.adapter.component.InterfaceComponent; 4 | import org.rspeer.runetek.api.commons.Time; 5 | import org.rspeer.runetek.api.component.chatter.ClanChat; 6 | import org.rspeer.runetek.api.component.tab.Tab; 7 | import org.rspeer.runetek.api.component.tab.Tabs; 8 | 9 | /** 10 | * 11 | * 12 | * @author 2baad4u2 13 | */ 14 | public class ExClanChat { 15 | 16 | private static final int CLAN_CHAT_INDEX; 17 | private static final int JOIN_LEAVE_CHAT_COMPONENT = 22; 18 | private static final int CLAN_SETUP_COMPONENT = 24; 19 | 20 | private static final int CLAN_CHAT_SETUP_INDEX = 94; 21 | private static final int NAME_COMPONENT = 10; 22 | private static final int ENTER_COMPONENT = 13; 23 | private static final int TALK_COMPONENT = 16; 24 | private static final int KICK_COMPONENT = 19; 25 | private static final int CLOSE_SETUP_COMPONENT = 3; 26 | private static final int CLOSE_SETUP_SUBCOMPONENT = 13; 27 | 28 | static { 29 | CLAN_CHAT_INDEX = InterfaceComposite.CLAN_CHAT.getGroup(); 30 | } 31 | 32 | public static boolean isInChannel() { 33 | return ClanChat.isInChannel(); 34 | } 35 | 36 | public static boolean isNotInChannel() { 37 | return !isInChannel(); 38 | } 39 | 40 | public static boolean isOpen() { 41 | return Tab.CLAN_CHAT.isOpen(); 42 | } 43 | 44 | public static boolean open() { 45 | return isOpen() || (Tabs.open(Tab.CLAN_CHAT) && Time.sleepUntil(ExClanChat::isOpen, 1200L)); 46 | } 47 | 48 | /** 49 | * Join clan chat channel with specified username (will leave current clan chat if already in one). 50 | * 51 | * @param username of the clan chat to join 52 | * @return true if successfully tried to join clan chat 53 | */ 54 | public static boolean join(String username) { 55 | if (username == null|| username.isEmpty() || !Time.sleepUntil(ExClanChat::open, 1200L) || !leave()) return false; 56 | Time.sleepUntil(ExClanChat::isNotInChannel, 1200L); 57 | InterfaceComponent joinChatButton = Interfaces.getComponent(CLAN_CHAT_INDEX, JOIN_LEAVE_CHAT_COMPONENT); 58 | if (joinChatButton != null && joinChatButton.click()) { 59 | Time.sleepUntil(EnterInput::isOpen, 1200L); 60 | return EnterInput.initiate(username); 61 | } 62 | return false; 63 | } 64 | 65 | /** 66 | * Join your own clan chat (will leave current clan chat if already in one). 67 | * 68 | * @return true if successfully tried to join clan chat 69 | */ 70 | public static boolean join() { 71 | if (!Time.sleepUntil(ExClanChat::open, 1200L) || !setup() || !leave()) return false; 72 | Time.sleepUntil(ExClanChat::isNotInChannel, 1200L); 73 | InterfaceComponent joinChatButton = Interfaces.getComponent(CLAN_CHAT_INDEX, JOIN_LEAVE_CHAT_COMPONENT); 74 | if (joinChatButton != null && joinChatButton.click()) { 75 | Time.sleepUntil(EnterInput::isOpen, 1200L); 76 | InterfaceComponent usernameComp = Interfaces.getComponent(InterfaceComposite.CHATBOX.getGroup(), 57); 77 | return usernameComp != null && EnterInput.initiate(usernameComp.getText().split(":")[0]); 78 | } 79 | return false; 80 | } 81 | 82 | public static boolean leave() { 83 | if (!isInChannel()) return true; 84 | if (!Time.sleepUntil(ExClanChat::open, 1200L)) return false; 85 | InterfaceComponent leaveChatButton = Interfaces.getComponent(CLAN_CHAT_INDEX, JOIN_LEAVE_CHAT_COMPONENT); 86 | return leaveChatButton != null && leaveChatButton.click(); 87 | } 88 | 89 | public static boolean isSetupOpen() { 90 | return Interfaces.isVisible(CLAN_CHAT_SETUP_INDEX, 0); 91 | } 92 | 93 | public static boolean openSetup() { 94 | if (isSetupOpen()) return true; 95 | if (!open()) return false; 96 | InterfaceComponent clanSetup = Interfaces.getComponent(CLAN_CHAT_INDEX, CLAN_SETUP_COMPONENT); 97 | return clanSetup != null && clanSetup.click() && Time.sleepUntil(ExClanChat::isSetupOpen, 1200L); 98 | } 99 | 100 | public static boolean closeSetup() { 101 | if (!isSetupOpen()) return true; 102 | InterfaceComponent closeSetup = Interfaces.getComponent(CLAN_CHAT_SETUP_INDEX, CLOSE_SETUP_COMPONENT, CLOSE_SETUP_SUBCOMPONENT); 103 | return closeSetup != null && closeSetup.click(); 104 | } 105 | 106 | /** 107 | * Setup player's own clan chat with default values. 108 | * 109 | * @return true if clan chat is setup. 110 | */ 111 | public static boolean setup() { 112 | return isChatEnabled() || setClanName("a"); 113 | } 114 | 115 | /** 116 | * Setup player's own clan chat with specified params. 117 | * 118 | * @param name of the clan chat 119 | * @param enter minimum rank needed to enter chat 120 | * @param talk minimum rank needed to talk in chat 121 | * @param kick minimum rank needed to kick a player from chat 122 | * @return true if clan chat is setup. 123 | */ 124 | public static boolean setup(String name, Permission enter, Permission talk, Permission kick) { 125 | return setClanName(name) 126 | && setEnterPermission(enter) 127 | && setTalkPermission(talk) 128 | && setKickPermission(kick); 129 | } 130 | 131 | private static Permission getClanPermission(int component) { 132 | if (!Time.sleepUntil(ExClanChat::openSetup, 1200L)) return null; 133 | InterfaceComponent permission = Interfaces.getComponent(CLAN_CHAT_SETUP_INDEX, component); 134 | return permission != null && permission.getText() != null ? 135 | Permission.getPermission(permission.getText()) : null; 136 | } 137 | 138 | private static boolean setClanPermission(Permission permission, int component) { 139 | if (permission == null || !Time.sleepUntil(ExClanChat::openSetup, 1200L)) return false; 140 | InterfaceComponent permissionComponent = Interfaces.getComponent(CLAN_CHAT_SETUP_INDEX, component); 141 | return permissionComponent != null && permissionComponent.interact(permission.value); 142 | } 143 | 144 | public static Permission getEnterPermission() { 145 | return getClanPermission(ENTER_COMPONENT); 146 | } 147 | 148 | public static boolean setEnterPermission(Permission permission) { 149 | return setClanPermission(permission, ENTER_COMPONENT); 150 | } 151 | 152 | public static Permission getTalkPermission() { 153 | return getClanPermission(TALK_COMPONENT); 154 | } 155 | 156 | public static boolean setTalkPermission(Permission permission) { 157 | return setClanPermission(permission, TALK_COMPONENT); 158 | } 159 | 160 | public static Permission getKickPermission() { 161 | return getClanPermission(KICK_COMPONENT); 162 | } 163 | 164 | public static boolean setKickPermission(Permission permission) { 165 | if (permission != null && permission.ordinal() < 3) return false; 166 | return setClanPermission(permission, KICK_COMPONENT); 167 | } 168 | 169 | public static String getSetupClanName() { 170 | if (!Time.sleepUntil(ExClanChat::openSetup, 1200L)) return ""; 171 | InterfaceComponent nameComponent = Interfaces.getComponent(CLAN_CHAT_SETUP_INDEX, NAME_COMPONENT); 172 | return nameComponent != null ? nameComponent.getText() : ""; 173 | } 174 | 175 | public static boolean setClanName(String name) { 176 | if (name == null || name.isEmpty() || !Time.sleepUntil(ExClanChat::openSetup, 1200L)) return false; 177 | InterfaceComponent nameComponent = Interfaces.getComponent(CLAN_CHAT_SETUP_INDEX, NAME_COMPONENT); 178 | if (nameComponent == null || !nameComponent.interact("Set prefix")) return false; 179 | Time.sleepUntil(EnterInput::isOpen, 1200L); 180 | return EnterInput.initiate(name); 181 | } 182 | 183 | public static boolean isChatEnabled() { 184 | return !isChatDisabled(); 185 | } 186 | 187 | public static boolean isChatDisabled() { 188 | return getSetupClanName().equals("Chat disabled"); 189 | } 190 | 191 | public static boolean disableChat() { 192 | if (!Time.sleepUntil(ExClanChat::openSetup, 1200L)) return false; 193 | InterfaceComponent nameComponent = Interfaces.getComponent(CLAN_CHAT_SETUP_INDEX, NAME_COMPONENT); 194 | return nameComponent != null && nameComponent.interact("Disable"); 195 | } 196 | 197 | public enum Permission { 198 | ANYONE("Anyone"), 199 | ANY_FRIENDS("Any friends"), 200 | RECRUIT("Recruit+"), 201 | CORPORAL("Corporal+"), 202 | SERGEANT("Sergeant+"), 203 | LIEUTENANT("Lieutenant+"), 204 | CAPTAIN("Captain+"), 205 | GENERAL("General+"), 206 | ONLY_ME("Only me"); 207 | 208 | private final String value; 209 | 210 | Permission(String value) { 211 | this.value = value; 212 | } 213 | 214 | public String getValue() { 215 | return value; 216 | } 217 | 218 | static Permission getPermission(String value) { 219 | for (Permission p : values()) 220 | if (p.getValue().equals(value)) return p; 221 | return null; 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /src/org/rspeer/runetek/api/component/ExWilderness.java: -------------------------------------------------------------------------------- 1 | package org.rspeer.runetek.api.component; 2 | 3 | import org.rspeer.runetek.adapter.component.InterfaceComponent; 4 | import org.rspeer.runetek.adapter.scene.Player; 5 | import org.rspeer.runetek.adapter.scene.SceneObject; 6 | import org.rspeer.runetek.api.commons.Time; 7 | import org.rspeer.runetek.api.commons.math.Random; 8 | import org.rspeer.runetek.api.movement.position.Area; 9 | import org.rspeer.runetek.api.scene.Players; 10 | import org.rspeer.runetek.api.scene.SceneObjects; 11 | 12 | import java.util.function.Predicate; 13 | 14 | /** 15 | * @author Typically 16 | */ 17 | public class ExWilderness { 18 | 19 | private static final int WILDERNESS_ROOT_INTERFACE_ID = 90; 20 | private static final int WILDERNESS_WARNING_INTERFACE_ID = 475; 21 | 22 | private static final InterfaceAddress WILDERNESS_ROOT_LEVEL_ADDRESS = new InterfaceAddress( 23 | () -> Interfaces.getFirst(WILDERNESS_ROOT_INTERFACE_ID, interfaceComponent -> interfaceComponent.getText().contains("Level"))); 24 | 25 | private static final InterfaceAddress WILDERNESS_WARNING_CHECKBOX_ADDRESS = new InterfaceAddress( 26 | () -> Interfaces.getFirst(WILDERNESS_WARNING_INTERFACE_ID, interfaceComponent -> 27 | interfaceComponent.containsAction("Enable warning") || interfaceComponent.containsAction("Disable warning"))); 28 | 29 | private static final InterfaceAddress WILDERNESS_WARNING_ENTER_ADDRESS = new InterfaceAddress( 30 | () -> Interfaces.getFirst(WILDERNESS_WARNING_INTERFACE_ID, interfaceComponent -> interfaceComponent.containsAction("Enter Wilderness"))); 31 | 32 | private static final Area WILDERNESS_SURFACE_AREA = Area.rectangular(2944, 3521, 3391, 3967); 33 | private static final Area WILDERNESS_EDGEVILLE_DUNGEON_AREA = Area.rectangular(3135, 9918, 3072, 10047); 34 | 35 | /** 36 | * Returns the current Wilderness level 37 | * 38 | * @return the current Wilderness level 39 | */ 40 | public static int getLevel() { 41 | // Get first interface component that contains the text "Level" 42 | final InterfaceComponent levelComponent = WILDERNESS_ROOT_LEVEL_ADDRESS.resolve(); 43 | 44 | // If it is null then return -1 45 | if (levelComponent == null) 46 | return -1; 47 | 48 | // If it is not null then get the text and split it by a space 49 | final String[] levelStringArray = levelComponent.getText().split(" "); 50 | 51 | // If the length of the string array is 0; return -1 52 | if (levelStringArray.length == 0) 53 | return -1; 54 | 55 | // Get the level from the string array 56 | final String levelString = levelStringArray[1]; 57 | 58 | // Parse the string to an integer 59 | return Integer.parseInt(levelString); 60 | } 61 | 62 | /** 63 | * Checks whether the wilderness warning is open or not 64 | * 65 | * @return true if the wilderness warning is open; false otherwise 66 | */ 67 | public static boolean isWarningOpen() { 68 | // If the warning button is not null then the warning is open 69 | return WILDERNESS_WARNING_ENTER_ADDRESS.resolve() != null; 70 | } 71 | 72 | /** 73 | * Checks whether the local player is in the wilderness or not 74 | * 75 | * @return true if the local player is in the wilderness; false otherwise 76 | */ 77 | public static boolean isInWilderness() { 78 | // If local player is contained within one of these areas (there are probably more) then return true 79 | // If the local player is not in any of the defined areas then fallback on the wilderness interface 80 | return WILDERNESS_SURFACE_AREA.contains(Players.getLocal()) 81 | || WILDERNESS_EDGEVILLE_DUNGEON_AREA.contains(Players.getLocal()) 82 | || WILDERNESS_ROOT_LEVEL_ADDRESS.resolve() != null; 83 | } 84 | 85 | 86 | /** 87 | * Checks whether a target player is in the wilderness or not 88 | * 89 | * @param target the player to check 90 | * @return true if the target player is in the wilderness; false otherwise 91 | */ 92 | public static boolean isInWilderness(final Player target) { 93 | // If the target player is equal to the local player then use the local player check 94 | if (target.equals(Players.getLocal())) 95 | return isInWilderness(); 96 | 97 | // If target player is contained within one of these areas (there are probably more) then return true 98 | return WILDERNESS_SURFACE_AREA.contains(target) 99 | || WILDERNESS_EDGEVILLE_DUNGEON_AREA.contains(target); 100 | } 101 | 102 | 103 | /** 104 | * Checks whether the specified player can be attack by a target player or not 105 | * 106 | * @param player the player to check from 107 | * @param target the player that is checked 108 | * @return true if the specified player can be attacked by the target player; false otherwise 109 | */ 110 | public static boolean canAttack(final Player player, final Player target) { 111 | // Get combat levels from both players 112 | final int combatLevel = player.getCombatLevel(); 113 | final int targetCombatLevel = target.getCombatLevel(); 114 | 115 | // Get the current wilderness level 116 | final int wildernessLevel = getLevel(); 117 | 118 | // Calculate the minimum and maximum attackable combat level 119 | final int minLevel = combatLevel - wildernessLevel; 120 | final int maxLevel = combatLevel + wildernessLevel; 121 | 122 | // Return true if the target combat level is in that range 123 | return targetCombatLevel >= minLevel && targetCombatLevel <= maxLevel; 124 | } 125 | 126 | /** 127 | * Checks whether the local player can be attack by a target player or not 128 | * 129 | * @param target the player that is checked 130 | * @return true if the local player can be attacked by the target player; false otherwise 131 | */ 132 | public static boolean canAttackLocal(final Player target) { 133 | return canAttack(Players.getLocal(), target); 134 | } 135 | 136 | /** 137 | * Checks whether the local player can be attacked by any loaded player 138 | * 139 | * @return true if the local player can be attacked by any loaded player; false otherwise 140 | */ 141 | public static boolean canAnyPlayerAttackLocal() { 142 | // If the local player is not in the wilderness return false 143 | if (!isInWilderness()) 144 | return false; 145 | 146 | // Loop through all loaded players (exclude local player) 147 | for (Player player : Players.getLoaded(player -> !player.equals(Players.getLocal()))) { 148 | // If the loaded player can attack the local player return true 149 | if (canAttackLocal(player)) { 150 | return true; 151 | } 152 | } 153 | 154 | return false; 155 | } 156 | 157 | /** 158 | * Approves the wilderness warning 159 | * 160 | * @param remember click on remember so the warning doesn't pop up again 161 | * @return true if the click on "Enter Wilderness" is successful; false otherwise 162 | */ 163 | public static boolean approveWarning(final boolean remember) { 164 | // If remember is true continue 165 | if (remember) { 166 | // Get first interface component the text "Disable warning" 167 | final InterfaceComponent warningCheckboxComponent = WILDERNESS_WARNING_CHECKBOX_ADDRESS.resolve(); 168 | 169 | // If the component is not null and it contains the disable warning action continue 170 | if (warningCheckboxComponent != null && warningCheckboxComponent.containsAction("Disable warning")) { 171 | // Click the warning checkbox 172 | if (warningCheckboxComponent.click()) { 173 | // Sleep until the checkbox contains the enable warning action (verifies a successful click) 174 | if (!Time.sleepUntil(() -> warningCheckboxComponent.containsAction("Enable warning"), Random.low(2000, 4000))) { 175 | // If it didn't verify do a early return 176 | return false; 177 | } 178 | } 179 | } 180 | } 181 | 182 | // Get first interface component the text "Enter Wilderness" 183 | final InterfaceComponent enterWildernessComponent = WILDERNESS_WARNING_ENTER_ADDRESS.resolve(); 184 | 185 | // If the component is null return false 186 | if (enterWildernessComponent == null) 187 | return false; 188 | 189 | return enterWildernessComponent.click(); 190 | } 191 | 192 | /** 193 | * Enter the wilderness using a set SceneObject and action 194 | * 195 | * @param sceneObject the SceneObject to click 196 | * @param action the action to use on the specified SceneObject 197 | * @param remember click on remember so the warning doesn't pop up again 198 | * @return true if the player is in the wilderness; false otherwise 199 | */ 200 | public static boolean enter(final SceneObject sceneObject, final String action, final boolean remember) { 201 | // If the local player is already in the wilderness; return true 202 | if (isInWilderness()) 203 | return true; 204 | 205 | // If the scene object is null; return false 206 | if (sceneObject == null) 207 | return false; 208 | 209 | // Interact with the scene object using the specified action if the warning isn't open 210 | if (!isWarningOpen()) 211 | sceneObject.interact(action); 212 | 213 | // Sleep till the warning pops up or the local player is in the wilderness 214 | Time.sleepUntil(() -> isWarningOpen() || isInWilderness(), Random.high(6000, 10000)); 215 | 216 | // If the warning is open, approve the warning and sleep till it is no longer open 217 | if (isWarningOpen() && approveWarning(remember)) { 218 | Time.sleepUntil(() -> !isWarningOpen(), Random.low(2000, 4000)); 219 | } 220 | 221 | // Sleep until the player is in the wilderness 222 | return Time.sleepUntil(ExWilderness::isInWilderness, Random.low(2000, 4000)); 223 | } 224 | 225 | /** 226 | * Enter the wilderness using a set SceneObject and action 227 | * 228 | * @param name the name of the SceneObject to click 229 | * @param action the action to use on the specified SceneObject 230 | * @param remember click on remember so the warning doesn't pop up again 231 | * @return true if the player is in the wilderness; false otherwise 232 | */ 233 | public static boolean enter(final String name, final String action, final boolean remember) { 234 | // Get the nearest scene object by the specified name 235 | final SceneObject sceneObject = SceneObjects.getNearest(name); 236 | 237 | // Enter the wilderness using that scene object 238 | return enter(sceneObject, action, remember); 239 | } 240 | 241 | /** 242 | * Enter the wilderness using a set SceneObject and action 243 | * 244 | * @param predicate the predicate for the SceneObject to click 245 | * @param action the action to use on the specified SceneObject 246 | * @param remember click on remember so the warning doesn't pop up again 247 | * @return true if the player is in the wilderness; false otherwise 248 | */ 249 | public static boolean enter(final Predicate predicate, final String action, final boolean remember) { 250 | // Get the nearest scene object by the specified name 251 | final SceneObject sceneObject = SceneObjects.getNearest(predicate); 252 | 253 | // Enter the wilderness using that scene object 254 | return enter(sceneObject, action, remember); 255 | } 256 | 257 | } 258 | --------------------------------------------------------------------------------