Jump to content

liverare

Scripter II
  • Posts

    1296
  • Joined

  • Last visited

  • Days Won

    3
  • Feedback

    0%

Everything posted by liverare

  1. Nice, but computing the required XP on each call (especially on paint) will only result in performance issues. I'd suggest just caching the values into a giant 2D array.
  2. Last-second update push. I added in a fail-safe to prevent the continued purchasing of items for slots that were previously holding your original required item. It was a logical error I spotted.
  3. liverare

    New Shop API

    Shop V2 Port Shop Item V2 Port I'll update more in the future, and feel free to contribute! Shop.scr import java.awt.Graphics2D; import java.util.HashSet; import java.util.Set; import org.osbot.script.MethodProvider; import org.osbot.script.Script; import org.osbot.script.rs2.model.Item; import org.osbot.script.rs2.model.NPC; import org.osbot.script.rs2.ui.RS2Interface; import org.osbot.script.rs2.ui.RS2InterfaceChild; /** * * @author LiveRare * * Shop class that provides simple access mechanisms to purchase items * from a shop interface. * */ public class Shop { /* * CONSTANT VARIABLES */ /** * Common parent ID of most (if not all) shops. */ public static final int COMMON_PARENT_ID = 300; /** * Common child ID for the component that contains the data for the items. */ public static final int COMMON_CONTENT_CHILD_ID = 75; /** * Common child ID for the shop's title. */ public static final int COMMON_TITLE_CHILD_ID = 76; /** * Common child ID for the shop's close button. */ public static final int COMMON_CLOSE_CHILD_ID = 92; /** * Maximum amount of slots available in a shop interface */ public static final int MAXIMUM_SLOT_AMOUNT = 40; /* * DYNAMIC VARIABLES */ /** * Script instance that will be accessing the interfaces from. */ private final Script script; /** * A cache of 40 available items. * * Note: 40 Is the maximum amount of item slots a shop can hold. */ private final ShopItem[] items; /** * ID values for the parent interface and child components. */ private final int parentID, childContentID, childTitleID, childCloseID; /** * Parent instance that will be accessed elsewhere in this class. */ private RS2Interface parent; /** * Name of the clerk to interact with. */ private String npcName; /* * Constructors */ public Shop(Script script, String npcName, int parentID, int childContentID, int childTitleID, int childCloseID) { this.script = script; this.npcName = npcName; this.parentID = parentID; this.childContentID = childContentID; this.childTitleID = childTitleID; this.childCloseID = childCloseID; this.items = new ShopItem[MAXIMUM_SLOT_AMOUNT]; init(); } public Shop(Script script, String npcName) { this(script, npcName, COMMON_PARENT_ID, COMMON_CONTENT_CHILD_ID, COMMON_TITLE_CHILD_ID, COMMON_CLOSE_CHILD_ID); } /* * Analytics methods */ /** * This class provides a property for an NPC name. This will allow the * {@link Shop#open(String)} function to execute with a viable NPC name. * * @param npcName * Name of the NPC to find */ public void setNPCName(String npcName) { this.npcName = npcName; } /** * This method will initialise the ShopItem 2D array that can contain up to * 40 ({@link Shop#MAXIMUM_SLOT_AMOUNT}). */ public void init() { for (int i = 0; i < MAXIMUM_SLOT_AMOUNT; i++) items[i] = new ShopItem(script, i); } /** * @Deprecated this method is really inefficient usage of the item cache * acquired from the shop interface. Since only one index is * required, the rest are disregarded. This method should only * be regarded if it's absolutely necessary! * * @param slot * Slot to validate * @return <tt>Validation was successful</tt> */ @Deprecated public boolean validate(int slot) { try { Item[] items = getItems(); this.items[slot].setDate(slot < items.length ? items[slot] : null); return true; } catch (Exception e) { this.items[slot].setDate(null); e.printStackTrace(); return false; } } /** * This method will analyse the shop's contents and stores the data in the * 2D ShopItem array. * * @return <tt>Successfully validated the shop's content</tt> */ public boolean validate() { try { Item[] items = getItems(); for (int i = 0; i < MAXIMUM_SLOT_AMOUNT; i++) this.items[i].setDate(i < items.length ? items[i] : null); return true; } catch (Exception e) { // If error occurs reset all ShopItem cache init(); e.printStackTrace(); return false; } } /** * * @return <tt>Shop interface is valid, thus; shop is open</tt> */ public boolean isOpen() { return (parent = script.client.getInterface(parentID)) != null && parent.isValid() && parent.isVisible(); } /** * * @return Shop's title */ public String getTitle() { return parent.getChild(childTitleID).getMessage(); } /** * * @return Items in the shop */ public Item[] getItems() { return parent.getItems(childContentID); } public int getAmount(int... itemIDs) { if (itemIDs == null || itemIDs.length == 0) return -1; int amount = 0; i: for (ShopItem item : items) if (item != null) for (int id : itemIDs) { if (item.getID() == id) { amount += item.getAmount(); continue i; } } return amount; } public int getAmount(String... itemNames) { if (itemNames == null || itemNames.length == 0) return -1; int amount = 0; i: for (ShopItem item : items) if (item != null && isStringValid(item.getName())) for (String name : itemNames) if (isStringValid(name)) { if (item.getName().equalsIgnoreCase(name)) { amount += item.getAmount(); continue i; } } return amount; } /** * Acquire an item based on its slot in the shop interface. * * ONLY USE THIS METHOD IF YOU <u>KNOW</u> FOR CERTAIN THE SLOT'S ITEM WILL * BE CONSISTENT, OTHERWISE USE ANOTHER GETTER. * * @param slot * Slot position within the shop * @return ShopItem by index */ public ShopItem getItemBySlot(int slot) { return slot >= 0 && slot < MAXIMUM_SLOT_AMOUNT ? this.items[slot] : null; } /** * Acquire an item based on item ID. * * @param ids * IDs of the item to search for * @return First shop item with a corresponding ID */ public ShopItem getItemByID(int... ids) { if (ids != null && ids.length > 0) for (ShopItem nextItem : items) for (int nextID : ids) if (nextItem.getID() == nextID) return nextItem; return null; } public ShopItem[] getItemsByID(int... ids) { Set<ShopItem> cache = new HashSet<>(); if (ids != null && ids.length > 0) for (ShopItem nextItem : items) for (int nextID : ids) if (nextItem.getID() == nextID) cache.add(nextItem); return cache.isEmpty() ? null : cache .toArray(new ShopItem[cache.size()]); } /** * Acquire an item based on item name. * * @param names * Names of the item to search for * @return First shop item with a corresponding name */ public ShopItem getItemByName(String... names) { if (names != null && names.length > 0) for (ShopItem nextItem : items) { String name = nextItem.getName(); if (!isStringValid(name)) continue; else for (String nextName : names) if (isStringValid(nextName) && name.equalsIgnoreCase(nextName)) return nextItem; } return null; } public ShopItem[] getItemsByName(String... names) { Set<ShopItem> cache = new HashSet<>(); if (names != null && names.length > 0) for (ShopItem nextItem : items) { String name = nextItem.getName(); if (!isStringValid(name)) continue; else for (String nextName : names) if (isStringValid(nextName) && name.equalsIgnoreCase(nextName)) cache.add(nextItem); } return cache.isEmpty() ? null : cache .toArray(new ShopItem[cache.size()]); } public void paint(Graphics2D g) { for (ShopItem next : items) next.draw(g); } /* * Interact methods */ public int tryPurchaseInvAmount(ShopItem item) throws InterruptedException { final int empty = script.client.getInventory() .getEmptySlots(); return tryPurchase(item, item.getAmount() > empty ? empty : item.getAmount()); } public int tryPurchase(ShopItem item, int amount) throws InterruptedException { if (item != null && amount > 0 && this.isOpen()) { this.validate(); int total = amount, onesPurchase = 0, fivesPurchase = 0, tensPurchase = 0; if (total >= 10) { tensPurchase = total / 10; total -= tensPurchase * 10; } if (total >= 5) { fivesPurchase = 1; total -= 5; } onesPurchase = total; int count = 0; try { for (int i = 0; i < tensPurchase; i++) if (purchase(item, 10)) count += 10; for (int i = 0; i < fivesPurchase; i++) if (purchase(item, 5)) count += 5; for (int i = 0; i < onesPurchase; i++) if (purchase(item, 1)) count += 1; } catch (RuntimeException e) { script.log(e.getMessage()); } return amount - count; } return -1; } private boolean purchase(ShopItem item, int amount) throws InterruptedException { final int oldID = item.getID(); validate(item.getSlot()); if (oldID != item.getID()) throw new RuntimeException("Inconsistent item! Required: " + oldID + ", but found: " + item.getID()); else if (item.getAmount() <= 0) return false; switch (amount) { case 1: return item.purchaseOne(); case 5: return item.purchaseFive(); case 10: return item.purchaseTen(); } return false; } public int trySell(Item item, int amount) throws InterruptedException { if (item != null && amount > 0 && this.isOpen()) { this.validate(); int total = amount, onesPurchase = 0, fivesPurchase = 0, tensPurchase = 0; if (total >= 10) { tensPurchase = total / 10; total -= tensPurchase * 10; } if (total >= 5) { fivesPurchase = 1; total -= 5; } onesPurchase = total; int count = 0; try { for (int i = 0; i < tensPurchase; i++) if (sell(item, 10)) count += 10; for (int i = 0; i < fivesPurchase; i++) if (sell(item, 5)) count += 5; for (int i = 0; i < onesPurchase; i++) if (sell(item, 1)) count += 1; } catch (RuntimeException e) { script.log(e.getMessage()); } return amount - count; } return -1; } private boolean sell(Item item, int amount) throws InterruptedException { return script.client.getInventory().interactWithId(item.getId(), "Sell " + amount); } /** * This method requires a pre-initialised <i>valid</i> NPC name or one needs * to be provided on the constructor. * * @param altNPCName * Alternative NPC to search for * @return <tt>Shop is open</tt> */ public boolean tryOpen(String altNPCName) throws InterruptedException { boolean open = isOpen(); try { if (open) return true; NPC npc = script .closestNPCForName(isStringValid(altNPCName) ? altNPCName : npcName); if (npc != null && npc.exists() && npc.interact("Trade")) script.sleep(MethodProvider.random(350, 600)); return open = isOpen(); } catch (Exception e) { e.printStackTrace(); return false; } finally { if (open) validate(); } } public boolean tryOpen() throws InterruptedException { return tryOpen(null); } public boolean close() throws InterruptedException { if (!isOpen()) // Prevent unnecessary re-closing return false; RS2InterfaceChild child = parent.getChild(childCloseID); return child != null && child.interact("Close"); } /* * Static methods */ private static boolean isStringValid(String arg0) { return arg0 != null && !arg0.isEmpty(); } } ShopItem.scr import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Stroke; import org.osbot.script.Script; import org.osbot.script.mouse.RectangleDestination; import org.osbot.script.rs2.model.Item; /** * * @author LiveRare * * This class is designed to store the details for every item * within a shop interface. There should be only 40 instances * of this object stored in an array because there's a maximum * of 40 available item slots in a shop interface. * */ public class ShopItem { public static final Stroke STROKE = new BasicStroke(0.655f); public static final Color FOREGROUND_COLOR = new Color(255, 255, 255, 150); public static final Point ITEM_STARTING_POSITION = new Point(80, 70); public static final Dimension ITEM_BOUNDS = new Dimension(30, 25); public static final Dimension SPACE_MARGIN = new Dimension(17, 23); private final Script script; private final int slot; private final int slotColumn; private final int slotRow; private final Rectangle slotBounds; private final RectangleDestination slotDestination; private int id; private String name; private int amount; public ShopItem(Script script, int slot) { this.script = script; this.slot = slot; this.slotColumn = (slot % 8); this.slotRow = (int) (slot / (double) 8); this.slotBounds = new Rectangle( ITEM_STARTING_POSITION.x + (ITEM_BOUNDS.width + SPACE_MARGIN.width) * (slotColumn), ITEM_STARTING_POSITION.y + (ITEM_BOUNDS.height + SPACE_MARGIN.height) * (slotRow), ITEM_BOUNDS.width, ITEM_BOUNDS.height); this.slotDestination = new RectangleDestination(slotBounds); } @Override public boolean equals(Object obj) { return obj != null && obj instanceof ShopItem && ((ShopItem) obj).getSlot() == getSlot(); } @Override public String toString() { return "[Slot: " + slot + " | Name: " + name + " | Item ID: " + id + " | Amount: " + amount + "]"; } /* * Item profile values */ public int getSlot() { return slot; } public int getID() { return id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void setID(int id) { this.id = id; } public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; } public int getSlotColumn() { return slotColumn; } public void setDate(Item item) { if (item != null) { this.id = item.getId(); this.name = item.getName(); this.amount = item.getAmount(); } else { this.id = -1; this.name = "null"; this.amount = -1; } } /* * Other methods */ public int getSlotRow() { return slotRow; } public Rectangle getSlotBounds() { return slotBounds; } public RectangleDestination getSlotDestination() { return slotDestination; } public boolean interact(String interact) throws InterruptedException { script.client.moveMouse(getSlotDestination(), false); return script.selectOption(null, getSlotDestination(), interact); } public boolean purchaseOne() throws InterruptedException { return interact("Buy 1"); } public boolean purchaseFive() throws InterruptedException { return interact("Buy 5"); } public boolean purchaseTen() throws InterruptedException { return interact("Buy 10"); } public void draw(Graphics2D g) { Rectangle r = new Rectangle(slotBounds.x - 4, slotBounds.y - 6, slotBounds.width + 4, slotBounds.height + 10); { // Draw bounding box g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); g.setStroke(STROKE); g.setColor(FOREGROUND_COLOR); g.draw(r); g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT); } { // Draw text g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); FontMetrics fm = g.getFontMetrics(); String id = String.valueOf(this.id); int width = (int) fm.getStringBounds(id, g).getWidth(); Point p = new Point(r.x + ((r.width - width) / 2), r.y + 32); g.setColor(Color.BLACK); g.drawString(id, p.x - 1, p.y - 1); g.drawString(id, p.x - 1, p.y + 1); g.drawString(id, p.x + 1, p.y - 1); g.drawString(id, p.x + 1, p.y + 1); g.setColor(Color.WHITE); g.drawString(id, p.x, p.y); g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); } } } Example of usage: Shop shop; @Override public void onStart() { shop = new Shop(this, "Shop keeper"); // Shop keeper in the Varrock general store } @Override public int onLoop() throws InterruptedException { if (shop.isOpen() && shop.validate()) { //Validate method is required to launch at least once before item profiling ShopItem item = shop.getItemByName("Willow shortbow (u)"); // Common item dumped in that store if (item != null) { // ENSURE TO NULL-CHECK int failedToPurchaseCount = shop.tryPurchase(item, 26); // Item amount that wasn't purchased! log("Need to purchase: " + failedToPurchaseCount + " more..."); // Debug string } } else { shop.tryOpen(); // shop.tryOpen(String) can be used instead if you didn't already assign ab NPC name on constructor } return 300; } @Override public void onPaint(Graphics arg0) { Graphics2D g = (Graphics2D) arg0; if (shop != null && shop.isOpen()) { shop.paint(g); } } Note: There may be a problem with items with a quantity of 0. I will look into this tomorrow.
  4. Redundant. Briefly hovering over a random skill wont fool a bot-hunter or any possible detection system. Instead of subjecting every end-user to pointless odd moments of behavioral difference, make a script that's too effective to get caught in the first place. I imagine both bot-hunters and the detection system pray for a consistent failures and flaws. Focus on that.
  5. liverare

    item dump

    You don't really need to provide actions because they would be most likely handled by the script writer. But if you could find a way to distinguish all redundant items from the dump and remove them, that would be useful. (i.e., "Cave Horror".) I'll improve the data dump later by grouping together all IDs for items with the same name.
  6. liverare

    item dump

    Good contribution. I condensed your 593 KB of data to 191 KB, which includes removing items entitled "null". This will improve performance when implementing it into my local script. I will be able to make a fast item look-up.
  7. Maybe post your GUI code? It would help us. Wait, are you the developer?
  8. Perhaps this is what you're looking for? I understand the concept. I can't recall what bot xbooting was abused on. It was used to override the main class of some old bot, executing commands that toyed with the settings, resulting in attaining premium/developer status. I think it may have been RSBuddy. As for the implementation of it for the RS client...I ain't played around with making a client myself. I honestly couldn't help you with this. But you should definitely post for help on p****bot's Developer forum section—there are a lot of cleverfucks who will know absolutely anything/everything you need to know about client hacking.
  9. Your code is too broad and it doesn't take into consideration potential latency issues someone may experience, e.g., I don't play on American servers because there would be too much latency at times. If I were to bot, this would undoubtedly effect the bot's performance.
  10. I don't bot, there are plenty of users who will help you out there. Instead, I review the code. It's good for learning experience and it allows me to offer improvements to where I see fit. If you want me to review the beta version, I won't mind at all--especially since I've lately been reworking my Clue Scroll Aid. I'm hoping to release an open-sourced version sometime soon.
  11. The thoughts good, but sadly, no. There's already an effective, mainstream application for your specific purpose: Rocketdock. Edit: I haven't used their application in years! They have added a new feature that allows you to minimize windows to the dock, i.e., media players. This may be useful for your bots. ...Hmm, maybe I re-install Rocketdock.
  12. You should add a power-runner mode that just glitches through to the herbs/fruit tree.
  13. Well, I gave you the most clues. Free version pl0x. Here's my system: Detail all clue scrolls in the XML. Create new instances of a 'clue scroll profile' that validates, parses and interpret the information for every documented clue scroll read from the XML file. Cache all the profiles in a Hashmap as values. The keys will be the clue scroll ID stored in the profile's instance. Check inventory for an item named "Clue scroll". If found, acquire its ID. Query the cache to find the details of that clue scroll. If not found, throw an error displaying something like "Clue scroll [iD] is not documented." Analyse the gotten instance and generate a new outcome, i.e., displaying the information or instructing your bot to act upon the information. The hardest part of this process is the first two tasks...and possibly the last task if you're creating a bot. Right, the only problem I see with this method is that should something go wrong, its very hard to fix. Right now I am leaning to creating a separate controller for each specific clue - more work, but better stability. Obviously looping through 100+ clues isn't efficient, so it finds the best node to go to based on ID. Updates: Just some more data collection 2 weeks off start tomorrow expect (hope) for a free public beta by the end! Fail-safe methods could be made generic and consistent, with the only variants in their handling being down to the extra data/information for the clue scroll. I obviously can't know how your node system works, but I assume you're crating individual classes for each clue?
  14. if(tab != ChatTab.GAME || tab != ChatTab.ALL) I believe you were supposed to use "&&". I got to work on making a fully working API you can use. Edited the API to make it not require Client to be a constant parameter for methods. However, an enum couldn't be used to achieve this.
  15. Well, I gave you the most clues. Free version pl0x. Here's my system: Detail all clue scrolls in the XML. Create new instances of a 'clue scroll profile' that validates, parses and interpret the information for every documented clue scroll read from the XML file. Cache all the profiles in a Hashmap as values. The keys will be the clue scroll ID stored in the profile's instance. Check inventory for an item named "Clue scroll". If found, acquire its ID. Query the cache to find the details of that clue scroll. If not found, throw an error displaying something like "Clue scroll [iD] is not documented." Analyse the gotten instance and generate a new outcome, i.e., displaying the information or instructing your bot to act upon the information. The hardest part of this process is the first two tasks...and possibly the last task if you're creating a bot.
  16. Here's a cache of level 3 clue scrolls I documented. ...Perhaps I should revisit my Clue Scroll Aid script.
  17. Can you please... No? Well that sucks, I was hoping you could set up a combination of tasks. I assumed so since you used check boxes.
  18. Errm, so can you cut, string, cut&string, make arrows, make bolts, make darts, gen-tip bolts, arrow shafts, headless arrows, broad bolts and arrows simultaneously?
  19. liverare

    Blind Walk

    OSBot should really implement a new exception surrounding walking: PositionOutOfReachException - Destination tile exceeds the mini-map's visible radius. (bout 15~ tiles, I think.) UnreachableDestinationException - Paths can't be generated (run-time) between two positions. IncompleteTraversalException - Moving to the destination tile was unsuccessful. Each exception should provide a sufficient enough information for developers to try to 're-correct' prior movements. Your code would be a solution for the first exception idea. I wrote the exceptions in this order to represent the linear checks that would be performed, and I believe this would provide OSBot with better walk handling.
  20. To be honest, I'd have a webpage with two content tables; one for core-scripting tutorials, i.e., presentation, packaging, structure and requirements, etc. The second table should be for "extra" tutorials, i.e., how to calculate XP p/hour, how to create custom interaction features, how to save a user profile, etc.
  21. I'm clueless in JavaScript, so I'm guessing: "Amerifat" is not a String type, thus; you can't return its length. I say this because, in Java, you define a String by String, not var. length; is not the correct way of returning the String's length. I say this because, in Java; you get the String's length with length();
  22. inb4 OP whines to mod to remove my post. Why would you even need to keep a cache of all the NPC based on whether they are in combat or not? Ultimately, you need one single result. One result that you can instruct your bot to attack, and here's how to: Instructions how-to: Get a cache of existing monsters. Filter out the monsters that you aren't interested in. Sort out the remaining monsters based on distance. Poll for the first monster in that sorted cache. You can slap all that in a single method. Heck, I even made an adapter for it. The only purpose I can think of for your code is to gather statistics.
  23. Why not just extend the HashMap<String, Object> onto the class and create a static constant of the class itself? You could remove all the already-existing methods from the class, i.e., #getValue(String). Here's what I would do instead: public class ScriptAttribute extends HashMap<String, Object> { private static final ScriptAttribute INSTANCE = new ScriptAttribute(); private static final String KEY_STATUS = "CURRENT_STATUS"; static { INSTANCE.put(KEY_STATUS, "null"); } private ScriptAttribute() { } public String getStatus() { return (String) get(KEY_STATUS); } public void setStatus(String status) { put(KEY_STATUS, status); } /** * This may look weird, but: * <code> * #setStatus("Al Kharid"); * #updateStatus("Walking to Bank"); * * #getStatus() @return "Al Kharid - Walking to Bank" * </code> * * @param updateStatus * Status to concatenate onto the prior state */ public void updateStatus(String updateStatus) { put(KEY_STATUS, getStatus() + " - " + updateStatus); } public void remove(String... keys) { if (keys == null || keys.length == 0) for (String next : keys) if (next != null && next.length() > 0) remove(next); } public static ScriptAttribute getInstance() { return INSTANCE; } } ...A few changes, but in a ScriptAdapter class (A class that merely extends Script and allows script conformity) would be: public class ScriptAdapter extends Script { . . . public static ScriptAttribute getAttributeHandler() { return ScriptAttribute.getInstance(); } } I would do this so that you can direct the access to the script's attributes via the main script class. 1 second after posting and I just remembered something:: I would override the #remove(Object) to prevent the removal of important keys, i.e., CURRENT_STATUS, etc. P.S. I did kind of rush the code, so updateStatus(String) would continuously append the existing String for CURRENT_STATUS, e.g., "Al Kharid - Going to Bank - Going to Mines - ..." ..It's not too bad, especially if you wanted to keep track of the executing states in order, but it wouldn't look good in the paint, though.
  24. JaGeX have control over the gaming environment, so I would assume they have systems set in motion that look out for large clusters of players (that aren't in consistently populated areas), and track what activity they're parking in (i.e., woodcutting) and how they interact with the gaming environment against the other fellow players. I assume that they average out the interactions of everyone involved and see if there's a correlation between obvious botters. They probably map out movements on a 2D grid and see if there are oddities in paths that a large cluster of users/bots seem to exhibit routinely. JaGeX probably graph out user interactions with in-game entities to see if there are common delays with particular players. While such data could be dismissed if it gathered from an isolated individual, I'd imagine that if the interaction patterns are frequent among multiple players, it's probably flagged as a call to concern. I assume they verify their findings by sending in in-game mods to evaluate the environment and the users. Your script may check for mods, but that won't do shit. Remember; JaGeX control the game. It wouldn't be far-fetched to assume they have the ability to exist server-side only--if they wanted. It's why I find anti-bans redundant. They don't do much. Jagex may be able to snipe out large clusters of bots in a single instance, but when it comes to bots who occupy the almost "outland" regions, I think they rely on other fellow players to file a report. ...Which is why I find anti-bans redundant. Once you're reported by a fellow player, it doesn't matter how much you shake your camera or hover over your skills, it's too late to "un-file" the report set against you. And you only justify said report if you continue to exhibit robot-like responses.
×
×
  • Create New...