gt:         VisibleObject currentTarget = getTarget();
context: /**
   * This file is part of Aion-Lightning <aion-lightning.org>.
   *
   *  Aion-Lightning is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  Aion-Lightning is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details. *
   *
   *  You should have received a copy of the GNU General Public License
   *  along with Aion-Lightning.
   *  If not, see <http://www.gnu.org/licenses/>.
   *
   *
   * Credits goes to all Open Source Core Developer Groups listed below
   * Please do not change here something, ragarding the developer credits, except the "developed by XXXX".
   * Even if you edit a lot of files in this source, you still have no rights to call it as "your Core".
   * Everybody knows that this Emulator Core was developed by Aion Lightning 
   * @-Aion-Unique-
   * @-Aion-Lightning
   * @Aion-Engine
   * @Aion-Extreme
   * @Aion-NextGen
   * @Aion-Core Dev.
   */
  package ai.instance.IdgelDome;
  
  import java.awt.Point;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.concurrent.Future;
  import java.util.concurrent.atomic.AtomicBoolean;
  
  import ai.AggressiveNpcAI2;
  
  import com.aionemu.commons.network.util.ThreadPoolManager;
  import com.aionemu.commons.utils.Rnd;
  import com.aionemu.gameserver.ai2.AI2Actions;
  import com.aionemu.gameserver.ai2.AIName;
  import com.aionemu.gameserver.ai2.AIState;
  import com.aionemu.gameserver.ai2.AISubState;
  import com.aionemu.gameserver.ai2.AttackIntention;
  import com.aionemu.gameserver.ai2.event.AIEventType;
  import com.aionemu.gameserver.ai2.handler.TargetEventHandler;
  import com.aionemu.gameserver.ai2.manager.EmoteManager;
  import com.aionemu.gameserver.model.Race;
  import com.aionemu.gameserver.model.actions.PlayerActions;
  import com.aionemu.gameserver.model.gameobjects.Creature;
  import com.aionemu.gameserver.model.gameobjects.Npc;
  import com.aionemu.gameserver.model.gameobjects.VisibleObject;
  import com.aionemu.gameserver.model.gameobjects.player.Player;
  import com.aionemu.gameserver.network.aion.serverpackets.SM_ATTACK_STATUS.TYPE;
  import com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE;
  import com.aionemu.gameserver.skillengine.SkillEngine;
  import com.aionemu.gameserver.utils.MathUtil;
  import com.aionemu.gameserver.utils.PacketSendUtility;
  import com.aionemu.gameserver.world.WorldMapInstance;
  import com.aionemu.gameserver.world.WorldPosition;
  import com.aionemu.gameserver.world.knownlist.Visitor;
  
  
  /**
   * @author GiGatR00n v4.7.5.x
   */
  @AIName("destroyer_kunax") //234190
  public class DestroyerKunaxAI2 extends AggressiveNpcAI2 {
  
      private Future<?> BossTasks;
      private int attackCounter = 0;
  	private AtomicBoolean isBossAggro = new AtomicBoolean(true);
  	private boolean isBossOutsideCircle = false;
  	private int NextBossRoar = (100 / 10) * 9;
  	private boolean canThink = true;
  
  	@Override
  	public boolean canThink() {
  		return canThink;
  	}
  	
      @Override
      protected void handleTargetGiveup() {
          TargetEventHandler.onTargetGiveup(this);
          
          // The Destroyer Kunax will stop focusing its target and return to its original position.
          sendMsgByRace(1402578, Race.PC_ALL, 0);
      }	
  	
      @Override
      protected void handleDeactivate() {
      }	
  	
      @Override
      protected void handleFinishAttack() {
      	//super.handleFinishAttack(); //It causes the Boss' HP Resets to full if there are not any attackers near the boss
      } 
      
      @Override
      protected void handleSpawned() {
          super.handleSpawned();
          makeBossStronger();
          BUFF_IdeScale(); /* Added Ide Scale BUFF to the "Destroyer Kunax" */
          checkBossLocation();
      }
  
      @Override
      protected void handleDespawned() {
      	cancelBossTask();
          super.handleDespawned();
      } 
      
      @Override
      protected void handleBackHome() {
      	isBossOutsideCircle = false;
      	canThink = true;
      	super.handleBackHome();
      }       
      
      @Override
      protected void handleMoveArrived() {
      	isBossOutsideCircle = false;
      	canThink = true;
      	super.handleMoveArrived();
      }
      
  	@Override
  	protected void handleAttack(Creature creature) {
  		
  		super.handleAttack(creature);
  		if (isBossAggro.compareAndSet(true, false)) {
  			callForHelp(10);
  		}
  		checkPercentage(getLifeStats().getHpPercentage());
  	}
  	
      @Override
      protected void handleDied() {
      	cancelBossTask();
      	/* Elite NPCs */
          deleteSummons(234751);//Sheban Elite Stalwart.
          deleteSummons(234752);//Sheban Elite Sniper.
          deleteSummons(234753);//Sheban Elite Marauder.
          deleteSummons(234754);//Sheban Elite Medic.
          /* Normal NPCs */
          deleteSummons(234186);//Sheban Intelligence Unit Ridgeblade
          deleteSummons(234187);//Sheban Intelligence Unit Hunter
          deleteSummons(234188);//Sheban Intelligent Unit Mongrel
          deleteSummons(234189);//Sheban Intelligence Unit Stitch
          super.handleDied();
          AI2Actions.deleteOwner(this);
      }
      
      private void makeBossStronger() {
          getOwner().getLifeStats().increaseHp(TYPE.HP, 500000);
          getOwner().getObjectTemplate().setAggroRange(20);
          getOwner().getObjectTemplate().setAttackRange(5);
      }
      
  //    private int getSkillAccordingToTarget() {
  //    	
  //    	double distance = MathUtil.getDistance(getOwner(), getTarget());
  //    	
  //    	
  //    	
  //    	
  //    	
  //    }
      
      private boolean canAttack() {
      	return !(getOwner().isCasting() || isAlreadyDead() || isBossOutsideCircle || getOwner().getTarget() == null || isInSubState(AISubState.CAST) || attackCounter > 20);
      }
      
  	private boolean chooseBossSkill() 
  	{
  		if (!canAttack()) {
  			return false;
  		}
  //    	if (getOwner().isCasting() || isAlreadyDead() || isBossOutsideCircle || getOwner().getTarget() == null || isInSubState(AISubState.CAST) || attackCounter > 20) {
  //    		return false;
  //    	}
  		
      	/* Choose Attack Skills */
      	int rand = Rnd.get(1, 29);
      	/* Choose Support Skills */
      	if (getLifeStats().getHpPercentage() <= NextBossRoar) {
      		rand = Rnd.get(30, 31);
      		NextBossRoar = getLifeStats().getHpPercentage() - (100 / 10);
      		NextBossRoar = (NextBossRoar > 0) ? NextBossRoar : 0;
      	}
      	
  		switch (rand) 
  		{
  			case 1:
  			case 2:
  			case 3:
  			case 4:
  			case 5:
  				AggressiveShot();//37m
  				break;
  			case 6:
  			case 7:
  			case 8:
  				SlaughteringCleave();//26m
  				break;
  			case 9:
  			case 10:
  			case 11:
  				Onslaught();//26m
  				break;
  			case 12:
  			case 13:
  				AetherPrison();//26m
  				break;
  			case 14:
  			case 15:
  			case 16:
  				CleavingMassacre();//26m
  				break;
  			case 17:
  			case 18:
  				AerialConfinement();//20m
  				break;
  			case 19:
  			case 20:
  			case 21:
  			case 22:
  			case 23:
  			case 24:
  			case 25:
  				BloodyCrash();//5m
  				break;
  			case 26:
  			case 27:
  			case 28:
  			case 29:
  				ButcherSweep();//5m
  				break;
  			case 30:
  			case 31:
  				SpawnKunaxWrathBomb();//2m
  				FierceRoar();//20m
  				break;				
  		}
  		
  		// the skill was selected successfully
  		return true;
  	}
  	/*************************************
  	 * 
  	 * Destroyer Kunax Skill's AI
  	 * 
  	 */
      private void BUFF_IdeScale() {
      	// BUFF = Ide Scale (21744) = IDLDF5_Fortress_Re_MainBuff_PD
      	applyEffect(21744, getOwner());
      }
      
      private void AggressiveShot() {
      	// SKILL = AggressiveShot (21651) = IDLDF5_Fortress_Re_NorSatkLong_Nr
      	//useSkill(21651, getOwner().getTarget());
          skillId = 21651;
          skillLevel = 65;
      }
      
      private void SlaughteringCleave() {
      	// SKILL = SlaughteringCleave (21551) = IDLDF5_Fortress_Re_WingBlade_TA
      	//useSkill(21551, getOwner().getTarget());
          skillId = 21551;
          skillLevel = 65;
      }
      
      private void Onslaught() {
      	// SKILL = Onslaught (21552) = IDLDF5_Fortress_Re_SatkLong_Strong
      	//useSkill(21552, getOwner().getTarget());
          skillId = 21552;
          skillLevel = 65;
      }
      
      private void AetherPrison() {
      	// SKILL = AetherPrison (21558) = STR_IDLDF5_Fortress_Re_ParaShield_TA
      	//useSkill(21558, getOwner().getTarget());
          skillId = 21558;
          skillLevel = 65;
      }
      
      private void CleavingMassacre() {
      	// SKILL = CleavingMassacre (21553) = IDLDF5_Fortress_Re_WingBlade_TA_Strong
      	//useSkill(21553, getOwner().getTarget());
          skillId = 21553;
          skillLevel = 65;
      }
      
      private void AerialConfinement() {
      	// SKILL = AerialConfinement (21555) = IDLDF5_Fortress_Re_AreaOpenAerial_forACT
      	//useSkill(21555, getOwner());
          skillId = 21555;
          skillLevel = 65;
          AI2Actions.targetSelf(this);    	
      }
      
      private void BloodyCrash() {
      	// SKILL = BloodyCrash (21556) = IDLDF5_Fortress_Re_CloseAerialTA_Nr
      	//useSkill(21556, getOwner().getTarget());
          skillId = 21556;
          skillLevel = 65;
      }
  
      private void FierceRoar() {
      	// SKILL = FierceRoar (21561) = IDLDF5_Fortress_Re_Buff_Notfly
      	//useSkill(21561, getOwner());
          skillId = 21561;
          skillLevel = 65;
          AI2Actions.targetSelf(this);
      }    
      
      private void ButcherSweep() {
      	// SKILL ButcherSweep (21554) = IDLDF5_Fortress_Re_SatkSA_Nr
      	//useSkill(21554, getOwner().getTarget());
          skillId = 21554;
          skillLevel = 65;
      }
      
      private void AetherCrystalArmor() {
      	// SKILL AetherCrystalArmor (21560) = IDLDF5_Fortress_Re_Bonus_Shield
      	applyEffect(21560, getOwner());
      }
  	/**
  	 * 
  	 * Destroyer Kunax Skill's AI
  	 * 
  	 ***********************************/
      
      private void useSkill(int skillId, VisibleObject target) {
          SkillEngine.getInstance().getSkill(getOwner(), skillId, 65, target).useSkill();
      }
      
      private void applyEffect(int skillId, Creature target) {
          SkillEngine.getInstance().applyEffectDirectly(skillId, getOwner(), target, 0);
      	//SkillEngine.getInstance().getSkill(getOwner(), skillId, 65, target).useSkill();
      }
      
      private void deleteSummons(int npcId) {
          if (getPosition().getWorldMapInstance().getNpcs(npcId) != null) {
              List<Npc> npcs = getPosition().getWorldMapInstance().getNpcs(npcId);
              for (Npc npc : npcs) {
                  npc.getController().onDelete();
              }
          }
      }    
      
      private void castSkillTask(final int skillId, int time, final VisibleObject firstTarget) {
      	ThreadPoolManager.getInstance().schedule(new Runnable() {
              @Override
              public void run() {
                  if (!isAlreadyDead() && !getOwner().isCasting() && !isInSubState(AISubState.CAST)) {      	
                      WorldPosition p = getPosition();
                      if (p != null) {
                          WorldMapInstance instance = p.getWorldMapInstance();
                          if (instance != null) {
                              SkillEngine.getInstance().getSkill(getOwner(), skillId, 65, firstTarget).useNoAnimationSkill();
                          }
                      }
                  }
              }
          }, time);
      }
      
      protected void sendMsgByRace(final int msg, final Race race, int time) 
      {
      	ThreadPoolManager.getInstance().schedule(new Runnable() {
              @Override
              public void run() {
              	getPosition().getWorldMapInstance().doOnAllPlayers(new Visitor<Player>() {
                      @Override
                      public void visit(Player player) {
                          if (player.getRace().equals(race) || race.equals(Race.PC_ALL)) {
                              PacketSendUtility.sendPacket(player, new SM_SYSTEM_MESSAGE(msg));
                          }
                      }
                  });
              }
          }, time);
      }
      
      private void SpawnKunaxWrathBomb() {
      	
      	// Finds a random target within Destroyer Kunax's Circle
      	Player player = getRndTargetInBossCircle(16.0f);
      	if (player == null) {
      		
      		// If any player find, check the target
      		if (getOwner().getTarget() instanceof Player) {
      			player = (Player) getOwner().getTarget();
      		} else {
      			return;
  			}
      	}
      	
      	// Get Target Coordinates
      	float x = player.getX();
      	float y = player.getY();
      	float z = player.getZ();
      	
      	// Spawn the Blind/Silence Bomb
      	spawn(702320, x, y, z, player.getHeading());
      }
      
      private void cancelBossTask() {
          if (BossTasks != null && !BossTasks.isDone()) {
          	BossTasks.cancel(true);
          }
      }
      
      private void checkBossLocation() {
      	BossTasks = ThreadPoolManager.getInstance().scheduleAtFixedRate(new Runnable() {
  			@Override
  			public void run() {
  				if (!isBossOutsideCircle) {
  					if (!isAlreadyDead() && !getOwner().isCasting()) {
  						double distance = getOwner().getDistanceToSpawnLocation();
  				    	if (distance >= 23.01) {
  				    		
  				    		isBossOutsideCircle = true;	    		
  				    		Player player = getRndTargetInBossCircle(23.01f);
  				    		getOwner().setTarget(player);
  
  				    		if (player == null) {
  				    			canThink = false;
  				    			getOwner().getMoveController().abortMove();
  					            EmoteManager.emoteStopAttacking(getOwner());
  					            setStateIfNot(AIState.WALKING);
  					            setSubStateIfNot(AISubState.NONE);
  					            getOwner().setTarget(null);
  					            
  					            // The Destroyer Kunax will stop focusing its target and return to its original position.
  					            sendMsgByRace(1402578, Race.PC_ALL, 0);
  					            
  //				    			Point randPoint = MathUtil.get2DPointOnCircle(new Point((int) 264.4382f, (int)258.58527f), new Point((int) getOwner().getX(), (int)getOwner().getY()), 16);
  				    			Point randPoint = MathUtil.get2DPointInsideCircle(264.4382f, 258.58527f, 14);
  				    			getOwner().getMoveController().moveToPoint(randPoint.x, randPoint.y, 85.81963f);
  				    		}
  				    	}
  	    			}
  				}
  			}
      	}, 100, 100);
      }
      
      /**
       * Returns a Random Target that Available in <b>Destroyer Kunax's Circle</b>
       *
       * @return (Player)
       */
      private Player getRndTargetInBossCircle(float CircleRadius) {
          List<Player> players = new ArrayList<Player>();
          for (Player player : getKnownList().getKnownPlayers().values()) {
              if (!PlayerActions.isAlreadyDead(player) && isInBossCircle(player, CircleRadius)) {
                  players.add(player);
              }
          }
          if (players.isEmpty()) {
              return null;
          }
          return players.get(Rnd.get(players.size()));
      }
      
      private boolean isInBossCircle(Creature creature, float CircleRadius) {
      	if (MathUtil.isInSphere(creature, 264.4382f, 258.58527f, 85.81963f, CircleRadius)) {
      		return true;
      	}
          return false;
      }
  	
      private synchronized void checkPercentage(int hpPercentage) {
      	attackCounter += 1;
      	if (!getOwner().isCasting() && !isAlreadyDead() && !isBossOutsideCircle && !isInSubState(AISubState.CAST) && attackCounter > 20) {
      		attackCounter = 0;
              if (hpPercentage <= 25) {
              	AetherCrystalArmor();
              } else if (hpPercentage <= 50) {
              	AetherCrystalArmor();
              } else if (hpPercentage <= 85) {
              	AetherCrystalArmor();
              }
      	}
      }
      
      @Override
      public AttackIntention chooseAttackIntention() {
          
  