Jump to content

yfoo

Lifetime Sponsor
  • Posts

    238
  • Joined

  • Last visited

  • Days Won

    1
  • Feedback

    100%

Everything posted by yfoo

  1. For a fishing script I do the following. I generate a gaussian mean and std dev at script start. - AFK when fishing (mouse offscreen) + AFK afterwards for a gaussian random amount of time. - Drop fish even if inventory is nearly full after afking - Random shift click drop orders (ex: snake left/right, snake up down, ect...) F2p is just high ban rate. Pretty sure there are tons of false positives too.
  2. That's a good idea, Thanks. I never really liked having to preform queries every 100 frames as it was a hack to prevent lag. Probably going to change it to use a periodic executor service in the constructor that does the query.
  3. Don't forget to call cleanup() in onStop(), this function removes the painter as both a mouse listener and a painter from osbot. @Override public void onStop() throws InterruptedException { super.onStop(); if(buildSpotSelectionPainter != null) buildSpotSelectionPainter.cleanup(); Instantiation of the painter object should be at the top of your onStart(). There can be a race condition where script.stop() is called before painter construction. script.stop() then triggers onStop before onStart creates that painter. The result is that the painter is never removed from the canvas.
  4. Painter classes that allows a user to select any entities through the paint. 1. Copy this class into your project, Adjust the package if needed. package Paint; import org.osbot.rs07.api.EntityAPI; import org.osbot.rs07.api.filter.Filter; import org.osbot.rs07.api.map.Position; import org.osbot.rs07.api.model.Entity; import org.osbot.rs07.canvas.paint.Painter; import org.osbot.rs07.input.mouse.BotMouseListener; import org.osbot.rs07.script.MethodProvider; import org.osbot.rs07.script.Script; import java.awt.*; import java.awt.event.MouseEvent; import java.awt.geom.Area; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; public abstract class EntitySelectionPainter<T extends Entity> extends BotMouseListener implements Painter { private final EntityAPI<T> entityAPI; private final Color FINISH_SELECTION_BG = new Color(25, 240, 25, 156); private final Color ALPHA_GREEN = new Color(25, 240, 25, 20); private final Color ALPHA_RED = new Color(250, 25, 25, 20); private final Filter<T> validEntityFilter; private final Script script; private List<T> visibleEntities; private final HashSet<T> selectedEntities; private final boolean isSingleSelection; private int frameCounter = 0; private Rectangle finishSelectionRect; private boolean isSelectionComplete = false; private final static String CONFIRM_SELECTION = "Confirm Selections"; protected EntitySelectionPainter(Script script, Filter<T> validEntityFilter, EntityAPI<T> entityAPI, boolean isSingleSelection) { this.entityAPI = entityAPI; this.script = script; this.validEntityFilter = validEntityFilter; this.selectedEntities = new HashSet<>(); this.isSingleSelection = isSingleSelection; script.getBot().addPainter(this); script.getBot().addMouseListener(this); } @Override public void onPaint(Graphics2D g2d) { setFinishSelectionRectangle(g2d); frameCounter += 1; if (frameCounter % 100 == 0) { queryValidEntities(); script.log("Found " + visibleEntities.size()); } for (T entity : visibleEntities) { if(entity == null) continue; Area entityOutline = getEntityOutline(entity); if(entityOutline != null) { g2d.setColor(selectedEntities.contains(entity) ? Color.GREEN : Color.RED); g2d.draw(entityOutline); g2d.setColor(selectedEntities.contains(entity) ? ALPHA_GREEN : ALPHA_RED); g2d.fill(entityOutline); continue; } Shape positionOutline = getEntityPositionShape(entity); if(positionOutline != null) { g2d.setColor(selectedEntities.contains(entity) ? Color.GREEN : Color.RED); g2d.draw(positionOutline); } } drawFinishSelectionRectangle(g2d); } @Override public void checkMouseEvent(MouseEvent mouseEvent) { if (mouseEvent.getID() != MouseEvent.MOUSE_PRESSED || mouseEvent.getButton() != MouseEvent.BUTTON1) { return; } Point clickPt = mouseEvent.getPoint(); if (finishSelectionRect != null && finishSelectionRect.contains(clickPt)) { isSelectionComplete = true; mouseEvent.consume(); return; } for (T entity : visibleEntities) { Rectangle entityBoundingBox = getEntityBoundingBox(entity); // Draw the outline of the tile (position) for an NPC. If too many players interact with a NPC at any point // It will disappear. ex: splashing host @ Ardy knights. boolean cannotGetBB = entityBoundingBox == null; if (cannotGetBB) script.warn(String.format("Entity bounding box is null (%s @ %s). Attempting to use Position Shape.", entity.getName(), entity.getPosition())); if (!cannotGetBB && entityBoundingBox.contains(clickPt)) { mouseEvent.consume(); userClickedEntityHelper(entity); continue; } Shape npcPositionOutline = getEntityPositionShape(entity); if(npcPositionOutline == null) { script.warn(String.format("Unable to get the Entity Position Shape for %s @ %s", entity.getName(), entity.getPosition())); continue; } if(npcPositionOutline.contains(clickPt)) { mouseEvent.consume(); userClickedEntityHelper(entity); } } } public ArrayList<T> awaitSelectedEntities() throws InterruptedException { while (!isSelectionComplete) { MethodProvider.sleep(1000); } if (selectedEntities.isEmpty()) { script.warn("Nothing was selected!"); } cleanup(); return new ArrayList<>(selectedEntities); } private void userClickedEntityHelper(T entity) { if(isSingleSelection) { boolean isDeselect = selectedEntities.contains(entity); selectedEntities.clear(); if(!isDeselect) selectedEntities.add(entity); return; } if (selectedEntities.contains(entity)) { script.log(String.format("Removing entity (id: %d)", entity.getId())); selectedEntities.remove(entity); } else { script.log(String.format("Added entity (id: %d)", entity.getId())); selectedEntities.add(entity); } } private void setFinishSelectionRectangle(Graphics2D g2d) { if(finishSelectionRect != null) { return; } FontMetrics metrics = g2d.getFontMetrics(); int width = metrics.stringWidth(CONFIRM_SELECTION) + 30; int numLines = CONFIRM_SELECTION.split("\n").length; int height = metrics.getHeight() * numLines + 30; finishSelectionRect = new Rectangle(0, 0, width, height); } private void drawFinishSelectionRectangle(Graphics2D g2d) { g2d.setColor(FINISH_SELECTION_BG); g2d.fill(finishSelectionRect); FontMetrics metrics = g2d.getFontMetrics(); int textX = finishSelectionRect.x + 15; int textY = finishSelectionRect.y + 15 + metrics.getAscent(); g2d.setColor(Color.WHITE); g2d.drawString(CONFIRM_SELECTION, textX, textY); } private void queryValidEntities() { //noinspection unchecked visibleEntities = entityAPI.filter(validEntityFilter).stream().distinct().collect(Collectors.toList()); if (visibleEntities.isEmpty()) { script.log("Found no NPCs with supplied filter"); } } private Rectangle getEntityBoundingBox(T entity) { return entity.getModel().getBoundingBox(entity.getGridX(), entity.getGridY(), entity.getZ()); } private Shape getEntityPositionShape(T entity) { Position position = entity.getPosition(); if (position != null) { return position.getPolygon(script.getBot()); } return null; } private Area getEntityOutline(T entity) { return entity.getModel().getArea(entity.getGridX(), entity.getGridY(), entity.getZ()); } public void cleanup() { script.getBot().removePainter(this); script.getBot().removeMouseListener(this); } } 2. Extend EntitySelectionPainter. ex: For RS2Objects (and its implementations GroundDecoration, InteractableObject, WallDecoration, WallObject) package Paint; import org.osbot.rs07.api.Objects; import org.osbot.rs07.api.filter.Filter; import org.osbot.rs07.api.model.RS2Object; import org.osbot.rs07.script.Script; public class Rs2ObjectSelectionPainter extends EntitySelectionPainter<RS2Object> { public Rs2ObjectSelectionPainter(Script script, Filter<RS2Object> validEntityFilter, Objects objects, boolean isSingleSelection) { super(script, validEntityFilter, objects, isSingleSelection); } } ex: For NPCs package Paint; import org.osbot.rs07.api.NPCS; import org.osbot.rs07.api.filter.Filter; import org.osbot.rs07.api.model.NPC; import org.osbot.rs07.script.Script; public class NPCSelectionPainter extends EntitySelectionPainter<NPC> { public NPCSelectionPainter(Script script, Filter<NPC> validEntityFilter, NPCS npcs, boolean isSingleSelection) { super(script, validEntityFilter, npcs, isSingleSelection); } } 3. Use in your project. I put this in onStart(). You will need a filter to only highlight applicable Entities for your script. This below example is from a construction script, therefore only objects that have the "Build" action will be highlighted. The isSingleSelection boolean controls if the user can only select 1 entity at a time. ex: A construction script may only want to select 1 larder build space. Rs2ObjectSelectionPainter buildSpotSelectionPainter; @Override public void onStart() throws InterruptedException { super.onStart(); buildSpotSelectionPainter = new Rs2ObjectSelectionPainter(this, object -> object.hasAction("Build"), objects, false); ArrayList<RS2Object> selectedObjects = buildSpotSelectionPainter.awaitSelectedEntities(); log("# objects: " + selectedObjects.size()); for (RS2Object e: selectedObjects) { log(e.getName() + " " + e.getPosition()); } }
  5. Do these have to be hosted externally? Half of the SDN scripts in my library don't even load their logos. Can I use path the resources folder instead?
  6. Can you add regular energy support as well? TY Got'em them all in like an hour.
  7. yfoo

    Super Stealer

    Presenting an open source general purpose pickpocketing script! I designed this script to handle the majority of pickpocket-able NPCs in the game. https://github.com/YifanLi5/Super-Stealer Setup You must leave empty slots for pickpocket loot. Minimum 3 (coins + coin pouch + 1 empty slot). Adjust accordingly for different NPCs Setup your inventory, this script takes a snapshot of the starting inventory setup and uses it to restock Want Dodgy necklaces? Have them present. Want Shadow veil? Have present staff/runes for the spell + Arceuus spellbook active. DO NOT START the script with a full inventory, OR at any point allow the inventory to fill up from loot (Except Master Farmers). Having a full inventory is what triggers a bank restock. It was designed this way to have compatibility with Master farmers. Click the NPCs you wish to steal from, then click Finish Selection. Multiple NPCs will be highlighted green if they share the same id. The closest one to you will be stuck to until something happens to it. Then a new instance of the same NPC will be reselected. This script will pickpocket the marked NPCs and restock at the nearest bank. The nearest bank is calculated automatically by whether a banking entity (Chest/Banker/ect.) is nearby OR handled by the Osbot webwalker. These are the currently supported banks (https://github.com/YifanLi5/Super-Stealer/blob/master/Super_Stealer/src/Util/BankAreaUtil.java) If you need a bank to be added DM me. Features Dodgy necklace support. Shadow Veil support Any healing item, as long as the action to consume is "Eat" or "Drink". I suggest however something from the list below, Overhealing may be an issue with food not on the list. More can be added on request. TROUT("Trout", 7), SALMON("Salmon", 9), TUNA("Tuna", 10), LOBSTER("Lobster", 12), WINE("Jug of wine", 12), SWORDFISH("Swordfish", 14), MONKFISH("Monkfish", 16); Will be active even when stunned! Will randomly pick an actions to preform... Heals Spam pickpocket Drops Junk (ex: Jugs if using wines) AFK Adjusts coin pouch limit based on Ardy diary level (None || Easy: 28, Medium: 56, Hard: 84, Elite: 140) Other Notes: Emergency eat is triggered at <= 5 hp, this may work for 10hp accounts but be careful with them. Feedback on performance of 10hp accounts will be gratefully accepted I don't have any Valamore, Darkmeyer, or Prifddinas setup. I'll have to evaluate later once my account gets the requirements. Bug Report Format: I need to know the following information to attempt to reproduce the issue Script starting location Target NPC Inventory Setup Bot's logger Optional: If your character is special in any way. (ex: 10hp skiller) Proggies Got 99 thieving.
  8. Welcome, hope you enjoy your time here. Writing scripts is fun.
  9. Thanks for the info. I eventually ended up with using the equipment check.
  10. If you're are already using myVertCount to determine how long you're stunned you should go ahead and also use it to determine if you are stunned. There is no reason to use 2 since one can do both for you.
  11. Just now figured out that using vertices count is the way to go. The birds that appear add to your vertices count, bumping it up by 42. Set your starting vertices count in onStart. Then you can check if stunned by comparing it against your current vertex count. Something like... // When player is stunned their vertices count goes up by ~42. // Get baseline vertices when idle to determine when stunned. MidStunUtil.approxVerticesCountStunned = myPlayer().getModel().getVerticesCount() + 42; public static boolean isPlayerStunned() { return approxVerticesCountStunned - globalMethodProvider.myPlayer().getModel().getVerticesCount() <= 5; } I used to use player height (normal ~ 198, stunned ~ 240) but that doesn't work if player is wielding certain items like a staff that increases your height over 240. Checking animation also is a nogo, The animation id flips back to -1 before the stun ends. So you wouldn't be able to ConditionalSleep until unstunned. Player hp is also bad, what if dodgy necklace procs?
  12. Generally you shouldn't really care about the exact positions or areas of objects, or at least i don't. The only time I did was Areas of banks. I rely more on the locations of Rs2Objects or Entitles instead since those objects can be easily interacted with using the api, and that is likely what you're going to do anyway. Your dynamic instance is still going to have common Rs2Objects/Entities right, why not use those to navigate instead?
  13. RS2Widget myWid = widgets.get(219, 1, 1); You are referring to this line right? Its ok to do because I am assigning an Object reference here. An object reference is just like a regular variable assignment (ex: int myint = 1;) except it deals with a class (ex: Rs2Widget, ArrayList, String) instead of a primitive (int, double, boolean). Remember, in Java an object reference can be assigned to null. Assuming the widgets.get() returns null, a null pointer will only occur if I attempt to do something with it without null checking, (Such as myWid.isVisible()). Thats why I still have your original null check just modified to use myWid. if(myWid != null && myWid.isVisible()) Watch this video to get a more indepth explanation of primitives vs references.
  14. It looks like if(dialogues.isPendingOption()){ if(widgets.get(219, 1, 1) != null && widgets.get(219, 1, 1).isVisible()){ RS2Widget myWid = widgets.get(219, 1, 1); if(myWid.getMessage().equals("Take to sawmill: 26 x Mahogany logs")){ if(inventory.contains("Mahogany logs")) { if (dialogues.selectOption("Take to sawmill: 26 x Mahogany logs")) {} } else { useLogsOnButler(); } } else if(myWid.getMessage().equals("Take to sawmill: 26 x Teak logs")){ if(inventory.contains("Teak logs")) { if (dialogues.selectOption("Take to sawmill: 26 x Teak logs")) {} } else { useLogsOnButler(); } } } //etc. should work but its bad practice to refer to widgets with more than root id, I think I read this in the SDN guidelines. Even if this is not going on SDN, good idea anyway. Separate note. Put... RS2Widget myWid = widgets.get(219, 1, 1); Above if(widgets.get(219, 1, 1) != null && widgets.get(219, 1, 1).isVisible()) Then change the if to if(myWid != null && myWid.isVisible()) So you don't make 3 calls to get the same widget.
  15. In that case, I would handle it by... - first determining if you are using Teak/Mahogany based on inventory. (ex: boolean isTeak) - Using widgets.containingText("Take To Sawmill") to get a List<Rs2Widget> of all the dialog options with the corresponding string. - Then based on "isTeak" search the List<Rs2Widget> for a rs2widget whose message ( rs2Widget.getMessage() ) contains both the correct log type AND 26. - Interact with the found widget.
  16. 1042 doesn't work. it increments even when I don't consume a charge. The Runelite plugin doesn't know what the charges are until they are manually checked. Then it starts counting. Pretty sure its checking if I get hit and the stun anim plays (Player height > 230 or whatever). I can use check ammy slot for simplicity equipment.isWearingItem(EquipmentSlot.AMULET, "Dodge necklace");
  17. Anyone willing to share how dodgy necklaces charges are detected? Its a persistent value on logout so I'm sure that means its a config. Personally rather use a config than a onMessage solution. Looking at config change history until I figure out the pattern . Edit: Looks like something to do with config 1042.
  18. Do you mean there are multiple options to select but all of them have the same text? There are different overloads of selectOptions. You probably want the one that takes in an int. https://osbot.org/api/org/osbot/rs07/api/Dialogues.html Also does typing in the exact string not work?
  19. Its invisible, you need to draw it on the screen in onPaint or enable Mouse Position in debug/settings menu (Right side of osbot window, 3 gears icon).
  20. When a npc is killed, its loot doesn't appear immediately. Death animation plays first. Change if (groundItems.closest("Raw rat meat") != null) { To a ConditionalSleep, sleep until you see your raw meat drop.
  21. >I was also not aware of a conditionalSleep2 method - what is the difference? regular CS requires you to make an object to call sleep. CS2.sleep() is a static method. >randomGaussian method is a good idea for sleeps! Although I feel like I would add a base 50ms just because reaction time? That's the point actually, I was using it to delay menu interactions by a small amount, like a human would. ex:) sleep(randomGaussian(300, 100)); keyboard.pressKey(KeyEvent.VK_SPACE); ScriptPaint.setStatus("Spacebar-ing make widget"); result = ConditionalSleep2.sleep(2000, () -> { List<RS2Widget> widgets = new ArrayList<>(getWidgets().containingActions(270, CREATE_VERBS)); return widgets.isEmpty(); }); sleep(randomGaussian(300, 100)); keyboard.releaseKey(KeyEvent.VK_SPACE); In this block, I wanted to wait a moment after the make widget appears before interacting with it. Then wait again after spacebar-ing it before releasing it.
  22. Neat! What about adding an additional step to have headless arrowheads in inventory and use those as well? Regarding the make widget I think the root id is 270. Also you can use "1" hotkey instead of clicking the widget since arrowheads are always the 1st option from the left. Here is a example of how I get the widget then interact with it with spacebar. Same concept as "1" hotkey. Except spacebar repeats the last widget interaction used. https://github.com/YifanLi5/Bankstanding-Skiller/blob/cc8c13d063fd141125494fe3bf7643330d14a49d/src/Task/CombineItems.java#L86
  23. Search engine? https://www.oldschoolscripts.com/ahk/pk-scripts/ This came up.
  24. Why not just an ahk? it'll work with runelite.
×
×
  • Create New...