omni4life Posted September 2, 2015 Share Posted September 2, 2015 Hey all, back again for yet another round of questions. I wrote an ultra quick Yak killer today for personal use, however, I have some issues with the combat method and I would love some more experienced users input. This is my method as it stands at the moment: case ATTACK: NPC yak = npcs.closest("Yak"); if (yak != null && !combat.isFighting() && !yak.isUnderAttack()) { yak.interact("Attack"); status = "Interacting with Yak"; sleep(random(500,800)); } break; These are my questions: As my character kills the NPC, the NPC enters its death animation thus rendering !combat.isFighting() false and the method continues to click the NPC attempting to re initiate combat. Is there a check I can implement so that once the NPC I'm fighting begins its death animation I can instantly move onto the next? The clicking a dying NPC looks very botlike, but I'm unsure how to combat it. Sometimes, despite the fact my character is already under attack from a Yak it will ignore it and attempt to fight a different Yak, spam clicking it and being unable to attack as it isn't a multicombat zone. Is there a reason it's doing this that I can't see or is the !combat.isFighting method just a little bit iffy? Thanks for any and all help as always! I really appreciate all of your input, ideas and advice. -Omni. Quote Link to comment Share on other sites More sharing options...
Czar Posted September 2, 2015 Share Posted September 2, 2015 (edited) So what you're doing is: > Finding the nearest yak > checking if the chosen yak exists > checking if the chosen yak isn't fighting > checking if the chosen yak isn't under attack what happens if it's fighting, or it's under attack? it will just wait/repeat cycle INSTEAD, you need to FILTER the yaks, and find the closest one which fits certain criteria: (the above conditions), and NOT find the closest yak, and check if it meets criteria As for the two questions; 1. check if the npc's health is above 0, and to make it faster, use the filter I mentioned above 2. you need to check if your character is interacting or being interacted, if it is, don't attack Edited September 2, 2015 by Czar 2 Quote Link to comment Share on other sites More sharing options...
FrostBug Posted September 2, 2015 Share Posted September 2, 2015 (edited) public class YakFilter implements Filter<NPC> { public boolean match(NPC npc) { return npc != null && npc.getName().equals("Yak") && npc.getHealth() > 0 } } ^ Use a custom filter to find the yaks that aren't dying Can be used like so: NPC yak = getNpcs().closest(new YakFilter()); Edited September 2, 2015 by FrostBug 2 Quote Link to comment Share on other sites More sharing options...
Bobrocket Posted September 2, 2015 Share Posted September 2, 2015 public class YakFilter implements Filter<NPC> { public boolean match(NPC npc) { return npc != null && npc.getName().equals("Yak") && npc.getHealth() > 0 }}^ Use a custom filter to find the yaks that aren't dyingCan be used like so: NPC yak = getNpcs().closest(new YakFilter()); What's the advantage for a custom filter over just an anonymous filter? Quote Link to comment Share on other sites More sharing options...
Botre Posted September 2, 2015 Share Posted September 2, 2015 What's the advantage for a custom filter over just an anonymous filter? An anonymous implementation would still make the filter custom, making it as a class makes it easier to reuse it in all your yak scripts I guess :p Quote Link to comment Share on other sites More sharing options...
omni4life Posted September 2, 2015 Author Share Posted September 2, 2015 So what you're doing is: > Finding the nearest yak > checking if the chosen yak exists > checking if the chosen yak isn't fighting > checking if the chosen yak isn't under attack what happens if it's fighting, or it's under attack? it will just wait/repeat cycle INSTEAD, you need to FILTER the yaks, and find the closest one which fits certain criteria: (the above conditions), and NOT find the closest yak, and check if it meets criteria As for the two questions; 1. check if the npc's health is above 0, and to make it faster, use the filter I mentioned above 2. you need to check if your character is interacting or being interacted, if it is, don't attack Thanks very much for the advice. With point 2, !combat.isFighting checks of my player is interacting, but not being interacted yes? I'm away from my pc/api at the minute, but which class is interacted under? MyPlayer()?Thanks for any and all input everyone! Quote Link to comment Share on other sites More sharing options...
Chris Posted September 2, 2015 Share Posted September 2, 2015 (edited) NPC target = npcs.closest(new Filter<NPC>() { @Override public boolean match(NPC npc) { return npc != null && npc.getName().equals("Yak") && !npc.isUnderAttack() && npc.getHealth() > 0 && map.canReach(npc); } }); Edited September 2, 2015 by Sinatra 1 Quote Link to comment Share on other sites More sharing options...
omni4life Posted September 2, 2015 Author Share Posted September 2, 2015 (edited) NPC target = npcs.closest(new Filter<NPC>() { @Override public boolean match(NPC npc) { return npc != null && npc.getName().equals("Yak") && !npc.isUnderAttack() && npc.getHealth() > 0 && map.canReach(npc); } }); I really don't mean to be spoon fed, but I'm struggling a little bit to understand the implementation. I've only just begun an online course on Java so for the most part I struggle to follow anything outside of states and if statements. I'm hoping to actually move to a node/OOP style next script, but I don't understand it well enough yet. If I post my current code, could you be so kind as to give me a demonstration of how it would be integrated? Either way, I'll keep experimenting with everything so thank you very much to both you and everyone else for your advice and input ! import org.osbot.rs07.api.model.NPC; import org.osbot.rs07.script.Script; import org.osbot.rs07.script.ScriptManifest; import java.awt.*; @ScriptManifest(author = "Omni4life", info = "Kills Yaks on Neitiznot.", name = "Yakinator", version = 1, logo = "") public class yakKiller extends Script { // Declare all Variables public static String status; @Override public void onStart() { log("Yak Killer by Omni4life has begun."); log("If you experience any issues while running this script please report them to me on the forums."); } private enum State { ATTACK, WAIT }; private State getState() { NPC yak = npcs.closest("Yak"); if (yak != null) return State.ATTACK; return State.WAIT; } @Override public int onLoop() throws InterruptedException { switch (getState()) { case ATTACK: NPC yak = npcs.closest("Yak"); if (yak != null && !combat.isFighting() && !yak.isUnderAttack() && yak.isAttackable()) { yak.interact("Attack"); status = "Interacting with Yak"; sleep(random(500, 800)); } break; case WAIT: sleep(random(500, 700)); break; } return random(200, 300); } @Override public void onExit() { log("Thanks for running Yak Killer"); } @Override public void onPaint(Graphics2D g) { } } Edited September 2, 2015 by omni4life Quote Link to comment Share on other sites More sharing options...
Appelflapjes Posted September 2, 2015 Share Posted September 2, 2015 (edited) Something like this? (not an expert either ) case ATTACK: NPC target = npcs.closest(new Filter<NPC>() { @Override public boolean match(NPC npc) { return npc != null && npc.getName().equals("Yak") && !npc.isUnderAttack() && npc.getHealth() > 0 && map.canReach(npc); } }); if (target != null) { target.interact("Attack"); status = "Interacting with Yak"; sleep(random(500, 800)); } else { // No yak available } break; Edited September 2, 2015 by Appelflapjes Quote Link to comment Share on other sites More sharing options...
Chris Posted September 2, 2015 Share Posted September 2, 2015 private State getState() { NPC yak = npcs.closest("Yak"); if (yak != null) return State.ATTACK; return State.WAIT; } remove this NPC yak = npcs.closest("Yak"); if (yak != null) return State.ATTACK; return State.WAIT; and you could change it in different ways. Mine may not be the best but it works if (!myplayer().isanimating && !myplayer.isUnderAttack) return State.ATTACK; return State.WAIT; then your case can be changed from case ATTACK: NPC yak = npcs.closest("Yak"); if (yak != null && !combat.isFighting() && !yak.isUnderAttack() && yak.isAttackable()) { yak.interact("Attack"); status = "Interacting with Yak"; sleep(random(500, 800)); } break; to.. case ATTACK: NPC target = npcs.closest(new Filter<NPC>() //add the whole filter code snippet i gave at top. here if (target != null && !combat.isFighting() && target.isAttackable()) { target.interact("Attack"); status = "Interacting with Yak"; sleep(random(500, 800)); } break; 1 Quote Link to comment Share on other sites More sharing options...
Joseph Posted September 2, 2015 Share Posted September 2, 2015 NPC target = npcs.closest(new Filter<NPC>() { @Override public boolean match(NPC npc) { return npc != null && npc.getName().equals("Yak") && !npc.isUnderAttack() && npc.getHealth() > 0 && map.canReach(npc); } }); The class that frost presented look way cleaner in my opinion. Both you guys had the samething except you had an extra private State getState() { NPC yak = npcs.closest("Yak"); if (yak != null) return State.ATTACK; return State.WAIT; } remove this NPC yak = npcs.closest("Yak"); if (yak != null) return State.ATTACK; return State.WAIT; and you could change it in different ways. Mine may not be the best but it works if (!myplayer().isanimating && !myplayer.isUnderAttack) return State.ATTACK; return State.WAIT; then your case can be changed from to.. case ATTACK: NPC target = npcs.closest(new Filter<NPC>() //add the whole filter code snippet i gave at top. here if (target != null && !combat.isFighting() && target.isAttackable()) { target.interact("Attack"); status = "Interacting with Yak"; sleep(random(500, 800)); } break; 1 Quote Link to comment Share on other sites More sharing options...
Bobrocket Posted September 2, 2015 Share Posted September 2, 2015 To fix your implementation, replace .closest("Yak") with .closest(<filter>) 1 Quote Link to comment Share on other sites More sharing options...
omni4life Posted September 2, 2015 Author Share Posted September 2, 2015 Thanks to everyone for all your help, I really appreciate the lengths you all go to to try and help out new folks around here! After uni today I'll give adding it a go and I'll test it out . Thanks again! 1 Quote Link to comment Share on other sites More sharing options...
Dark Magician Posted September 3, 2015 Share Posted September 3, 2015 (edited) Thanks to everyone for all your help, I really appreciate the lengths you all go to to try and help out new folks around here! After uni today I'll give adding it a go and I'll test it out . Thanks again! NPC Filter + check if another player is interacting with it. public boolean isPlayerInteracting(NPC npc) { for (Player p : players.getAll()) { if (p.getInteracting() != null && p.getInteracting() == npc || p.getInteracting() != null && p.getInteracting().getPosition() == npc.getPosition() || p.getInteracting() != null && p.getInteracting().isInteracting(npc)) { return true; } } return false; } public boolean walkTile(Position p) throws InterruptedException { if(this.myPosition().distance(p) > 13) { Position fail = new Position((p.getX() + this.myPosition().getX()) / 2 + random(-3, 3), (p.getY() + this.myPosition().getY()) / 2 + random(-3, 3), this.myPosition().getZ()); this.walkTile(fail); } this.mouse.click(new MiniMapTileDestination(this.bot, p), false); int var3 = 0; while(this.myPosition().distance(p) > 2 && var3 < 10) { sleep(500L); if(!this.myPlayer().isMoving()) { ++var3; } } return var3 != 10; } public boolean isNpcValid(NPC npc) { if (npc != null && map.canReach(npc)) { int id = npc.getId(); if (id != -1) { for (NPC i : getNpcs().get(npc.getX(), npc.getY())) { if (i.getId() == id) return true; } } } return false; } public void interact(NPC n, String action) throws InterruptedException { if (map.isWithinRange(n, 7)) { status = "Interacting with " + n.getName(); double x = n.model.getBoundingBox(n.getGridX(), n.getGridY(), n.getZ()).getCenterX(); double y = n.model.getBoundingBox(n.getGridX(), n.getGridY(), n.getZ()).getCenterY(); mouse.move((int) x, (int) y); if (mouse.getEntitiesOnCursor() != null && mouse.getEntitiesOnCursor().contains(n) && mouse.click(true)) { if (menu.isOpen() && menu.selectAction(action)) { sleep(random(900, 1200)); } else { mouse.moveRandomly(); } } else { camera.toEntity(n); } } else if (n.getPosition().isOnMiniMap(this.client.bot)) { status = "Walking to " + n.getName(); walkTile(n.getPosition()); } else if (localWalker.walk(n)) { status = "Walking to " + n.getName(); sleep(random(900, 1200)); } } NPC yak = getNpcs().closest(new Filter<NPC>() { @Override public boolean match(NPC npc) { return npc != null && npc.exists() && npc.getName().contains("Yak") && npc.isAttackable() && !npc.isUnderAttack() && npc.getHealth() != 0 && !isPlayerInteracting(npc) && map.isWithinRange(myPlayer().getPosition(), npc, 7); }}); if (isNpcValid(yak)) { interact(yak, "Attack"); } Edited September 3, 2015 by Dark Magician Quote Link to comment Share on other sites More sharing options...
FrostBug Posted September 3, 2015 Share Posted September 3, 2015 if (p.getInteracting() != null && p.getInteracting() == npc || p.getInteracting() != null && p.getInteracting().getPosition() == npc.getPosition() || p.getInteracting() != null && p.getInteracting().isInteracting(npc)) { return true; } What am I reading o_O this whole thing is literally the same as if(npc == p.getInteracting()) { return true; } Quote Link to comment Share on other sites More sharing options...