dubai Posted August 21 Share Posted August 21 (edited) With the game update, I can't do anymore testing atm sadly, so I thought it's time to share how my scripts are coming along. I have a few that are working solid and lately I've just been breaking them down and taking methods out into their own individual classes within seperate packages of the project so that I can reuse methods and features throughout my different scripts... I'm very happy with how they're looking too, nice and clean now, easy to read Here's the main class to my fighting bot, has a few nice and simple features with a plan for much more import org.osbot.rs07.api.map.Area; import org.osbot.rs07.api.model.GroundItem; import org.osbot.rs07.api.model.NPC; import org.osbot.rs07.api.ui.Skill; import org.osbot.rs07.script.Script; import org.osbot.rs07.script.ScriptManifest; import org.osbot.rs07.utility.ConditionalSleep; import javax.swing.*; import java.awt.*; import java.time.Instant; import java.util.*; import java.util.List; import antiban.basicAB; import extraFeatures.enableRun; import extraFeatures.WorldHopper; @ScriptManifest(name = "Fighter", author = "Dubai", version = 1.0, info = "Fights mobs", logo = "") public class Fighter extends Script { private enum State { WALK_TO_NPC, CHECK_HEALTH, FIND_TARGET, ATTACK_NPC, FIGHTING, LOOTING_CHECK, LOOTING, WALK_TO_BANK, BANK, HANDLE_BANK_INTERFACE, HOP_WORLD, ENABLE_RUN } private final Object lock = new Object(); private boolean guiDone = false; private NPC currentTargetNPC; private basicAB antiBan; private static Random random = new Random(); private State currentState; private final Area defaultBankArea = new Area(3009, 3355, 3017, 3358); private Area bankArea = defaultBankArea; private Map<String, Area> npcAreas = new HashMap<>(); private boolean enableEating; private String selectedFood; private int eatBelowHealth; private int withdrawFoodAmount; private List<Integer> hopWorlds; private boolean enableRun; private String selectedNPC; private boolean enableLooting; private List<String> itemsToLoot; private enableRun runEnabler; private WorldHopper hopWorld; public void setEnableAutoRetaliate(boolean selected) { System.out.println("Enable Auto-retaliate: " + selected); } public void setBuryBones(boolean selected) { System.out.println("Bury Bones: " + selected); } public void setEnableTalkBack(boolean selected) { System.out.println("Enable Talk-Back: " + selected); } public void setEnablePotion(boolean selected) { System.out.println("Enable Potion: " + selected); } public void setPotions(ArrayList<String> list) { System.out.println("Potions List: " + list); } public void setHopForPlayers(boolean hopForPlayers) { System.out.println("Hop for Players: " + hopForPlayers); } public void setEnableEating(boolean enableEating) { this.enableEating = enableEating; } public void setSelectedFood(String selectedFood) { this.selectedFood = selectedFood; } public void setEatBelowHealth(int eatBelowHealth) { this.eatBelowHealth = eatBelowHealth; } public void setWithdrawFoodAmount(int withdrawFoodAmount) { this.withdrawFoodAmount = withdrawFoodAmount; } public void setEnableRun(boolean enableRun) { this.enableRun = enableRun; } public void setSelectedNPC(String selectedNPC) { this.selectedNPC = selectedNPC; } public void setEnableLooting(boolean enableLooting) { this.enableLooting = enableLooting; } public void setItemsToLoot(List<String> itemsToLoot) { this.itemsToLoot = itemsToLoot; } public void setBankArea(Area bankArea) { this.bankArea = bankArea; } public void setHopWorlds(List<Integer> hopWorlds) { this.hopWorlds = hopWorlds; } public Object getLock() { return lock; } public void guiDone() { synchronized (lock) { guiDone = true; lock.notify(); } } private boolean shouldFindNewTarget() { return currentTargetNPC == null || !currentTargetNPC.exists() || currentTargetNPC.getHealthPercent() == 0; } @Override public void onStart() { antiBan = new basicAB(this); antiBan.setAntiBanChance(0.2); Instant startTime = Instant.now(); runEnabler = new enableRun(this); hopWorld = new WorldHopper(this, hopWorlds); npcAreas.put("Chicken", new Area(3026, 3282, 3037, 3289)); npcAreas.put("Cow", new Area(3022, 3298, 3042, 3312)); npcAreas.put("Monk", new Area(3200, 3400, 3210, 3410)); npcAreas.put("Guard", new Area(2963, 3389, 2968, 3399)); // Show GUI SwingUtilities.invokeLater(() -> new FighterGUI(this).showGUI()); // Wait for GUI to be done synchronized (lock) { while (!guiDone) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } log("GUI done. Initializing state."); currentState = State.WALK_TO_NPC; // Set initial state } @Override public int onLoop() throws InterruptedException { if (!guiDone) { return 500; } if (random.nextInt(10) < 1) { antiBan.performAntiBan(); } if (enableRun) { runEnabler.enableRunMode(); } log("Current State: " + currentState); switch (currentState) { case WALK_TO_NPC: walkToNPC(); break; case FIGHTING: killNPC(); break; case LOOTING: pickupLoot(); break; case WALK_TO_BANK: walkToBank(); break; case BANK: handleBanking(); break; case HOP_WORLD: hopWorld.hopWorld(); break; default: log("Invalid state, switching to WALK_TO_NPC."); currentState = State.WALK_TO_NPC; break; } return random(1600, 1800); } private void walkToNPC() { if (!npcAreas.get(selectedNPC).contains(myPosition())) { log("Walking to NPC area..."); getWalking().webWalk(npcAreas.get(selectedNPC)); } else { if (!getCombat().isFighting()) { log("Arrived at NPC area."); currentState = State.FIGHTING; } } } private void killNPC() { if (enableEating && getInventory().getAmount(selectedFood) == 0) { log("Out of food, walking to bank..."); currentState = State.WALK_TO_BANK; return; } if (enableEating && getSkills().getDynamic(Skill.HITPOINTS) <= eatBelowHealth) { if (getInventory().contains(selectedFood)) { log("Eating food..."); getInventory().getItem(selectedFood).interact("Eat"); new ConditionalSleep(5000) { @Override public boolean condition() { return getSkills().getDynamic(Skill.HITPOINTS) > eatBelowHealth || !getInventory().contains(selectedFood); } }.sleep(); } else { log("No food in inventory while trying to eat, walking to bank..."); currentState = State.WALK_TO_BANK; return; } } if (shouldFindNewTarget()) { findAndAttackNewTarget(); } } private void findAndAttackNewTarget() { log("Finding a new target NPC..."); NPC newTarget = getNpcs().closest(npc -> npc.getName().equalsIgnoreCase(selectedNPC) && npcAreas.get(selectedNPC).contains(npc) && !npc.isUnderAttack() && !npc.isMoving()); if (newTarget != null) { currentTargetNPC = newTarget; currentTargetNPC.interact("Attack"); currentState = State.FIGHTING; } else { log("No NPC found in the area."); if (hopWorlds != null && !hopWorlds.isEmpty()) { log("Hopping worlds as no NPC found..."); currentState = State.HOP_WORLD; } else { log("World hopping not enabled. Returning to WALK_TO_NPC state."); currentState = State.WALK_TO_NPC; } } } private void pickupLoot() { if (enableLooting) { GroundItem loot = getGroundItems().closest(item -> itemsToLoot.contains(item.getName()) && npcAreas.get(selectedNPC).contains(item)); if (loot != null && loot.exists()) { log("Picking up loot: " + loot.getName()); loot.interact("Take"); new ConditionalSleep(3000) { @Override public boolean condition() { return !loot.exists(); } }.sleep(); } else { log("No more items to loot."); currentState = State.FIGHTING; } } else { log("Looting disabled, returning to fighting."); currentState = State.FIGHTING; } } private void walkToBank() { if (!bankArea.contains(myPosition())) { log("Walking to bank area..."); getWalking().webWalk(bankArea); } else { log("Arrived at bank."); currentState = State.BANK; } } private void handleBanking() throws InterruptedException { if (getBank().isOpen()) { if (enableEating && getInventory().getAmount(selectedFood) < withdrawFoodAmount) { log("Withdrawing food: " + selectedFood); getBank().withdraw(selectedFood, withdrawFoodAmount); new ConditionalSleep(3000) { @Override public boolean condition() { return getInventory().getAmount(selectedFood) >= withdrawFoodAmount; } }.sleep(); } log("Closing bank."); getBank().close(); currentState = State.WALK_TO_NPC; } else { log("Opening bank..."); getBank().open(); new ConditionalSleep(5000) { @Override public boolean condition() { return getBank().isOpen(); } }.sleep(); } } @Override public void onPaint(Graphics2D g) { g.drawString("Current State: " + currentState, 10, 20); } @Override public void onExit() { log("Script stopped."); } } Still planning to take some stuff out like the banking handling into its own class, also haven't done much for the onpaint for this script yet but the gui is looking nice. Any feedback greatly appreciated! Edited August 21 by dubai Quote Link to comment Share on other sites More sharing options...
Fanny Posted August 21 Share Posted August 21 (edited) Looks like a pretty solid script! I haven't had chance to look over it in great detail, but a couple of little concerns/tips: 1) Loot looks like it would probably loop indefinitely if there is an item that cannot be picked up (i.e. inventory full or ironman and its not your loot) - also consider players would eat regardless of HP to relieve an inventory slot for certain pieces of loot 2) Perhaps for the hop worlds logic it would make more sense to keep an average of the number of players in the local vicinity over a short period of time (1 min), and if it goes above a certain number for a certain amount of time then hop... Or an average of how many attackable NPCs there are even better! 3) The eating food logic looks like it would work fine, but on low-hitting mobs, it will be very obvious over time that you always eat at a specific hp level, perhaps consider checking the NPCs max hits, and consider having a random chance to eat on each loop below a certain hp, but 100% chance to eat before you enter 1 hit range? 4) I'd also break the conditional sleep AFTER attempting to eat on being within 1 hit range (so you tried to eat before, but if that failed, you will definitely try again quickly instead of waiting out the sleep!) Edited August 21 by Fanny Quote Link to comment Share on other sites More sharing options...
dubai Posted August 21 Author Share Posted August 21 9 hours ago, Fanny said: Looks like a pretty solid script! I haven't had chance to look over it in great detail, but a couple of little concerns/tips: 1) Loot looks like it would probably loop indefinitely if there is an item that cannot be picked up (i.e. inventory full or ironman and its not your loot) - also consider players would eat regardless of HP to relieve an inventory slot for certain pieces of loot 2) Perhaps for the hop worlds logic it would make more sense to keep an average of the number of players in the local vicinity over a short period of time (1 min), and if it goes above a certain number for a certain amount of time then hop... Or an average of how many attackable NPCs there are even better! 3) The eating food logic looks like it would work fine, but on low-hitting mobs, it will be very obvious over time that you always eat at a specific hp level, perhaps consider checking the NPCs max hits, and consider having a random chance to eat on each loop below a certain hp, but 100% chance to eat before you enter 1 hit range? 4) I'd also break the conditional sleep AFTER attempting to eat on being within 1 hit range (so you tried to eat before, but if that failed, you will definitely try again quickly instead of waiting out the sleep!) Some fire feedback there mate thank you, you're right, it is basic in the sense of, lots can break it, as i'm adding more features i always find this to be true, I don't have enough accounts/time it seems to do enough testing but I am getting there, slowly fixing one thing at a time. Your eating logic sounds a bit complicated, I know my eating method does need some attention, I was thinking of providing a range that it can eat at, say, eat between 20-30hp... for simplicity this seems like it could really work. Bots shouldn't really be risking until 1hit range but you're also right, that a human would I think I'll leave the current world hop feature to instantly world hop if a player comes by for now because I planned to ouse these same methods accross multiple scripts, including some wilderness content scripting. So basically if i player comes in the area it will straight away begin to hop. This feature is pretty smooth so I don't want to change it too much. 100% need attention to the looting, it is flawed at the moment, thats what i'm currently working on amongst gui changes.. I think I got carried away adding features and things started breaking so I'm working backwards currently... Thanks again for the great feedback! Are these features you've implemented in your scripts? Quote Link to comment Share on other sites More sharing options...
Fanny Posted August 22 Share Posted August 22 (edited) 11 hours ago, dubai said: Are these features you've implemented in your scripts? I have actually been putting off writing a combat script since I started scripting OSBot All my scripts are skilling and buying/selling I reasoned to myself that until I can write scripts pretty flawlessly, it is going to die a lot!! Without overcomplicating the food eating, you could perhaps implement a new int eatBelowHealthMin if (enableEating && getSkills().getDynamic(Skill.HITPOINTS) <= eatBelowHealth) { boolean shouldEat = false; // Always eat if health is below eatBelowHealthMin if (getSkills().getDynamic(Skill.HITPOINTS) <= eatBelowHealthMin) { shouldEat = true; } else { // 3% chance to eat when below eatBelowHealth but above eatBelowHealthMin if (RANDOM.nextDouble() <= 0.03) { shouldEat = true; } } if (shouldEat) { if (getInventory().contains(selectedFood)) { log("Eating food..."); getInventory().getItem(selectedFood).interact("Eat"); // Set sleep down to 1000 to prevent locking out your script after failing to eat i.e. misclick or something new ConditionalSleep(1000) { @Override public boolean condition() { return getSkills().getDynamic(Skill.HITPOINTS) > eatBelowHealthMin || !getInventory().contains(selectedFood); } }.sleep(); } else { log("No food in inventory while trying to eat, walking to bank..."); currentState = State.WALK_TO_BANK; return; } } } Yeah the world hop is fair enough, it's a thought for later, but most importantly it works for the minute!! For the looting, maybe something like this: (implement a list of priority items) private List<String> itemPickupAlways = Arrays.asList( "item1", "item2", "item3" ); private void pickupLoot() { if (enableLooting) { GroundItem loot = getGroundItems().closest(item -> itemsToLoot.contains(item.getName()) && npcAreas.get(selectedNPC).contains(item)); if (loot != null && loot.exists()) { boolean inventoryFull = getInventory().isFull(); boolean isPriorityItem = itemPickupAlways.contains(loot.getName().toLowerCase()); // If the inventory is full and the loot is a priority item, handle freeing space if (inventoryFull && isPriorityItem) { boolean spaceFreed = false; // Try to eat food if available if (getInventory().contains(selectedFood)) { log("Inventory full, eating food to free space..."); getInventory().getItem(selectedFood).interact("Eat"); spaceFreed = new ConditionalSleep(2000) { // Wait for the eating action to complete @Override public boolean condition() { return !getInventory().isFull(); } }.sleep(); } else { // No food available, drop the least valuable item to free space log("No food available, finding least valuable item to drop..."); Item leastValuableItem = getInventory().stream() .filter(item -> !itemPickupAlways.contains(item.getName().toLowerCase()) && !item.getName().equalsIgnoreCase(selectedFood)) .min(Comparator.comparingInt(item -> getItemValue(item))) // Assuming you have a method to get item value .orElse(null); if (leastValuableItem != null) { log("Dropping least valuable item: " + leastValuableItem.getName()); getInventory().drop(leastValuableItem); spaceFreed = new ConditionalSleep(2000) { // Wait for the dropping action to complete, but not too long! @Override public boolean condition() { return !getInventory().isFull(); } }.sleep(); } else { log("No suitable item found to drop."); } } if (!spaceFreed) { log("Failed to free inventory space for priority item."); return; // Exit if space couldn't be freed } } // Proceed to pick up the loot if there is space if (!inventoryFull || isPriorityItem) { log("Picking up loot: " + loot.getName()); loot.interact("Take"); new ConditionalSleep(3000) { @Override public boolean condition() { return !loot.exists(); } }.sleep(); } else { log("No space to pick up loot: " + loot.getName()); } } else { log("No more items to loot."); currentState = State.FIGHTING; } } else { log("Looting disabled, returning to fighting."); currentState = State.FIGHTING; } } // Helper method to get the value of an item - you could hardcode or retrieve values from DB or wiki or something private int getItemValue(Item item) { switch (item.getName().toLowerCase()) { case "iron ore": return 100; case "steel bar": return 300; default: return 1; } } Edited August 22 by Fanny Quote Link to comment Share on other sites More sharing options...
dubai Posted August 23 Author Share Posted August 23 14 hours ago, Fanny said: I have actually been putting off writing a combat script since I started scripting OSBot All my scripts are skilling and buying/selling I reasoned to myself that until I can write scripts pretty flawlessly, it is going to die a lot!! Without overcomplicating the food eating, you could perhaps implement a new int eatBelowHealthMin if (enableEating && getSkills().getDynamic(Skill.HITPOINTS) <= eatBelowHealth) { boolean shouldEat = false; // Always eat if health is below eatBelowHealthMin if (getSkills().getDynamic(Skill.HITPOINTS) <= eatBelowHealthMin) { shouldEat = true; } else { // 3% chance to eat when below eatBelowHealth but above eatBelowHealthMin if (RANDOM.nextDouble() <= 0.03) { shouldEat = true; } } if (shouldEat) { if (getInventory().contains(selectedFood)) { log("Eating food..."); getInventory().getItem(selectedFood).interact("Eat"); // Set sleep down to 1000 to prevent locking out your script after failing to eat i.e. misclick or something new ConditionalSleep(1000) { @Override public boolean condition() { return getSkills().getDynamic(Skill.HITPOINTS) > eatBelowHealthMin || !getInventory().contains(selectedFood); } }.sleep(); } else { log("No food in inventory while trying to eat, walking to bank..."); currentState = State.WALK_TO_BANK; return; } } } Yeah the world hop is fair enough, it's a thought for later, but most importantly it works for the minute!! For the looting, maybe something like this: (implement a list of priority items) private List<String> itemPickupAlways = Arrays.asList( "item1", "item2", "item3" ); private void pickupLoot() { if (enableLooting) { GroundItem loot = getGroundItems().closest(item -> itemsToLoot.contains(item.getName()) && npcAreas.get(selectedNPC).contains(item)); if (loot != null && loot.exists()) { boolean inventoryFull = getInventory().isFull(); boolean isPriorityItem = itemPickupAlways.contains(loot.getName().toLowerCase()); // If the inventory is full and the loot is a priority item, handle freeing space if (inventoryFull && isPriorityItem) { boolean spaceFreed = false; // Try to eat food if available if (getInventory().contains(selectedFood)) { log("Inventory full, eating food to free space..."); getInventory().getItem(selectedFood).interact("Eat"); spaceFreed = new ConditionalSleep(2000) { // Wait for the eating action to complete @Override public boolean condition() { return !getInventory().isFull(); } }.sleep(); } else { // No food available, drop the least valuable item to free space log("No food available, finding least valuable item to drop..."); Item leastValuableItem = getInventory().stream() .filter(item -> !itemPickupAlways.contains(item.getName().toLowerCase()) && !item.getName().equalsIgnoreCase(selectedFood)) .min(Comparator.comparingInt(item -> getItemValue(item))) // Assuming you have a method to get item value .orElse(null); if (leastValuableItem != null) { log("Dropping least valuable item: " + leastValuableItem.getName()); getInventory().drop(leastValuableItem); spaceFreed = new ConditionalSleep(2000) { // Wait for the dropping action to complete, but not too long! @Override public boolean condition() { return !getInventory().isFull(); } }.sleep(); } else { log("No suitable item found to drop."); } } if (!spaceFreed) { log("Failed to free inventory space for priority item."); return; // Exit if space couldn't be freed } } // Proceed to pick up the loot if there is space if (!inventoryFull || isPriorityItem) { log("Picking up loot: " + loot.getName()); loot.interact("Take"); new ConditionalSleep(3000) { @Override public boolean condition() { return !loot.exists(); } }.sleep(); } else { log("No space to pick up loot: " + loot.getName()); } } else { log("No more items to loot."); currentState = State.FIGHTING; } } else { log("Looting disabled, returning to fighting."); currentState = State.FIGHTING; } } // Helper method to get the value of an item - you could hardcode or retrieve values from DB or wiki or something private int getItemValue(Item item) { switch (item.getName().toLowerCase()) { case "iron ore": return 100; case "steel bar": return 300; default: return 1; } } Wow such a detailed response, appreciate it! Honestly don't be too shy of combat scripts! I've only had 1 death since I started and that was coz I was pushing the limits of the eating handlers really. I freakin started making a quest bot lastnight to do restless ghost, thought it would take 30 minutes but It's been about 4 hours and It's ALMOST done... fun stuff I'm thinking for now the looting mechanics on my script are good enough for an aio fighter like this, it's not made to be a looting script so not going to be focusing on that, more aiming for perfect fighting mechanics to push xp/hr rates. Also being made in f2p this bot is more or less for training bot farms, and low level hardcore ironmen etc, not mains. I'll definitely be making more loot focused scripts and I really like your priority looting idea actually, I can see how that would be beneficial if you're killing dragons or something and want to loot the bones over the hide, if theres 1 inventory space left, prioritizing the bones would be more humanlike and better for gp/hr rates etc. Quote Link to comment Share on other sites More sharing options...