	

    package source;
     
    import org.osbot.script.Script;
    import org.osbot.script.ScriptManifest;
     
    @ScriptManifest(author = "", info = "", name = "", version = 1.0)
    public class Main extends Script {
     
        public Combat combat = new Combat(this);
     
        public int onLoop() {
                if(runCombatListener()) {
                        combat.update();
                }
                return 300;
        }
     
        public boolean runCombatListener() {
                return true;
        }
     
    }
           
    import java.util.ArrayList;
    import java.util.List;
     
    import org.osbot.script.rs2.model.Character;
    import org.osbot.script.rs2.model.Entity;
    import org.osbot.script.rs2.model.NPC;
    import org.osbot.script.rs2.model.Player;
     
    public class Combat {
     
        public Main main;
        public List<CombatEntity> combatEntities;
     
     
        public Combat(Main main) {
                this.main = main;
                combatEntities = new ArrayList<CombatEntity>();
        }
     
        public void update() {
                //Clean Up
                for(CombatEntity combat : combatEntities) {
                        if(combat == null) {
                                combatEntities.remove(combat);
                                continue;
                        }
                        if(!combat.getEntity().exists()) {
                                if(combat.hasAttacked) {
                                        CombatEntity cleanup = combat.getAttacking();
                                        cleanup.attacker = null;
                                        if(cleanup.attacking == combat) {
                                                cleanup.setAttacking(null);
                                                cleanup.setHasAttacked(false);
                                        }
                                }
                        }
                }
                //add new entities
                for(NPC npc : main.client.getLocalNPCs()) {
                        if(npc == null) {
                                continue;
                        }
                        Entity facing = npc.getFacing();
                        if(facing != null) {
                                if(!exists(npc)) {
                                        combatEntities.add(new CombatEntity(npc,facing));
                                }
                        } else {
                                if(exists(npc)) {
                                        CombatEntity remove = getCombatEntity(npc);
                                        combatEntities.remove(remove);
                                }
                        }
                }
                for(Player player : main.client.getLocalPlayers()) {
                        if(player == null) {
                                continue;
                        }
                        Entity facing = player.getFacing();
                        if(facing != null) {
                                if(!exists(player)) {
                                        combatEntities.add(new CombatEntity(player,facing));
                                }
                        } else {
                                if(exists(player)) {
                                        CombatEntity remove = getCombatEntity(player);
                                        combatEntities.remove(remove);
                                }
                        }
                }
                //Updates state of the entities
                for(CombatEntity combat : combatEntities) {
                        if(combat == null) {
                                combatEntities.remove(combat);
                                continue;
                        }
                        Entity facing = ((Character<?>) combat.getEntity()).getFacing();
                        if(combat.getFacing() != facing) { //switched to new target
                                if(combat.getHasAttacked()) {
                                        CombatEntity entity = combat.getAttacking();
                                        combat.setHasAttacked(false);//if switched to new target we do not know if he has fully attacked yet
                                        combat.setFacing(facing);
                                        entity.setAttacker(null);
                                }
                        }
                        if(((Character<?>) combat.getEntity()).getAnimation() != -1) { //made a combat animation (if non combat animation has happened you would no longer be facing a target and wouldn't reach this point)
                                combat.setHasAttacked(true);
                                CombatEntity attacking = getCombatEntity(combat.getFacing());
                                attacking.setAttacker(combat);
                                combat.setAttacking(attacking);
                        }
                }
        }
     
        public boolean attack(int targetId) throws InterruptedException {
                Entity target = getClosestTarget(targetId);
                if(target == null) {
                        return false;
                }
                target.interact("Attack");
                return true;
        }
     
        public boolean attackRandomWithinDistance(int distance, int targetId) throws InterruptedException {
                Entity target = getRandomTarget(distance, targetId);
                if(target == null) {
                        return false;
                }
                target.interact("Attack");
                return true;
        }
     
        public boolean canAttack() {
                CombatEntity myPlayer = getCombatEntity(main.client.getMyPlayer());
                if(myPlayer.isAttacking()) {
                        return false;
                }
                if(myPlayer.getFacing() != null) {
                        CombatEntity facing = getCombatEntity(myPlayer.getFacing());
                        if(facing.getAttacker() != myPlayer) {
                                return true;
                        }
                        return false;
                }
                return true;
        }
     
        public Entity getRandomTarget(int targetId, int distance) { //will still return if being attacked by an aggressive npc
                CombatEntity myPlayer = getCombatEntity(main.client.getMyPlayer());
                for(CombatEntity combat : combatEntities) {
                        if(combat == null) {
                                combatEntities.remove(combat);
                                continue;
                        }
                        if(combat.getFacing() == main.client.getMyPlayer()) {
                                if(combat.beingAttacked() && combat.getAttacker() != myPlayer) {
                                        continue;
                                }
                                return combat.getEntity(); //If being targetted by a npc in an aggressive area, checks if this npc is being attacked by another player
                        }
                }
                List<NPC> attackables = new ArrayList<NPC>();
                for(NPC npc : main.client.getLocalNPCs()) {
                        if(npc == null) {
                                continue;
                        }
                        if(npc.getId() != targetId) {
                                continue;
                        }
                        if(exists(npc)) {
                                CombatEntity combatEntity = getCombatEntity(npc);
                                if(combatEntity.beingAttacked()) {
                                        continue;
                                }
                        }
                        int distanceBetween = main.client.getMyPlayer().getPosition().distance(npc.getPosition());
                        if(distanceBetween < distance) { //checks if this entity is closer or not, if so sets it to the currently known closest npc
                                attackables.add(npc);
                        }
                }
                if(attackables.size() == 0) {
                        return null;
                }
                NPC toReturn = attackables.get((int) (Math.random() * (attackables.size()-1)));
                return toReturn;
        }
     
        public Entity getClosestTarget(int targetId) {
                CombatEntity myPlayer = getCombatEntity(main.client.getMyPlayer());
                for(CombatEntity combat : combatEntities) {
                        if(combat == null) {
                                combatEntities.remove(combat);
                                continue;
                        }
                        if(combat.getFacing() == main.client.getMyPlayer()) {
                                if(combat.beingAttacked() && combat.getAttacker() != myPlayer) {
                                        continue;
                                }
                                return combat.getEntity(); //If being targetted by a npc in an aggressive area, checks if this npc is being attacked by another player
                        }
                }
                NPC closestAttackable = null;
                int distance = 20; //Max distance it'll attack (change if you want O.o)
                for(NPC npc : main.client.getLocalNPCs()) {
                        if(npc == null) {
                                continue;
                        }
                        if(npc.getId() != targetId) {
                                continue;
                        }
                        if(exists(npc)) {
                                CombatEntity combatEntity = getCombatEntity(npc);
                                if(combatEntity.beingAttacked()) {
                                        continue;
                                }
                        }
                        int distanceBetween = main.client.getMyPlayer().getPosition().distance(npc.getPosition());
                        if(distanceBetween < distance) { //checks if this entity is closer or not, if so sets it to the currently known closest npc
                                closestAttackable = npc;
                                distance = distanceBetween;
                        }
                }
                return closestAttackable; //if returns null there is no npcs to attack O.o
        }
     
        public boolean exists(Entity entity) {
                for(CombatEntity check : combatEntities) {
                        if(check == null) {
                                combatEntities.remove(check);
                                continue;
                        }
                        if(check.isEntity(entity)) {
                                return true;
                        }
                }
                return false;
        }
     
        public CombatEntity getCombatEntity(Entity entity) {
                for(CombatEntity check : combatEntities) {
                        if(check == null) {
                                combatEntities.remove(check);
                                continue;
                        }
                        if(check.isEntity(entity)) {
                                return check;
                        }
                }
                return null;
        }
     
    }
           
    import org.osbot.script.rs2.model.Entity;
     
    public class CombatEntity {
     
        public Entity entity;
        public Entity facing;
        public boolean hasAttacked;
        public CombatEntity attacker = null;
        public CombatEntity attacking = null;
     
        public CombatEntity(Entity entity, Entity facing) {
                this.entity = entity;
                this.facing = facing;
        }
     
        public boolean isEntity(Entity entity) {
                if(this.entity == entity) {
                        return true;
                }
                return false;
        }
     
        public boolean getHasAttacked() {
                return hasAttacked;
        }
     
        public void setHasAttacked(boolean bool) {
                hasAttacked = bool;
        }
     
        public Entity getEntity() {
                return entity;
        }
     
        public Entity getFacing() {
                return facing;
        }
     
        public void setFacing(Entity facing) {
                this.facing = facing;
        }
     
        public CombatEntity getAttacking() {
                return attacking;
        }
     
        public void setAttacking(CombatEntity entity) {
                attacking = entity;
        }
     
        public CombatEntity getAttacker() {
                return attacker;
        }
     
        public void setAttacker(CombatEntity attacker) {
                this.attacker = attacker;
        }
     
        public boolean beingAttacked() {
                if(attacker != null) {
                        return true;
                }
                return false;
        }
     
        public boolean isAttacking() {
                if(attacking != null) {
                        return true;
                }
                return false;
        }
    }