Thread: Instance NPCs Unable to be Interacted With

Page 1 of 2 12 LastLast
Results 1 to 10 of 12
  1. #1 Instance NPCs Unable to be Interacted With 
    Donator
    The Stoned's Avatar
    Join Date
    Jan 2013
    Posts
    638
    Thanks given
    62
    Thanks received
    80
    Rep Power
    62
    I am working on creating boss instances, and have run into an issue with interacting with the NPCs spawned in the newly created instance room.

    The Instance is being created with the following: (this example copies the Bandos throne room and places it wherever an empty 8x8 chunk can be found)
    Code:
    int[] boundChuncks = RegionBuilder.findEmptyChunkBound(8, 8); 
    RegionBuilder.copyAllPlanesMap(355, 667, boundChuncks[0], boundChuncks[1], 8);
    player.setNextWorldTile(getWorldTile(24, 21));
    Code:
    public WorldTile getWorldTile(int mapX, int mapY) {
          return new WorldTile(boundChuncks[0]*8 + mapX, boundChuncks[1]*8 + mapY, 2);
    }
    The issue comes when the NPCs are actually spawned. All of the NPCs are unable to move, and are unable to be attacked/interacted with.

    Some Background:
    • I am able to have them register me as a target and rotate in place, as seen in the 2 screenshots attached.
    • I am able to walk around freely in the instance as if I were actually in the throne room.
    • The coordinates for these rooms are different each time, but the NPCs spawn in the correct relative positions.
    • Should be obv, but there is a controller for the instances


    I am aware that NPCs are unable to be attacked if not on land, but I do not know how/where that check is handled.
    My question is, How can I enable NPCs to be attacked/interacted within these newly generated chunks/Instance Controller?


    Reply With Quote  
     

  2. #2  
    Contributor

    clem585's Avatar
    Join Date
    Sep 2013
    Posts
    3,756
    Thanks given
    703
    Thanks received
    691
    Discord
    View profile
    Rep Power
    518
    Have you checked the server console for any errors? There might be some coordinates check that validates if you're in the original coordinates of the instance. Or a controller check to be able to decrement killcount
    Project thread
    Reply With Quote  
     

  3. #3  
    Donator
    The Stoned's Avatar
    Join Date
    Jan 2013
    Posts
    638
    Thanks given
    62
    Thanks received
    80
    Rep Power
    62
    Quote Originally Posted by clem585 View Post
    Have you checked the server console for any errors? There might be some coordinates check that validates if you're in the original coordinates of the instance. Or a controller check to be able to decrement killcount
    There console doesn't have any errors, and through tests of spawning NPCs off the map, it behaves like a null check just disables the NPC process() method.
    I first looked in NPCCombat, World, and Entity. I haven't found any checks for coords yet. I have found checks for the NPCs map hashname when determining the walking path, but the issue seems to be coming before that check.

    Here is a copy of an InstanceNPC class I made. You can see the getPossibleTargets method that actually makes them rotate on my position.

    Code:
    package com.rs.game.npc.combat;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import com.rs.game.Entity;
    import com.rs.game.World;
    import com.rs.game.WorldTile;
    import com.rs.game.npc.NPC;
    import com.rs.game.player.Player;
    import com.rs.utils.Utils;
    
    /**
     * @author taylo || Swaghetti || Jul 21, 2022 
     *
     */
    
     @suppressWarnings("serial")
    public class InstanceNPC extends NPC {
    	
    	public InstanceNPC(int id, WorldTile tile) {
    		super(id, tile, -1, true, true);
    		setForceMultiArea(true);
    		setNoDistanceCheck(true);
    		setAtMultiArea(true);
    		setRandomWalk(true);
    	}
    
    	@Override
    	public ArrayList<Entity> getPossibleTargets() {
    		ArrayList<Entity> possibleTarget = new ArrayList<Entity>(1);
    		List<Integer> playerIndexes = World.getRegion(getRegionId()).getPlayerIndexes();
    		if (playerIndexes != null) {
    			for (int npcIndex : playerIndexes) {
    				Player player = World.getPlayers().get(npcIndex);
    				if (player == null || player.isDead() || player.hasFinished() || !player.isRunning())
    					continue;
    				possibleTarget.add(player);
    			}
    		}
    		return possibleTarget;
    	}
    	
    	@Override
    	public boolean isCantFollowUnderCombat() {
    		return false;
    	}
    	
    	@Override
    	public boolean hasRandomWalk() {
    		return true;
    	}
    	
    	@Override
    	public boolean isNoDistanceCheck() {
    		return true;
    	}
    	
    	
    }
    Last edited by The Stoned; 07-23-2022 at 11:29 PM.
    Reply With Quote  
     

  4. #4  
    Donator
    The Stoned's Avatar
    Join Date
    Jan 2013
    Posts
    638
    Thanks given
    62
    Thanks received
    80
    Rep Power
    62
    I have been able to get the NPCs to attack, and I am able to attack the NPCs as well now.
    The only remaining problem is that the NPCs are not generating a walk path before attacking.

    For example, the range and mage attacks are done throughout the Bandos room, but the melee NPCs will not walk towards the target. They only attack when I walk in range of them.

    I was able to make them attack by removing this in PlayerCombat.java and NPCCombat.java:
    Code:
    if (!player.clipedProjectile(target, target instanceof NexMinion ? false : maxDistance == 0)) {
    	return 0;
    }
    Does anyone know how to allow NPCs to walk in the instance area?
    As a player, I have always been able to walk around the room like normal.
    Reply With Quote  
     

  5. #5  
    Contributor

    clem585's Avatar
    Join Date
    Sep 2013
    Posts
    3,756
    Thanks given
    703
    Thanks received
    691
    Discord
    View profile
    Rep Power
    518
    Quote Originally Posted by The Stoned View Post
    I have been able to get the NPCs to attack, and I am able to attack the NPCs as well now.
    The only remaining problem is that the NPCs are not generating a walk path before attacking.

    For example, the range and mage attacks are done throughout the Bandos room, but the melee NPCs will not walk towards the target. They only attack when I walk in range of them.

    I was able to make them attack by removing this in PlayerCombat.java and NPCCombat.java:
    Code:
    if (!player.clipedProjectile(target, target instanceof NexMinion ? false : maxDistance == 0)) {
    	return 0;
    }
    Does anyone know how to allow NPCs to walk in the instance area?
    As a player, I have always been able to walk around the room like normal.
    Can you check in NPC.java and NPCCombat.java? Post them if you can. There should be a check somewhere to make the (melee) NPC walk to the target when in combat
    Project thread
    Reply With Quote  
     

  6. #6  
    Donator
    The Stoned's Avatar
    Join Date
    Jan 2013
    Posts
    638
    Thanks given
    62
    Thanks received
    80
    Rep Power
    62
    Quote Originally Posted by clem585 View Post
    Can you check in NPC.java and NPCCombat.java? Post them if you can. There should be a check somewhere to make the (melee) NPC walk to the target when in combat
    I have been focused around this part of NPCCombat.java, but please feel free to explore.


    Code:
    if ((!npc.clipedProjectile(target, maxDistance == 0 && !forceCheckClipAsRange(target))) || !Utils.isOnRange(npc.getX(), npc.getY(), size, target.getX(), target.getY(), targetSize, maxDistance)) {
    	if (!npc.calcFollow(target, npc.getRun() ? 2 : 1, true, npc.isIntelligentRouteFinder())
    		&& combatDelay < 3 && attackStyle == NPCCombatDefinitions.MELEE)
    			combatDelay = 3;
    		return true;
    	}
    }
    NPC.java
    Code:
    package com.rs.game.npc;
    
    import java.io.IOException;
    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    
    import com.rs.Settings;
    import com.rs.cache.Cache;
    import com.rs.cache.loaders.ItemDefinitions;
    import com.rs.cache.loaders.NPCDefinitions;
    import com.rs.cores.CoresManager;
    import com.rs.game.Animation;
    import com.rs.game.Entity;
    import com.rs.game.ForceTalk;
    import com.rs.game.Graphics;
    import com.rs.game.Hit;
    import com.rs.game.World;
    import com.rs.game.WorldTile;
    import com.rs.game.Hit.HitLook;
    import com.rs.game.item.Item;
    import com.rs.game.npc.combat.NPCCombat;
    import com.rs.game.npc.combat.NPCCombatDefinitions;
    import com.rs.game.npc.familiar.Familiar;
    import com.rs.game.player.Player;
    import com.rs.game.player.Skills;
    import com.rs.game.player.actions.HerbCleaning;
    import com.rs.game.player.actions.PlayerCombat;
    import com.rs.game.player.content.Burying;
    import com.rs.game.player.controlers.WarriorsGuildControler;
    import com.rs.game.player.controlers.Wilderness;
    import com.rs.game.tasks.WorldTask;
    import com.rs.game.tasks.WorldTasksManager;
    import com.rs.utils.MapAreas;
    import com.rs.utils.Misc;
    import com.rs.utils.NPCBonuses;
    import com.rs.utils.NPCCombatDefinitionsL;
    import com.rs.utils.NPCDrops;
    import com.rs.utils.Utils;
    
    public class NPC extends Entity implements Serializable {
    
    	private static final long serialVersionUID = -4794678936277614443L;
    
    	private int id;
    	private int renderEmote;
    	private WorldTile respawnTile;
    	private int mapAreaNameHash;
    	private boolean canBeAttackFromOutOfArea;
    	private boolean randomwalk;
    	private int[] bonuses; // 0 stab, 1 slash, 2 crush,3 mage, 4 range, 5 stab
    							// def, blahblah till 9
    	private boolean spawned;
    	private transient NPCCombat combat;
    	private WorldTile forceWalk;
    	private boolean intelligentRouteFinder;
    	private long lastAttackedByTarget;
    	private boolean cantInteract;
    	private int capDamage;
    	private int lureDelay;
    	private boolean cantFollowUnderCombat;
    	private boolean forceAgressive;
    	private int forceTargetDistance;
    	private boolean forceFollowClose;
    	private boolean forceMultiAttacked;
    
    	// npc masks
    	private transient Transformation nextTransformation;
    	// name changing masks
    	private String name;
    	private transient boolean changedName;
    	private int combatLevel;
    	private transient boolean changedCombatLevel;
    	private transient SecondaryBar nextSecondaryBar;
    	private transient Player owner;
    
    	public NPC(int id, WorldTile tile, int mapAreaNameHash, boolean canBeAttackFromOutOfArea) {
    		this(id, tile, mapAreaNameHash, canBeAttackFromOutOfArea, false);
    	}
    
    	private boolean noDistanceCheck;
    
    	public void setNoDistanceCheck(boolean noDistanceCheck) {
    		this.noDistanceCheck = noDistanceCheck;
    	}
    
    	public boolean isNoDistanceCheck() {
    		return noDistanceCheck;
    	}
    
    	public void SpawnPrivateNPC(Player owner, int id, boolean isPrivateNpc, int loc) {
    		this.owner = owner;
    		// this.id = npcId;
    		// this.loc = WorldTile.x;
    	}
    
    	public void isPrivateNpc() {
    
    	}
    
    	public void setSpawned(boolean spawned) {
    		this.spawned = spawned;
    	}
    
    	public boolean isFamiliar() {
    		return this instanceof Familiar;
    	}
    
    	public SecondaryBar getNextSecondaryBar() {
    		return nextSecondaryBar;
    	}
    
    	public void setNextSecondaryBar(SecondaryBar secondaryBar) {
    		this.nextSecondaryBar = secondaryBar;
    	}
    
    	/*
    	 * creates and adds npc
    	 */
    	public NPC(int id, WorldTile tile, int mapAreaNameHash, boolean canBeAttackFromOutOfArea, boolean spawned) {
    		super(tile);
    		this.id = id;
    		this.respawnTile = new WorldTile(tile);
    		this.mapAreaNameHash = mapAreaNameHash;
    		this.canBeAttackFromOutOfArea = canBeAttackFromOutOfArea;
    		this.spawned = spawned;
    		combatLevel = -1;
    		setHitpoints(getMaxHitpoints());
    		setDirection(getRespawnDirection());
    		setRandomWalk((getDefinitions().walkMask & 0x2) != 0 || forceRandomWalk(id));
    		bonuses = NPCBonuses.getBonuses(id);
    		combat = new NPCCombat(this);
    		capDamage = -1;
    		lureDelay = 12000;
    		// npc is inited on creating instance
    		initEntity();
    		World.addNPC(this);
    		World.updateEntityRegion(this);
    		// npc is started on creating instance
    		loadMapRegions();
    		checkMultiArea();
    	}
    
    	@Override
    	public boolean needMasksUpdate() {
    		return super.needMasksUpdate() || nextSecondaryBar != null || nextTransformation != null
    				|| getCustomName() != null || getCustomCombatLevel() >= 0 /*
    																			 * * changedName
    																			 */;
    	}
    
    	public void transformIntoNPC(int id) {
    		setNPC(id);
    		nextTransformation = new Transformation(id);
    	}
    
    	public void setNPC(int id) {
    		this.id = id;
    		bonuses = NPCBonuses.getBonuses(id);
    	}
    
    	@Override
    	public void resetMasks() {
    		super.resetMasks();
    		nextTransformation = null;
    		changedCombatLevel = false;
    		changedName = false;
    		nextSecondaryBar = null;
    	}
    
    	public int getMapAreaNameHash() {
    		return mapAreaNameHash;
    	}
    
    	public boolean canBeAttackFromOutOfArea() {
    		return canBeAttackFromOutOfArea;
    	}
    
    	public NPCDefinitions getDefinitions() {
    		return NPCDefinitions.getNPCDefinitions(id);
    	}
    
    	public NPCCombatDefinitions getCombatDefinitions() {
    		return NPCCombatDefinitionsL.getNPCCombatDefinitions(id);
    	}
    
    	@Override
    	public int getMaxHitpoints() {
    		return getCombatDefinitions().getHitpoints();
    	}
    
    	public int getId() {
    		return id;
    	}
    
    	public static void main(String[] args) throws IOException {
    		Cache.init();
    	}
    
    	public void processNPC() {
    		if (isDead())
    			return;
    		if (!combat.process()) { // if not under combat
    			if (!isForceWalking()) {// combat still processed for attack delay
    									// go down
    				// random walk
    				if (!cantInteract) {
    					if (!checkAgressivity()) {
    						if (getFreezeDelay() < Utils.currentTimeMillis()) {
    							if (((hasRandomWalk()) && World.getRotation(getPlane(), getX(), getY()) == 0) // temporary
    																											// fix
    									&& Math.random() * 1000.0 < 100.0) {
    								int moveX = (int) Math.round(Math.random() * 10.0 - 5.0);
    								int moveY = (int) Math.round(Math.random() * 10.0 - 5.0);
    								resetWalkSteps();
    								if (getMapAreaNameHash() != -1) {
    									if (!MapAreas.isAtArea(getMapAreaNameHash(), this)) {
    										forceWalkRespawnTile();
    										return;
    									}
    									addWalkSteps(getX() + moveX, getY() + moveY, 5);
    								} else
    									addWalkSteps(respawnTile.getX() + moveX, respawnTile.getY() + moveY, 5);
    							}
    						}
    					}
    				}
    			}
    		}
    
    		// if (getCombat().getTarget() instanceof Player) {
    		// }
    
    		if (this.getDefinitions().getName().contains("Revenant")) {
    			setForceAgressive(true);
    		}
    		if (this.getDefinitions().getName().contains("Revenant")) {
    			final Player player = getCombat().getTarget() instanceof Player ? (Player) getCombat().getTarget() : null;
    			if (player != null) {
    				if (player.containsForinthry()) {
    					this.setForceAgressive(false);
    				}
    			}
    		}
    
    		if (this.getDefinitions().getName().contains("Revenant")) {
    			final Player player = getCombat().getTarget() instanceof Player ? (Player) getCombat().getTarget() : null;
    			if (player != null) {
    				if (player.containsForinthry()) {
    					getCombat().setTarget(null);
    				}
    				this.setForceAgressive(false);
    			}
    		}
    		if (id == 11512)
    			setName("Donator Manager");
    		if (id == 2253)
    			setName("Player Listings");
    		if (id == 705)
    			setName("Melee shop");
    		if (id == 1861)
    			setName("Range shop");
    		if (id == 4707)
    			setName("Magic shop");
    		if (id == 9371)
    			setName("<img=4> Ironman Shop");
    		if (id == 882)
    			setName("Recipe of Disaster");
    		if (id == 3374)
    			setName("Skilling Task Manager");
    		if (id == 455)
    			setName("Herblore Supplies");
    		if (id == 4511)
    			setName("Lunar Diplomacy");
    		if (id == 219)
    			setName("Supplies/Resources");
    		
    		if (isForceWalking()) {
    			if (getFreezeDelay() < Utils.currentTimeMillis()) {
    				setRandomWalk(false);
    				if (id == 519)
    					setRandomWalk(false);
    				if (id == 219)
    					setRandomWalk(false);
    				if (id == 455)
    					setRandomWalk(false);
    				if (id == 550)
    					setRandomWalk(false);
    				if (id == 546)
    					setRandomWalk(false);
    				if (id == 549)
    					setRandomWalk(false);
    				if (id == 683)
    					setRandomWalk(false);
    				if (id == 2676)
    					setRandomWalk(false);
    				if (id == 948)
    					setRandomWalk(false);
    				if (id == 2676)
    					setRandomWalk(false);
    				if (id == 948)
    					setRandomWalk(false);
    				if (id == 445)
    					setRandomWalk(false);
    				if (id == 3299)
    					setRandomWalk(false);
    				if (id == 2732)
    					setRandomWalk(false);
    				if (id == 4906)
    					setRandomWalk(false);
    				if (id == 3706)
    					setRandomWalk(false);
    				if (getX() != forceWalk.getX() || getY() != forceWalk.getY()) {
    					if (!hasWalkSteps())
    						addWalkSteps(forceWalk.getX(), forceWalk.getY(), getSize(), true);
    					if (!hasWalkSteps()) { // failing finding route
    						setNextWorldTile(new WorldTile(forceWalk)); // force
    																	// tele
    																	// to
    																	// the
    																	// forcewalk
    																	// place
    						forceWalk = null; // so ofc reached forcewalk place
    					}
    				} else
    					// walked till forcewalk place
    					forceWalk = null;
    			}
    		}
    	}
    
    	@Override
    	public void processEntity() {
    		super.processEntity();
    		processNPC();
    	}
    
    	public int getRespawnDirection() {
    		NPCDefinitions definitions = getDefinitions();
    		if (definitions.anInt853 << 32 != 0 && definitions.respawnDirection > 0 && definitions.respawnDirection <= 8)
    			return (4 + definitions.respawnDirection) << 11;
    		return 0;
    	}
    
    	/*
    	 * forces npc to random walk even if cache says no, used because of fake cache
    	 * information
    	 */
    	private static boolean forceRandomWalk(int npcId) {
    		switch (npcId) {
    		case 11226:
    			return true;
    		default:
    			return false;
    		}
    	}
    
    	@Override
    	public void handleIngoingHit(final Hit hit) {
    		if (capDamage != -1 && hit.getDamage() > capDamage)
    			hit.setDamage(capDamage);
    		if (hit.getLook() != HitLook.MELEE_DAMAGE && hit.getLook() != HitLook.RANGE_DAMAGE
    				&& hit.getLook() != HitLook.MAGIC_DAMAGE)
    			return;
    		Entity source = hit.getSource();
    		if (source == null)
    			return;
    		if (source instanceof Player) {
    			final Player p2 = (Player) source;
    			if (p2.getPrayer().hasPrayersOn()) {
    				if (p2.getPrayer().usingPrayer(1, 18)) {
    					final NPC target = this;
    					if (hit.getDamage() > 0)
    						World.sendProjectile(p2, this, 2263, 11, 11, 20, 5, 0, 0);
    					p2.heal(hit.getDamage() / 5);
    					p2.getPrayer().drainPrayer(hit.getDamage() / 5);
    					WorldTasksManager.schedule(new WorldTask() {
    						@Override
    						public void run() {
    							setNextGraphics(new Graphics(2264));
    							if (hit.getDamage() > 0)
    								World.sendProjectile(target, p2, 2263, 11, 11, 20, 5, 0, 0);
    						}
    					}, 1);
    				}
    				if (hit.getDamage() == 0)
    					return;
    				if (!p2.getPrayer().isBoostedLeech()) {
    					if (hit.getLook() == HitLook.MELEE_DAMAGE) {
    						if (p2.getPrayer().usingPrayer(1, 19)) {
    							p2.getPrayer().setBoostedLeech(true);
    							return;
    						} else if (p2.getPrayer().usingPrayer(1, 1)) { // sap
    																		// att
    							if (Utils.getRandom(4) == 0) {
    								if (p2.getPrayer().reachedMax(0)) {
    									p2.getPackets().sendGameMessage(
    											"Your opponent has been weakened so much that your sap curse has no effect.",
    											true);
    								} else {
    									p2.getPrayer().increaseLeechBonus(0);
    									p2.getPackets().sendGameMessage(
    											"Your curse drains Attack from the enemy, boosting your Attack.", true);
    								}
    								p2.setNextAnimation(new Animation(12569));
    								p2.setNextGraphics(new Graphics(2214));
    								p2.getPrayer().setBoostedLeech(true);
    								World.sendProjectile(p2, this, 2215, 35, 35, 20, 5, 0, 0);
    								WorldTasksManager.schedule(new WorldTask() {
    									@Override
    									public void run() {
    										setNextGraphics(new Graphics(2216));
    									}
    								}, 1);
    								return;
    							}
    						} else {
    							if (p2.getPrayer().usingPrayer(1, 10)) {
    								if (Utils.getRandom(7) == 0) {
    									if (p2.getPrayer().reachedMax(3)) {
    										p2.getPackets().sendGameMessage(
    												"Your opponent has been weakened so much that your leech curse has no effect.",
    												true);
    									} else {
    										p2.getPrayer().increaseLeechBonus(3);
    										p2.getPackets().sendGameMessage(
    												"Your curse drains Attack from the enemy, boosting your Attack.", true);
    									}
    									p2.setNextAnimation(new Animation(12575));
    									p2.getPrayer().setBoostedLeech(true);
    									World.sendProjectile(p2, this, 2231, 35, 35, 20, 5, 0, 0);
    									WorldTasksManager.schedule(new WorldTask() {
    										@Override
    										public void run() {
    											setNextGraphics(new Graphics(2232));
    										}
    									}, 1);
    									return;
    								}
    							}
    							if (p2.getPrayer().usingPrayer(1, 14)) {
    								if (Utils.getRandom(7) == 0) {
    									if (p2.getPrayer().reachedMax(7)) {
    										p2.getPackets().sendGameMessage(
    												"Your opponent has been weakened so much that your leech curse has no effect.",
    												true);
    									} else {
    										p2.getPrayer().increaseLeechBonus(7);
    										p2.getPackets().sendGameMessage(
    												"Your curse drains Strength from the enemy, boosting your Strength.",
    												true);
    									}
    									p2.setNextAnimation(new Animation(12575));
    									p2.getPrayer().setBoostedLeech(true);
    									World.sendProjectile(p2, this, 2248, 35, 35, 20, 5, 0, 0);
    									WorldTasksManager.schedule(new WorldTask() {
    										@Override
    										public void run() {
    											setNextGraphics(new Graphics(2250));
    										}
    									}, 1);
    									return;
    								}
    							}
    
    						}
    					}
    					if (hit.getLook() == HitLook.RANGE_DAMAGE) {
    						if (p2.getPrayer().usingPrayer(1, 2)) { // sap range
    							if (Utils.getRandom(4) == 0) {
    								if (p2.getPrayer().reachedMax(1)) {
    									p2.getPackets().sendGameMessage(
    											"Your opponent has been weakened so much that your sap curse has no effect.",
    											true);
    								} else {
    									p2.getPrayer().increaseLeechBonus(1);
    									p2.getPackets().sendGameMessage(
    											"Your curse drains Range from the enemy, boosting your Range.", true);
    								}
    								p2.setNextAnimation(new Animation(12569));
    								p2.setNextGraphics(new Graphics(2217));
    								p2.getPrayer().setBoostedLeech(true);
    								World.sendProjectile(p2, this, 2218, 35, 35, 20, 5, 0, 0);
    								WorldTasksManager.schedule(new WorldTask() {
    									@Override
    									public void run() {
    										setNextGraphics(new Graphics(2219));
    									}
    								}, 1);
    								return;
    							}
    						} else if (p2.getPrayer().usingPrayer(1, 11)) {
    							if (Utils.getRandom(7) == 0) {
    								if (p2.getPrayer().reachedMax(4)) {
    									p2.getPackets().sendGameMessage(
    											"Your opponent has been weakened so much that your leech curse has no effect.",
    											true);
    								} else {
    									p2.getPrayer().increaseLeechBonus(4);
    									p2.getPackets().sendGameMessage(
    											"Your curse drains Range from the enemy, boosting your Range.", true);
    								}
    								p2.setNextAnimation(new Animation(12575));
    								p2.getPrayer().setBoostedLeech(true);
    								World.sendProjectile(p2, this, 2236, 35, 35, 20, 5, 0, 0);
    								WorldTasksManager.schedule(new WorldTask() {
    									@Override
    									public void run() {
    										setNextGraphics(new Graphics(2238));
    									}
    								});
    								return;
    							}
    						}
    					}
    					if (hit.getLook() == HitLook.MAGIC_DAMAGE) {
    						if (p2.getPrayer().usingPrayer(1, 3)) { // sap mage
    							if (Utils.getRandom(4) == 0) {
    								if (p2.getPrayer().reachedMax(2)) {
    									p2.getPackets().sendGameMessage(
    											"Your opponent has been weakened so much that your sap curse has no effect.",
    											true);
    								} else {
    									p2.getPrayer().increaseLeechBonus(2);
    									p2.getPackets().sendGameMessage(
    											"Your curse drains Magic from the enemy, boosting your Magic.", true);
    								}
    								p2.setNextAnimation(new Animation(12569));
    								p2.setNextGraphics(new Graphics(2220));
    								p2.getPrayer().setBoostedLeech(true);
    								World.sendProjectile(p2, this, 2221, 35, 35, 20, 5, 0, 0);
    								WorldTasksManager.schedule(new WorldTask() {
    									@Override
    									public void run() {
    										setNextGraphics(new Graphics(2222));
    									}
    								}, 1);
    								return;
    							}
    						} else if (p2.getPrayer().usingPrayer(1, 12)) {
    							if (Utils.getRandom(7) == 0) {
    								if (p2.getPrayer().reachedMax(5)) {
    									p2.getPackets().sendGameMessage(
    											"Your opponent has been weakened so much that your leech curse has no effect.",
    											true);
    								} else {
    									p2.getPrayer().increaseLeechBonus(5);
    									p2.getPackets().sendGameMessage(
    											"Your curse drains Magic from the enemy, boosting your Magic.", true);
    								}
    								p2.setNextAnimation(new Animation(12575));
    								p2.getPrayer().setBoostedLeech(true);
    								World.sendProjectile(p2, this, 2240, 35, 35, 20, 5, 0, 0);
    								WorldTasksManager.schedule(new WorldTask() {
    									@Override
    									public void run() {
    										setNextGraphics(new Graphics(2242));
    									}
    								}, 1);
    								return;
    							}
    						}
    					}
    
    					// overall
    
    					if (p2.getPrayer().usingPrayer(1, 13)) { // leech defence
    						if (Utils.getRandom(10) == 0) {
    							if (p2.getPrayer().reachedMax(6)) {
    								p2.getPackets().sendGameMessage(
    										"Your opponent has been weakened so much that your leech curse has no effect.",
    										true);
    							} else {
    								p2.getPrayer().increaseLeechBonus(6);
    								p2.getPackets().sendGameMessage(
    										"Your curse drains Defence from the enemy, boosting your Defence.", true);
    							}
    							p2.setNextAnimation(new Animation(12575));
    							p2.getPrayer().setBoostedLeech(true);
    							World.sendProjectile(p2, this, 2244, 35, 35, 20, 5, 0, 0);
    							WorldTasksManager.schedule(new WorldTask() {
    								@Override
    								public void run() {
    									setNextGraphics(new Graphics(2246));
    								}
    							}, 1);
    							return;
    						}
    					}
    				}
    			}
    		}
    
    	}
    
    	@Override
    	public void reset() {
    		super.reset();
    		setDirection(getRespawnDirection());
    		combat.reset();
    		bonuses = NPCBonuses.getBonuses(id); // back to real bonuses
    		forceWalk = null;
    	}
    
    	@Override
    	public void finish() {
    		if (hasFinished())
    			return;
    		setFinished(true);
    		World.updateEntityRegion(this);
    		World.removeNPC(this);
    	}
    
    	public void setRespawnTask() {
    		if (!hasFinished()) {
    			reset();
    			setLocation(respawnTile);
    			finish();
    		}
    		CoresManager.slowExecutor.schedule(new Runnable() {
    			@Override
    			public void run() {
    				try {
    					spawn();
    				} catch (Exception e) {
    					e.printStackTrace();
    				} catch (Error e) {
    					e.printStackTrace();
    				}
    			}
    		}, getId() == 1265 ? 500 : getCombatDefinitions().getRespawnDelay() * 600, TimeUnit.MILLISECONDS);
    	}
    
    	public void deserialize() {
    		if (combat == null)
    			combat = new NPCCombat(this);
    		spawn();
    	}
    
    	public void spawn() {
    		setFinished(false);
    		World.addNPC(this);
    		setLastRegionId(0);
    		World.updateEntityRegion(this);
    		loadMapRegions();
    		checkMultiArea();
    	}
    
    	public NPCCombat getCombat() {
    		return combat;
    	}
    
    	@Override
    	public void sendDeath(Entity source) {
    		final NPCCombatDefinitions defs = getCombatDefinitions();
    		resetWalkSteps();
    		combat.removeTarget();
    		setNextAnimation(null);
    		WorldTasksManager.schedule(new WorldTask() {
    			int loop;
    
    			@Override
    			public void run() {
    				if (loop == 0) {
    					setNextAnimation(new Animation(defs.getDeathEmote()));
    				} else if (loop >= defs.getDeathDelay()) {
    					drop();
    					reset();
    					setLocation(respawnTile);
    					finish();
    					if (getId() == 1265)
    						setRespawnTask();
    					if (!spawned)
    						setRespawnTask();
    					stop();
    				}
    				loop++;
    			}
    		}, 0, 1);
    	}
    
    	public void drop() {
    		try {
    
    			Drop[] drops = NPCDrops.getDrops(id);
    			if (drops == null)
    				return;
    			Player killer = getMostDamageReceivedSourcePlayer();
    			if (killer == null)
    				return;
    			if (killer.getTask() != null) {
    				if (getName().contains(killer.getTask().getName())) {
    					killer.getTask().onMonsterDeath(killer, this);
    				}
    			}
    			// if (killer.slayerTask.getTaskMonstersLeft() > 0) {
    			// for (String m : killer.slayerTask.getTask().slayable) {
    			// if (getDefinitions().name.equals(m)) {
    			// killer.slayerTask.onMonsterDeath(killer, this);
    			// break;
    			// }
    			// } World.sendWorldMessage("<col=ee7600><img=18>[News] "
    			// +player.getDisplayName() + " found an uncut onyx in the crystal chest.",
    			// false);
    
    			// }
    			Drop[] possibleDrops = new Drop[drops.length];
    			int possibleDropsCount = 0;
    			for (Drop drop : drops) {
    				if (drop.getRate() == 100)
    					sendDrop(killer, drop);
    				else {
    					if ((Utils.getRandomDouble(99) + 1) <= drop.getRate() * 1.5)
    						possibleDrops[possibleDropsCount++] = drop;
    				}
    			}
    			if (possibleDropsCount > 0)
    				sendDrop(killer, possibleDrops[Utils.getRandom(possibleDropsCount - 1)]);
    		} catch (Exception e) {
    			e.printStackTrace();
    		} catch (Error e) {
    			e.printStackTrace();
    		}
    	}
    
    	public void sendDrop(Player player, Drop drop) {
    		int size = getSize();
    		int bonus = 1;
    		if (World.doubledrops == true) {
    			bonus = 2;
    		}
    		String dropName = ItemDefinitions.getItemDefinitions(drop.getItemId()).getName().toLowerCase();
    		Item item = ItemDefinitions.getItemDefinitions(drop.getItemId())
    				.isStackable() ? new Item(drop.getItemId(),
    				(drop.getMinAmount() * Settings.DROP_RATE*bonus)
    						+ Utils.getRandom(drop.getExtraAmount()
    								* Settings.DROP_RATE*bonus)) : new Item(
    				drop.getItemId(), drop.getMinAmount()
    						+ Utils.getRandom(drop.getExtraAmount()));
    		if (dropName.contains("pernix") || dropName.contains("zamorakian") || dropName.contains("dragon pickaxe") || dropName.contains("callisto") || dropName.contains("saradomin") || dropName.contains("armadyl") || dropName.contains("draconic") || dropName.contains("torva") || dropName.contains("virtus") //Rare drops
    				|| dropName.contains("bandos")) {
    			World.sendWorldMessage("<col=ee7600><shad=00000><img=8> " + player.getDisplayName() + " has received a "
    					+ dropName + " as drop!", false);
    		}
    		
    	
    	if (player.getInventory().containsItem(18337, 1)// Bonecrusher
    			&& item.getDefinitions().getName().toLowerCase()
    					.contains("bones")) {
    		player.getSkills().addXp(Skills.PRAYER,
    				Burying.Bone.forId(drop.getItemId()).getExperience());
    		return;
    	}
    	if (player.getInventory().containsItem(19675, 1)// Herbicide
    			&& item.getDefinitions().getName().toLowerCase()
    					.contains("grimy")) {
    		if (player.getSkills().getLevelForXp(Skills.HERBLORE) >= HerbCleaning.getHerb(item.getId()).getLevel()) {
    			player.getSkills().addXp(
    					Skills.HERBLORE,
    					HerbCleaning.getHerb(drop.getItemId())
    							.getExperience() * 2);
    			return;
    		}
    	}
    		World.addGroundItem(new Item(drop.getItemId(), drop.getMinAmount() + Utils.getRandom(drop.getExtraAmount())),
    				new WorldTile(getCoordFaceX(size), getCoordFaceY(size), getPlane()), player, false, 180, true);
    		
    		int keyPartChance = Utils.random(1, 100);
    		if (keyPartChance >= 90) {
    			int whichHalf = Utils.random(1, 100);
    			if (whichHalf >= 50) {
    				World.addGroundItem(new Item(987, 1), new WorldTile(getCoordFaceX(size), getCoordFaceY(size), getPlane()), player, false, 180, true);
    			} else {
    				World.addGroundItem(new Item(985, 1), new WorldTile(getCoordFaceX(size), getCoordFaceY(size), getPlane()), player, false, 180, true);
    			}
    		}
    		
    		int charmDrop = Utils.random(1, 100);
    		if (charmDrop >= 15) {
    			int charmChance = Utils.random(1, 100);
    			if (charmChance >= 0 && charmChance <= 20) {
    				World.addGroundItem(new Item(12158, 1), new WorldTile(getCoordFaceX(size), getCoordFaceY(size), getPlane()), player, false, 180, true);
    			} else if (charmChance >= 21 && charmChance <= 50) {
    				World.addGroundItem(new Item(12160, 1), new WorldTile(getCoordFaceX(size), getCoordFaceY(size), getPlane()), player, false, 180, true);
    			} else if (charmChance >= 51 && charmChance <= 75) {
    				World.addGroundItem(new Item(12159, 1), new WorldTile(getCoordFaceX(size), getCoordFaceY(size), getPlane()), player, false, 180, true);
    			} else {
    				World.addGroundItem(new Item(12163, 1), new WorldTile(getCoordFaceX(size), getCoordFaceY(size), getPlane()), player, false, 180, true);
    			}
    		}
    		if (this.getName().contains("TzHaar")) {
    			World.addGroundItem(new Item(6529, 100 + Utils.getRandom(900)),
    					new WorldTile(getCoordFaceX(size), getCoordFaceY(size), getPlane()), player, false, 180, true);
    		}
    		if (this.getId() == 6230 || this.getId() == 6231 || this.getId() == 6229
    				|| this.getId() == 6232 || this.getId() == 6240 || this.getId() == 6241
    				|| this.getId() == 6242 || this.getId() ==  6233 || this.getId() == 6234
    				|| this.getId() == 6243 || this.getId() == 6244 || this.getId() == 6245
    				|| this.getId() == 6246 || this.getId() == 6238 || this.getId() == 6239
    				|| this.getId() == 6227 || this.getId() == 6625 || this.getId() == 6223
    				|| this.getId() == 6222) {
    			player.ArmadylKC++;
    	        player.getPackets().sendIComponentText(601, 8,  ""+ player.ArmadylKC);
    		}
    		if (this.getId() == 6278 || this.getId() == 6277 || this.getId() == 6276
    				|| this.getId() == 6283 || this.getId() == 6282 || this.getId() == 6280
    				|| this.getId() == 6281 || this.getId() == 6279 || this.getId() == 6275
    				|| this.getId() == 6271 || this.getId() == 6272 || this.getId() == 6273
    				|| this.getId() == 6274 || this.getId() == 6269 || this.getId() ==  6270
    				|| this.getId() == 6268 || this.getId() == 6265 || this.getId() == 6263
    				|| this.getId() == 6261 || this.getId() == 6260) {
    			player.BandosKC++;
    			player.getPackets().sendIComponentText(601, 9,  ""+ player.BandosKC);
    		}
    		if (this.getId() == 6257 || this.getId() == 6255 || this.getId() == 6256
    				|| this.getId() == 6258 || this.getId() == 6259 || this.getId() == 6254
    				|| this.getId() == 6252 || this.getId() == 6250 || this.getId() == 6248
    				|| this.getId() == 6247) {
    			player.SaradominKC++;
    			 player.getPackets().sendIComponentText(601, 10,  ""+ player.SaradominKC);
    		}
    		if (this.getId() == 6221 || this.getId() == 6219 || this.getId() == 6220
    				|| this.getId() == 6217 || this.getId() == 6216 || this.getId() == 6215
    				|| this.getId() == 6214 || this.getId() == 6213 || this.getId() == 6212
    				|| this.getId() == 6211 || this.getId() == 6218 || this.getId() == 6208
    				|| this.getId() == 6206 || this.getId() == 6204 || this.getId() == 6203) {
    			player.ZamorakKC++;
    			player.getPackets().sendIComponentText(601, 11,  ""+ player.ZamorakKC);
    		}
    		int random = Utils.random(1, 100);
    		if (random >= 95 && random <= 100) {
    			if (this.getId() == 116 || this.getId() == 4292 || this.getId() == 4291 || this.getId() == 6078
    					|| this.getId() == 6079 || this.getId() == 6080 && drop.getItemId() == 8844) {
    				player.getDialogueManager().startDialogue("SimpleMessage", "There is a defender dropped on the floor!");
    				WarriorsGuildControler.dropDefender(player, this);
    			}
    		}
    	}
    
    	@Override
    	public int getSize() {
    		return getDefinitions().size;
    	}
    
    	public int getMaxHit() {
    		return getCombatDefinitions().getMaxHit();
    	}
    
    	public int[] getBonuses() {
    		return bonuses;
    	}
    
    	@Override
    	public double getMagePrayerMultiplier() {
    		return 0;
    	}
    
    	@Override
    	public double getRangePrayerMultiplier() {
    		return 0;
    	}
    
    	@Override
    	public double getMeleePrayerMultiplier() {
    		return 0;
    	}
    
    	public WorldTile getRespawnTile() {
    		return respawnTile;
    	}
    
    	public boolean isUnderCombat() {
    		return combat.underCombat();
    	}
    
    	@Override
    	public void setAttackedBy(Entity target) {
    		super.setAttackedBy(target);
    		if (target == combat.getTarget() && !(combat.getTarget() instanceof Familiar))
    			lastAttackedByTarget = Utils.currentTimeMillis();
    	}
    
    	public boolean canBeAttackedByAutoRelatie() {
    		return Utils.currentTimeMillis() - lastAttackedByTarget > lureDelay;
    	}
    
    	public boolean isForceWalking() {
    		return forceWalk != null;
    	}
    
    	public void setTarget(Entity entity) {
    		if (isForceWalking()) // if force walk not gonna get target
    			return;
    		combat.setTarget(entity);
    		lastAttackedByTarget = Utils.currentTimeMillis();
    	}
    
    	public void removeTarget() {
    		if (combat.getTarget() == null)
    			return;
    		combat.removeTarget();
    	}
    
    	public void forceWalkRespawnTile() {
    		setForceWalk(respawnTile);
    	}
    
    	public void setForceWalk(WorldTile tile) {
    		resetWalkSteps();
    		forceWalk = tile;
    	}
    
    	public boolean hasForceWalk() {
    		return forceWalk != null;
    	}
    
    	public ArrayList<Entity> getPossibleTargets() {
    		ArrayList<Entity> possibleTarget = new ArrayList<Entity>();
    		for (int regionId : getMapRegionsIds()) {
    			List<Integer> playerIndexes = World.getRegion(regionId).getPlayerIndexes();
    			if (playerIndexes != null) {
    				for (int npcIndex : playerIndexes) {
    					Player player = World.getPlayers().get(npcIndex);
    					if (player == null || player.isDead() || player.hasFinished() || !player.isRunning()
    							|| !player.withinDistance(this, forceTargetDistance > 0 ? forceTargetDistance
    									: (getCombatDefinitions().getAttackStyle() == NPCCombatDefinitions.MELEE ? 4
    											: getCombatDefinitions().getAttackStyle() == NPCCombatDefinitions.SPECIAL
    													? 64
    													: 8))
    							|| (!forceMultiAttacked && (!isAtMultiArea() || !player.isAtMultiArea())
    									&& player.getAttackedBy() != this
    									&& (player.getAttackedByDelay() > System.currentTimeMillis()
    											|| player.getFindTargetDelay() > System.currentTimeMillis()))
    							|| !clipedProjectile(player, false)
    							|| (!forceAgressive && !Wilderness.isAtWild(this) && player.getSkills()
    									.getCombatLevelWithSummoning() >= getDefinitions().combatLevel * 2))
    						continue;
    					possibleTarget.add(player);
    				}
    			}
    		}
    		return possibleTarget;
    	}
    
    	public boolean checkAgressivity() {
    		// if(!(Wilderness.isAtWild(this) &&
    		// getDefinitions().hasAttackOption())) {
    		if (!forceAgressive) {
    			NPCCombatDefinitions defs = getCombatDefinitions();
    			if (defs.getAgressivenessType() == NPCCombatDefinitions.PASSIVE)
    				return false;
    		}
    		// }
    		ArrayList<Entity> possibleTarget = getPossibleTargets();
    		if (!possibleTarget.isEmpty()) {
    			Entity target = possibleTarget.get(Utils.getRandom(possibleTarget.size() - 1));
    			setTarget(target);
    			target.setAttackedBy(target);
    			target.setFindTargetDelay(Utils.currentTimeMillis() + 10000);
    			return true;
    		}
    		return false;
    	}
    
    	public boolean isCantInteract() {
    		return cantInteract;
    	}
    
    	public void setCantInteract(boolean cantInteract) {
    		this.cantInteract = cantInteract;
    		if (cantInteract)
    			combat.reset();
    	}
    
    	public int getCapDamage() {
    		return capDamage;
    	}
    
    	public void setCapDamage(int capDamage) {
    		this.capDamage = capDamage;
    	}
    
    	public int getLureDelay() {
    		return lureDelay;
    	}
    
    	public void setLureDelay(int lureDelay) {
    		this.lureDelay = lureDelay;
    	}
    
    	public boolean isCantFollowUnderCombat() {
    		return cantFollowUnderCombat;
    	}
    
    	public void setCantFollowUnderCombat(boolean canFollowUnderCombat) {
    		this.cantFollowUnderCombat = canFollowUnderCombat;
    	}
    
    	public Transformation getNextTransformation() {
    		return nextTransformation;
    	}
    
    	@Override
    	public String toString() {
    		return getDefinitions().name + " - " + id + " - " + getX() + " " + getY() + " " + getPlane();
    	}
    
    	public boolean isForceAgressive() {
    		return forceAgressive;
    	}
    
    	public void setForceAgressive(boolean forceAgressive) {
    		this.forceAgressive = forceAgressive;
    	}
    
    	public int getForceTargetDistance() {
    		return forceTargetDistance;
    	}
    
    	public void setForceTargetDistance(int forceTargetDistance) {
    		this.forceTargetDistance = forceTargetDistance;
    	}
    
    	public boolean isForceFollowClose() {
    		return forceFollowClose;
    	}
    
    	public void setForceFollowClose(boolean forceFollowClose) {
    		this.forceFollowClose = forceFollowClose;
    	}
    
    	public boolean isForceMultiAttacked() {
    		return forceMultiAttacked;
    	}
    
    	public void setForceMultiAttacked(boolean forceMultiAttacked) {
    		this.forceMultiAttacked = forceMultiAttacked;
    	}
    
    	public boolean hasRandomWalk() {
    		return randomwalk;
    	}
    
    	public void setRandomWalk(boolean forceRandomWalk) {
    		this.randomwalk = forceRandomWalk;
    	}
    
    	public String getCustomName() {
    		return name;
    	}
    
    	public void setName(String string) {
    		this.name = getDefinitions().name.equals(string) ? null : string;
    		changedName = true;
    	}
    	public int getRemote() {
    		return getDefinitions().renderEmote;
    	}
    	
    	public int setRemote(int remote) {
    		return getDefinitions().renderEmote = remote;
    	}
    	
    
    	public int getCustomCombatLevel() {
    		return combatLevel;
    	}
    
    	public int getCombatLevel() {
    		return combatLevel >= 0 ? combatLevel : getDefinitions().combatLevel;
    	}
    
    	public String getName() {
    		return name != null ? name : getDefinitions().name;
    	}
    
    	public void setCombatLevel(int level) {
    		combatLevel = getDefinitions().combatLevel == level ? -1 : level;
    		changedCombatLevel = true;
    	}
    
    	public boolean hasChangedName() {
    		return changedName;
    	}
    
    	public boolean hasChangedCombatLevel() {
    		return changedCombatLevel;
    	}
    
    	public WorldTile getMiddleWorldTile() {
    		int size = getSize();
    		return new WorldTile(getCoordFaceX(size), getCoordFaceY(size), getPlane());
    	}
    
    	public boolean withinDistance(Player tile, int distance) {
    		return super.withinDistance(tile, distance);
    	}
    
    	public boolean isIntelligentRouteFinder() {
    		return intelligentRouteFinder;
    	}
    
    	public void setIntelligentRouteFinder(boolean intelligentRouteFinder) {
    		this.intelligentRouteFinder = intelligentRouteFinder;
    	}
    }
    NPCCombat.java
    Code:
    package com.rs.game.npc.combat;
    
    import com.rs.game.Animation;
    import com.rs.game.Entity;
    import com.rs.game.ForceMovement;
    import com.rs.game.World;
    import com.rs.game.WorldTile;
    import com.rs.game.npc.NPC;
    import com.rs.game.npc.familiar.Familiar;
    import com.rs.game.npc.godwars.zaros.Nex;
    import com.rs.game.npc.pest.PestPortal;
    import com.rs.game.player.content.Combat;
    import com.rs.utils.MapAreas;
    import com.rs.utils.Utils;
    
    public final class NPCCombat {
    
    	private NPC npc;
    	private int combatDelay;
    	private Entity target;
    
    	public NPCCombat(NPC npc) {
    		this.npc = npc;
    	}
    
    	public int getCombatDelay() {
    		return combatDelay;
    	}
    
    	/*
    	 * returns if under combat
    	 */
    	public boolean process() {
    		if (combatDelay > 0)
    			combatDelay--;
    		if (target != null) {
    			if (!checkAll()) {
    				removeTarget();
    				return false;
    			}
    			if (combatDelay <= 0)
    				combatDelay = combatAttack();
    			return true;
    		}
    		return false;
    	}
    
    	/*
    	 * return combatDelay
    	 */
    	private int combatAttack() {
    		Entity target = this.target; // prevents multithread issues
    		if (target == null)
    			return 0;
    		// if hes frooze not gonna attack
    		if (npc.getFreezeDelay() >= Utils.currentTimeMillis())
    			return 0;
    		// check if close to target, if not let it just walk and dont attack
    		// this gameticket
    		NPCCombatDefinitions defs = npc.getCombatDefinitions();
    		int attackStyle = defs.getAttackStyle();
    		int maxDistance = attackStyle == NPCCombatDefinitions.MELEE || attackStyle == NPCCombatDefinitions.SPECIAL2 ? 0
    				: 7;
    		/*
    		if ((!(npc instanceof Nex)) && !npc.clipedProjectile(target, maxDistance == 0))
    			return 0;
    		*/
    		int distanceX = target.getX() - npc.getX();
    		int distanceY = target.getY() - npc.getY();
    		int size = npc.getSize();
    		/*
    		 * if(npc.hasWalkSteps()) maxDistance += 1;
    		 */
    		if (distanceX > size + maxDistance || distanceX < -1 - maxDistance || distanceY > size + maxDistance
    				|| distanceY < -1 - maxDistance) {
    			return 0;
    		}
    		addAttackedByDelay(target);
    		return CombatScriptsHandler.specialAttack(npc, target);
    	}
    
    	protected void doDefenceEmote(Entity target) {
    		/*
    		 * if (target.getNextAnimation() != null) // if has att emote already return;
    		 */
    		target.setNextAnimationNoPriority(new Animation(Combat.getDefenceEmote(target)));
    	}
    
    	public Entity getTarget() {
    		return target;
    	}
    
    	public void addAttackedByDelay(Entity target) { // prevents multithread
    													// issues
    		target.setAttackedBy(npc);
    		target.setAttackedByDelay(Utils.currentTimeMillis() + npc.getCombatDefinitions().getAttackDelay() * 600 + 600); // 8seconds
    	}
    
    	public void setTarget(Entity target) {
    		this.target = target;
    		npc.setNextFaceEntity(target);
    		if (!checkAll()) {
    			removeTarget();
    			return;
    		}
    	}
    
    	public boolean checkAll() {
    		Entity target = this.target; // prevents multithread issues
    		if (target == null) {
    			return false;
    		}
    		if (npc.isDead() || npc.hasFinished() || npc.isForceWalking() || target.isDead() || target.hasFinished() || npc.getPlane() != target.getPlane()) {
    			return false;
    		}
    		if (npc.getFreezeDelay() >= Utils.currentTimeMillis())
    			return true; // if freeze cant move ofc
    		int distanceX = npc.getX() - npc.getRespawnTile().getX();
    		int distanceY = npc.getY() - npc.getRespawnTile().getY();
    		int size = npc.getSize();
    		int maxDistance;
    		if (!npc.isNoDistanceCheck() && !npc.isCantFollowUnderCombat()) {
    			maxDistance = 32;
    			if (!(npc instanceof Familiar)) {
    
    				if (npc.getMapAreaNameHash() != -1) {
    					// if out his area
    					if (!MapAreas.isAtArea(npc.getMapAreaNameHash(), npc) || (!npc.canBeAttackFromOutOfArea()
    							&& !MapAreas.isAtArea(npc.getMapAreaNameHash(), target))) {
    						npc.forceWalkRespawnTile();
    						return false;
    					}
    				} else if (distanceX > size + maxDistance || distanceX < -1 - maxDistance
    						|| distanceY > size + maxDistance || distanceY < -1 - maxDistance) {
    					// if more than 32 distance from respawn place
    					npc.forceWalkRespawnTile();
    					return false;
    				}
    			}
    			maxDistance = 16;
    			distanceX = target.getX() - npc.getX();
    			distanceY = target.getY() - npc.getY();
    			if (distanceX > size + maxDistance || distanceX < -1 - maxDistance || distanceY > size + maxDistance || distanceY < -1 - maxDistance) {
    				return false; // if target distance higher 16
    			}
    		} else {
    			distanceX = target.getX() - npc.getX();
    			distanceY = target.getY() - npc.getY();
    		}
    		// checks for no multi area :)
    		if (npc instanceof Familiar) {
    			Familiar familiar = (Familiar) npc;
    			if (!familiar.canAttack(target))
    				return false;
    		} else {
    			if (!npc.isForceMultiAttacked()) {
    				if (!target.isAtMultiArea() || !npc.isAtMultiArea()) {
    					if (npc.getAttackedBy() != target && npc.getAttackedByDelay() > Utils.currentTimeMillis())
    						return false;
    					if (target.getAttackedBy() != npc && target.getAttackedByDelay() > Utils.currentTimeMillis())
    						return false;
    				}
    			}
    		}
    		if (!npc.isCantFollowUnderCombat()) {
    			// if is under
    			int targetSize = target.getSize();
    			/*
    			 * if (distanceX < size && distanceX > -targetSize && distanceY < size &&
    			 * distanceY > -targetSize && !target.hasWalkSteps()) {
    			 */
    			if (!target.hasWalkSteps()
    					&& Utils.colides(npc.getX(), npc.getY(), size, target.getX(), target.getY(), targetSize)) {
    				npc.resetWalkSteps();
    				if (!npc.addWalkSteps(target.getX() + targetSize, npc.getY())) {
    					npc.resetWalkSteps();
    					if (!npc.addWalkSteps(target.getX() - size, npc.getY())) {
    						npc.resetWalkSteps();
    						if (!npc.addWalkSteps(npc.getX(), target.getY() + targetSize)) {
    							npc.resetWalkSteps();
    							if (!npc.addWalkSteps(npc.getX(), target.getY() - size)) {
    								return true;
    							}
    						}
    					}
    				}
    				return true;
    			}
    			if (npc.getCombatDefinitions().getAttackStyle() == NPCCombatDefinitions.MELEE && targetSize == 1
    					&& size == 1 && Math.abs(npc.getX() - target.getX()) == 1
    					&& Math.abs(npc.getY() - target.getY()) == 1 && !target.hasWalkSteps()) {
    				if (!npc.addWalkSteps(target.getX(), npc.getY(), 1))
    					npc.addWalkSteps(npc.getX(), target.getY(), 1);
    				return true;
    			}
    
    			int attackStyle = npc.getCombatDefinitions().getAttackStyle();
    			if (npc instanceof Nex) {
    				Nex nex = (Nex) npc;
    				maxDistance = nex.isForceFollowClose() ? 0 : 7;
    				if (!nex.isFlying() && (!npc.clipedProjectile(target, maxDistance == 0 && !forceCheckClipAsRange(target))) || !Utils.isOnRange(npc.getX(), npc.getY(), size, target.getX(), target.getY(), targetSize,
    								maxDistance)) {
    					npc.resetWalkSteps();
    					if (!Utils.isOnRange(npc.getX(), npc.getY(), size, target.getX(), target.getY(), targetSize, 10)) {
    						int[][] dirs = Utils.getCoordOffsetsNear(size);
    						for (int dir = 0; dir < dirs[0].length; dir++) {
    							final WorldTile tile = new WorldTile(new WorldTile(target.getX() + dirs[0][dir],
    									target.getY() + dirs[1][dir], target.getPlane()));
    							if (World.isTileFree(tile.getPlane(), tile.getX(), tile.getY(), size)) { // if
    								// found
    								// done
    								npc.setNextForceMovement(new ForceMovement(new WorldTile(npc), 0, tile, 1,
    										Utils.getMoveDirection(tile.getX() - npc.getX(), tile.getY() - npc.getY())));
    								npc.setNextAnimation(new Animation(6985));
    								npc.setNextWorldTile(tile);
    								nex.setFlying(false);
    								return true;
    							}
    						}
    					} else
    						npc.calcFollow(target, 2, true, npc.isIntelligentRouteFinder());
    					return true;
    				} else
    					// if doesnt need to move more stop moving
    					npc.resetWalkSteps();
    			} else {
    				// MAGE_FOLLOW and RANGE_FOLLOW follow close but can attack far
    				// unlike melee
    				maxDistance = npc.isForceFollowClose() ? 0
    						: (attackStyle == NPCCombatDefinitions.MELEE || attackStyle == NPCCombatDefinitions.SPECIAL2
    								|| attackStyle == NPCCombatDefinitions.SPECIAL) ? 0 : 7;
    				npc.resetWalkSteps();
    				// is far from target, moves to it till can attack
    				if ((!npc.clipedProjectile(target, maxDistance == 0 && !forceCheckClipAsRange(target)))
    						|| !Utils.isOnRange(npc.getX(), npc.getY(), size, target.getX(), target.getY(), targetSize,
    								maxDistance)) {
    					if (!npc.calcFollow(target, npc.getRun() ? 2 : 1, true, npc.isIntelligentRouteFinder())
    							&& combatDelay < 3 && attackStyle == NPCCombatDefinitions.MELEE)
    						combatDelay = 3;
    					return true;
    				}
    				// if under target, moves
    
    			}
    		}
    		return true;
    	}
    
    	private boolean forceCheckClipAsRange(Entity target) {
    		return target instanceof PestPortal;
    	}
    
    	public void addCombatDelay(int delay) {
    		combatDelay += delay;
    	}
    
    	public void setCombatDelay(int delay) {
    		combatDelay = delay;
    	}
    
    	public boolean underCombat() {
    		return target != null;
    	}
    
    	public void removeTarget() {
    		this.target = null;
    		npc.setNextFaceEntity(null);
    	}
    
    	public void reset() {
    		combatDelay = 0;
    		target = null;
    	}
    
    }
    While I'm dumping code, here is the test instance controller I am using
    Code:
    package com.rs.game.player.controlers;
    
    import java.util.concurrent.TimeUnit;
    
    import com.rs.Settings;
    import com.rs.cores.CoresManager;
    import com.rs.game.Entity;
    import com.rs.game.Region;
    import com.rs.game.RegionBuilder;
    import com.rs.game.World;
    import com.rs.game.WorldObject;
    import com.rs.game.WorldTile;
    import com.rs.game.minigames.rfd.RfdNPC;
    import com.rs.game.npc.NPC;
    import com.rs.game.npc.combat.InstanceNPC;
    import com.rs.game.player.Player;
    import com.rs.game.tasks.WorldTask;
    import com.rs.game.tasks.WorldTasksManager;
    
    public class Test extends Controler {
    
    	/*
    	 * Author Tetrix
    	 */
    
    	private int[] boundChuncks;
    	public boolean spawned;
    
    
    	@Override
    	public void start() {
    		loadBandos();
    	}
    
    
    	/*
    	 * return false so wont remove script
    	 */
    	@Override
    	public boolean login() {
    		exitBandos(0);
    		return true;
    	}
    	
    	public WorldTile getWorldTile(int mapX, int mapY) {
    		return new WorldTile(boundChuncks[0]*8 + mapX, boundChuncks[1]*8 + mapY, 2);
    	}
    	
    	@Override
    	public boolean processObjectClick1(WorldObject object) {
    		if(object.getId() == 9357) {
    			exitBandos(0);
    			return false;
    		}
    		return true;
    	}
    
    	public void loadBandos() {
    		CoresManager.slowExecutor.execute(new Runnable() {
    			@Override
    			public void run() {
    				boundChuncks = RegionBuilder.findEmptyChunkBound(8, 8); 
    				RegionBuilder.copyAllPlanesMap(402, 402, boundChuncks[0], boundChuncks[1], 8);
    				
    				player.setNextWorldTile(getWorldTile(24, 21));
    				WorldTasksManager.schedule(new WorldTask()  {
    					@Override
    					public void run() {
    						player.setForceMultiArea(true);
    						player.sm("You have entered your private room");
    					}
    				}, 0);
    
    				new InstanceNPC(6260, new WorldTile(94, 92, 2));
    				new InstanceNPC(6263, new WorldTile(97, 88, 2));
    				new InstanceNPC(6265, new WorldTile(95, 84, 2));
    				new InstanceNPC(6261, new WorldTile(91, 85, 2));
    			}
    		});
    	}
    	public void exitBandos(int type) {
    		if (type == 0) {
    			player.setForceMultiArea(false);
    			player.getPackets().closeInterface(player.getInterfaceManager().hasResizableScreen() ? 11 : 0);
    			removeControler();
    		} else {
    			player.setForceMultiArea(false);
    			player.setNextWorldTile(new WorldTile (Settings.RESPAWN_PLAYER_LOCATION));
    			player.getPackets().closeInterface(player.getInterfaceManager().hasResizableScreen() ? 11 : 0);
    			removeControler();
    		}
    		/*
    		 * 1200 delay because of leaving
    		 */
    		CoresManager.slowExecutor.schedule(new Runnable() {
    			@Override
    			public void run() {
    				RegionBuilder.destroyMap(boundChuncks[0], boundChuncks[1], 8, 8);
    			}
    		}, 1200, TimeUnit.MILLISECONDS);
    	}
    
    	@Override
    	public void magicTeleported(int type) {
    		exitBandos(0);
    	}	
    	@Override
    	public boolean processMagicTeleport(WorldTile toTile) {
    		exitBandos(0);
    		return true;
    	}
    	
    	@Override
    	public boolean processItemTeleport(WorldTile toTile) {
    		exitBandos(0);
    		return true;
    	}
    	
    	@Override
    	public boolean processObjectTeleport(WorldTile toTile) {
    		exitBandos(0);
    		return true;
    	}
    	@Override
    	public boolean logout() {
    		exitBandos(1);
    		return false;
    	}
    	
    	@Override
    	public boolean canAttack(Entity target) {
    		return true;
    	}
    	
    	@Override
    	public boolean keepCombating(Entity target) {
    		return true;
    	}
    	
    	@Override
    	public boolean canPlayerOption1(Player target) {
    		return true;
    	}
    	
    	@Override
    	public boolean canHit(Entity entity) {
    		return true;
    	}
    	
    	@Override
    	public boolean processNPCClick1(NPC npc) {
    		return true;
    	}
    	
    }
    Reply With Quote  
     

  7. #7  
    Contributor

    clem585's Avatar
    Join Date
    Sep 2013
    Posts
    3,756
    Thanks given
    703
    Thanks received
    691
    Discord
    View profile
    Rep Power
    518
    Make sure none of these checks are returning false;

    Code:
    			if (!(npc instanceof Familiar)) {
    
    				if (npc.getMapAreaNameHash() != -1) {
    					// if out his area
    					if (!MapAreas.isAtArea(npc.getMapAreaNameHash(), npc) || (!npc.canBeAttackFromOutOfArea()
    							&& !MapAreas.isAtArea(npc.getMapAreaNameHash(), target))) {
    						npc.forceWalkRespawnTile();
    						return false;
    					}
    				} else if (distanceX > size + maxDistance || distanceX < -1 - maxDistance
    						|| distanceY > size + maxDistance || distanceY < -1 - maxDistance) {
    					// if more than 32 distance from respawn place
    					npc.forceWalkRespawnTile();
    					return false;
    				}
    			}
    			maxDistance = 16;
    			distanceX = target.getX() - npc.getX();
    			distanceY = target.getY() - npc.getY();
    			if (distanceX > size + maxDistance || distanceX < -1 - maxDistance || distanceY > size + maxDistance || distanceY < -1 - maxDistance) {
    				return false; // if target distance higher 16
    			}
    This is the block for walking the NPC to the target;

    Code:
    if (!npc.isCantFollowUnderCombat()) {
    			// if is under
    			int targetSize = target.getSize();
    			/*
    			 * if (distanceX < size && distanceX > -targetSize && distanceY < size &&
    			 * distanceY > -targetSize && !target.hasWalkSteps()) {
    			 */
    			if (!target.hasWalkSteps()
    					&& Utils.colides(npc.getX(), npc.getY(), size, target.getX(), target.getY(), targetSize)) {
    				npc.resetWalkSteps();
    				if (!npc.addWalkSteps(target.getX() + targetSize, npc.getY())) {
    					npc.resetWalkSteps();
    					if (!npc.addWalkSteps(target.getX() - size, npc.getY())) {
    						npc.resetWalkSteps();
    						if (!npc.addWalkSteps(npc.getX(), target.getY() + targetSize)) {
    							npc.resetWalkSteps();
    							if (!npc.addWalkSteps(npc.getX(), target.getY() - size)) {
    								return true;
    							}
    						}
    					}
    				}
    				return true;
    			}
    			if (npc.getCombatDefinitions().getAttackStyle() == NPCCombatDefinitions.MELEE && targetSize == 1
    					&& size == 1 && Math.abs(npc.getX() - target.getX()) == 1
    					&& Math.abs(npc.getY() - target.getY()) == 1 && !target.hasWalkSteps()) {
    				if (!npc.addWalkSteps(target.getX(), npc.getY(), 1))
    					npc.addWalkSteps(npc.getX(), target.getY(), 1);
    				return true;
    			}
    
    			int attackStyle = npc.getCombatDefinitions().getAttackStyle();
    			if (npc instanceof Nex) {
    				Nex nex = (Nex) npc;
    				maxDistance = nex.isForceFollowClose() ? 0 : 7;
    				if (!nex.isFlying() && (!npc.clipedProjectile(target, maxDistance == 0 && !forceCheckClipAsRange(target))) || !Utils.isOnRange(npc.getX(), npc.getY(), size, target.getX(), target.getY(), targetSize,
    								maxDistance)) {
    					npc.resetWalkSteps();
    					if (!Utils.isOnRange(npc.getX(), npc.getY(), size, target.getX(), target.getY(), targetSize, 10)) {
    						int[][] dirs = Utils.getCoordOffsetsNear(size);
    						for (int dir = 0; dir < dirs[0].length; dir++) {
    							final WorldTile tile = new WorldTile(new WorldTile(target.getX() + dirs[0][dir],
    									target.getY() + dirs[1][dir], target.getPlane()));
    							if (World.isTileFree(tile.getPlane(), tile.getX(), tile.getY(), size)) { // if
    								// found
    								// done
    								npc.setNextForceMovement(new ForceMovement(new WorldTile(npc), 0, tile, 1,
    										Utils.getMoveDirection(tile.getX() - npc.getX(), tile.getY() - npc.getY())));
    								npc.setNextAnimation(new Animation(6985));
    								npc.setNextWorldTile(tile);
    								nex.setFlying(false);
    								return true;
    							}
    						}
    					} else
    						npc.calcFollow(target, 2, true, npc.isIntelligentRouteFinder());
    					return true;
    				} else
    					// if doesnt need to move more stop moving
    					npc.resetWalkSteps();
    			} else {
    				// MAGE_FOLLOW and RANGE_FOLLOW follow close but can attack far
    				// unlike melee
    				maxDistance = npc.isForceFollowClose() ? 0
    						: (attackStyle == NPCCombatDefinitions.MELEE || attackStyle == NPCCombatDefinitions.SPECIAL2
    								|| attackStyle == NPCCombatDefinitions.SPECIAL) ? 0 : 7;
    				npc.resetWalkSteps();
    				// is far from target, moves to it till can attack
    				if ((!npc.clipedProjectile(target, maxDistance == 0 && !forceCheckClipAsRange(target)))
    						|| !Utils.isOnRange(npc.getX(), npc.getY(), size, target.getX(), target.getY(), targetSize,
    								maxDistance)) {
    					if (!npc.calcFollow(target, npc.getRun() ? 2 : 1, true, npc.isIntelligentRouteFinder())
    							&& combatDelay < 3 && attackStyle == NPCCombatDefinitions.MELEE)
    						combatDelay = 3;
    					return true;
    				}
    				// if under target, moves
    
    			}
    		}
    The processing logic error is in there somewhere
    Project thread
    Reply With Quote  
     

  8. #8  
    Aldor Manager


    Join Date
    Mar 2014
    Age
    26
    Posts
    1,172
    Thanks given
    178
    Thanks received
    246
    Rep Power
    648
    is has to do with this

    if (npc.getMapAreaNameHash() != -1) {
    // if out his area
    if (!MapAreas.isAtArea(npc.getMapAreaNameHash(), npc) || (!npc.canBeAttackFromOutOfArea()
    && !MapAreas.isAtArea(npc.getMapAreaNameHash(), target))) {
    npc.forceWalkRespawnTile();
    return false;
    }


    look for this:

    super(id, tile, -1, true, true);
    and change it to this

    super(id, tile, -1, true, false);

    that should fix it.

    Respect goes to everyone as he deserves.
    Reply With Quote  
     

  9. #9  
    Donator
    The Stoned's Avatar
    Join Date
    Jan 2013
    Posts
    638
    Thanks given
    62
    Thanks received
    80
    Rep Power
    62
    Quote Originally Posted by _Jamal View Post
    is has to do with this

    if (npc.getMapAreaNameHash() != -1) {
    // if out his area
    if (!MapAreas.isAtArea(npc.getMapAreaNameHash(), npc) || (!npc.canBeAttackFromOutOfArea()
    && !MapAreas.isAtArea(npc.getMapAreaNameHash(), target))) {
    npc.forceWalkRespawnTile();
    return false;
    }


    look for this:

    super(id, tile, -1, true, true);
    and change it to this

    super(id, tile, -1, true, false);

    that should fix it.
    Unfortunately, it did not. I took a day break on this one to work on construction instead.
    Through further development on my project, I fear there may be a larger issue with World, Region, or MapArea (more issues in construction w/ object spawns).

    I am continuing to look through the logic for isCantFollowUnderCombat() like clem mentioned.
    Reply With Quote  
     

  10. #10  
    Mug Club


    Join Date
    Jul 2011
    Age
    27
    Posts
    1,931
    Thanks given
    528
    Thanks received
    935
    Discord
    View profile
    Rep Power
    384
    Matrix projectile clipping in dynamic regions is very far off especially for rotated regions which is why people have issues copy pasting dungeoneering into it without having npcs attack you through the walls. It could be related to that. The biggest red flag leading me in that direction is the snippet you posted just ignoring the projectile clipping to enable interactions.
    Reply With Quote  
     

Page 1 of 2 12 LastLast

Thread Information
Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)


User Tag List

Similar Threads

  1. Replies: 2
    Last Post: 03-25-2014, 06:18 PM
  2. Replies: 18
    Last Post: 12-06-2013, 05:40 AM
  3. Replies: 0
    Last Post: 08-25-2013, 01:59 AM
  4. Replies: 1
    Last Post: 06-22-2009, 07:23 AM
  5. Unable to Be Online:[
    By Galkon in forum Chat
    Replies: 6
    Last Post: 12-08-2008, 11:49 AM
Posting Permissions
  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •