/*
 * Copyright (C) 2004-2013 L2J DataPack
 * 
 * This file is part of L2J DataPack.
 * 
 * L2J DataPack 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.
 * 
 * L2J DataPack 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 this program. If not, see <http://www.gnu.org/licenses/>.
 */
package ai.individual;

import static com.l2jserver.gameserver.ai.CtrlIntention.*;
import static com.l2jserver.gameserver.datatables.SkillTable.*;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;

import ai.npc.AbstractNpcAI;

import com.l2jserver.Config;
import com.l2jserver.gameserver.GeoData;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.enums.MountType;
import com.l2jserver.gameserver.instancemanager.GrandBossManager;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.Location;
import com.l2jserver.gameserver.model.StatsSet;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2DecoyInstance;
import com.l2jserver.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.effects.L2Effect;
import com.l2jserver.gameserver.model.skills.L2Skill;
import com.l2jserver.gameserver.model.zone.type.L2BossZone;
import com.l2jserver.gameserver.network.serverpackets.Earthquake;
import com.l2jserver.gameserver.network.serverpackets.MoveToPawn;
import com.l2jserver.gameserver.network.serverpackets.NpcSay;
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
import com.l2jserver.gameserver.network.serverpackets.SocialAction;
import com.l2jserver.gameserver.util.Broadcast;
import com.l2jserver.gameserver.util.Util;

/**
 * Baium's AI.
 * @author Fulminus
 */
public class Baium extends AbstractNpcAI
{
	// config
	private static final boolean FWB_MOVEATRANDOM = true;
	private static final boolean FIX_AI_SYNCHRONIZED = true;	//[JOJO] true - ReentrantLock, false - synchronized this
	private static final boolean FIX_AI_CAST_SLEEP = true;	//[JOJO] true - schedule, false - sleep
	
	// NPCs
	private static final int STONE_BAIUM = 29025;
	private static final int ANGELIC_VORTEX = 31862;
	private static final int LIVE_BAIUM = 29020;
	private static final int ARCHANGEL = 29021;
	private static final int TELEPORT_CUBIC = 31842;
	// Item
	private static final int BLOODED_FABRIC = 4295;
	// Baium status tracking
	private static final byte ASLEEP = 0; // baium is in the stone version, waiting to be woken up. Entry is unlocked
	private static final byte AWAKE = 1; // baium is awake and fighting. Entry is locked.
	private static final byte DEAD = 2; // baium has been killed and has not yet spawned. Entry is locked
	// Fixed archangel spawn location
	private static final Location[] ANGEL_LOCATION =
	{
		new Location(114239, 17168, 10080, 63544),
		new Location(115780, 15564, 10080, 13620),
		new Location(114880, 16236, 10080, 5400),
		new Location(115168, 17200, 10080, 0),
		new Location(115792, 16608, 10080, 0)
	};
	private static final Location[] TELEPORT_CUBIC_LOCATION = new Location[]
	{
		new Location(108784, 16000, -4928),
		new Location(113824, 10448, -5164),
		new Location(115488, 22096, -5168),
	};
	private static final Location BAIUM_DESPAWN = new Location(116033, 17447, 10104);
	private static final Location BAIUM_ENTER = new Location(113100, 14500, 10077);
	// Skills
	private static final int GENERAL_ATTACK = getSkillHashCode(4127, 1);
	private static final int WIND_OF_FORCE = getSkillHashCode(4128, 1);
	private static final int EARTHQUAKE = getSkillHashCode(4129, 1);
	private static final int STRIKING_OF_THUNDERBOLT = getSkillHashCode(4130, 1);
	private static final int STUN = getSkillHashCode(4131, 1);
	private static final int BAIUM_HEAL = getSkillHashCode(4135, 1);
	private static final int HINDER_STRIDER = getSkillHashCode(4258, 1);
	// private static final int PRESENT_FROM_BAIUM = getSkillHashCode(4136, 1);
	
	private long _LastAttackVsBaiumTime = 0;
	protected final List<L2Npc> _Minions = new ArrayList<>(5);
	protected L2BossZone _Zone;
	private ReentrantLock _AILock;
	
	private L2Character _target;
	private int _skillHashCode;
	
	private Baium(String name, String descr)
	{
		super(name, descr);
		registerMobs(LIVE_BAIUM);
		// Quest NPC starter initialization
		addStartNpc(STONE_BAIUM, ANGELIC_VORTEX, TELEPORT_CUBIC);
		addTalkId(STONE_BAIUM, ANGELIC_VORTEX, TELEPORT_CUBIC);
		
		_Zone = GrandBossManager.getInstance().getZone(113100, 14500, 10077);
		StatsSet info = GrandBossManager.getInstance().getStatsSet(LIVE_BAIUM);
		int status = GrandBossManager.getInstance().getBossStatus(LIVE_BAIUM);
		if (info.getInt("loc_x") == 0 && info.getInt("loc_y") == 0) status = DEAD;	//[JOJO]
		if (status == DEAD)
		{
			// load the unlock date and time for baium from DB
			long temp = (info.getLong("respawn_time") - System.currentTimeMillis());
			if (temp > 0)
			{
				// the unlock time has not yet expired. Mark Baium as currently locked (dead). Setup a timer
				// to fire at the correct time (calculate the time between now and the unlock time,
				// setup a timer to fire after that many msec)
				startQuestTimer("baium_unlock", temp, null, null);
				_log.info("AI script: Next spawn date of Baium is " + GrandBossManager.respawnTimeFormat(info) + ".");
			}
			else
			{
				// the time has already expired while the server was offline. Delete the saved time and
				// immediately spawn the stone-baium. Also the state need not be changed from ASLEEP
				addSpawn(STONE_BAIUM, 116033, 17447, 10107, -25348, false, 0);
				GrandBossManager.getInstance().setBossStatus(LIVE_BAIUM, ASLEEP);
			}
		}
		else if (status == AWAKE)
		{
			int loc_x = info.getInt("loc_x");
			int loc_y = info.getInt("loc_y");
			int loc_z = info.getInt("loc_z") - com.l2jserver.Config.NPC_SPAWN_Z_MARGIN;
			int heading = info.getInt("heading");
			final int hp = info.getInt("currentHP");
			final int mp = info.getInt("currentMP");
			L2GrandBossInstance baium = (L2GrandBossInstance) addSpawn(LIVE_BAIUM, loc_x, loc_y, loc_z, heading, false, 0);
			GrandBossManager.getInstance().addBoss(baium);
			final L2Npc _baium = baium;
			ThreadPoolManager.getInstance().scheduleGeneral(new Runnable()
			{
				@Override
				public void run()
				{
					try
					{
						_baium.setCurrentHpMp(hp, mp);
						_baium.setIsInvul(true);
						_baium.setIsImmobilized(true);
						_baium.setRunning();
					//	_baium.broadcastSocialAction(2);
						startQuestTimer("baium_wakeup", 15000, _baium, null);
					}
					catch (Exception e)
					{
						e.printStackTrace();
					}
				}
			}, 100L);
		}
		else
		{
			addSpawn(STONE_BAIUM, 116033, 17447, 10107, -25348, false, 0);
		}
	}
	
	@Override
	public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
	{
		switch (event)
		{
			case "baium_unlock":
			{
				GrandBossManager.getInstance().setBossStatus(LIVE_BAIUM, ASLEEP);
				addSpawn(STONE_BAIUM, 116033, 17447, 10107, -25348, false, 0);
				break;
			}
			case "skill_range":
			{
				if (npc != null)
				{
					callSkillAI(npc);
				}
				break;
			}
			case "clean_player":
			{
				_target = getRandomTarget(npc);
				break;
			}
			case "baium_wakeup":
			{
				if ((npc != null) && (npc.getId() == LIVE_BAIUM))
				{
					if (player != null)	//[JOJO]
					{
						_Zone.broadcastPacket(new SocialAction(npc, 1));
						_Zone.broadcastPacket(new Earthquake(npc.getX(), npc.getY(), npc.getZ(), 40, 5));
						_Zone.broadcastPacket(new PlaySound(1, "BS02_A", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
						Broadcast.announceToOnlinePlayers("傲慢の塔のバイウムが覚醒しました。"); // [JOJO]
						_Zone.broadcastPacket(new NpcSay(npc.getObjectId(), 0, npc.getId(), player.getName() + "、私の眠りを妨げるとは！、死ぬがいい！")); // [JOJO]
						startQuestTimer("pc_kill", 7000, npc, player, false);
					}
					// start monitoring baium's inactivity
					_LastAttackVsBaiumTime = System.currentTimeMillis();
					startQuestTimer("baium_despawn", 60000, npc, null, true);
					startQuestTimer("skill_range", 500, npc, null, true);
					final L2Npc baium = npc;
					ThreadPoolManager.getInstance().scheduleGeneral(new Runnable()
					{
						@Override
						public void run()
						{
							try
							{
								baium.setIsInvul(false);
								baium.setIsImmobilized(false);
								for (L2Npc minion : _Minions)
								{
									minion.setShowSummonAnimation(false);
								}
							}
							catch (Exception e)
							{
								_log.log(Level.WARNING, "", e);
							}
						}
					}, 11100L);
					
					// XXXX: Player that wake up Baium take damage.
					
					for (Location loc : ANGEL_LOCATION)
					{
						L2Npc angel = addSpawn(ARCHANGEL, loc, false, 0, true);
						angel.setIsInvul(true);
						_Minions.add(angel);
					}
				}
				// despawn the live baium after 30 minutes of inactivity
				// also check if the players are cheating, having pulled Baium outside his zone...
				break;
			}
			case "baium_despawn":
			{
				if ((npc != null) && (npc.getId() == LIVE_BAIUM))
				{
					// just in case the zone reference has been lost (somehow...), restore the reference
					if (_Zone == null)
					{
						_Zone = GrandBossManager.getInstance().getZone(113100, 14500, 10077);
					}
					long temp = System.currentTimeMillis() - _LastAttackVsBaiumTime;
					if (temp > 1800000)
					{
						cancelQuestTimer("baium_despawn", npc, null);
						cancelQuestTimer("skill_range", npc, null);
						cancelQuestTimer("clean_player", npc, null);
						if (FIX_AI_SYNCHRONIZED) _AILock = null;
						npc.deleteMe(); // despawn the live-baium
						for (L2Npc minion : _Minions)
						{
							if (minion != null)
							{
								minion.getSpawn().stopRespawn();
								minion.deleteMe();
							}
						}
						_Minions.clear();
						addSpawn(STONE_BAIUM, 116033, 17447, 10107, -25348, false, 0); // spawn stone-baium
						GrandBossManager.getInstance().setBossStatus(LIVE_BAIUM, ASLEEP); // mark that Baium is not awake any more
						_Zone.oustAllPlayers();
					}
					else if (((_LastAttackVsBaiumTime + 300000) < System.currentTimeMillis()) && (npc.getCurrentHp() < ((npc.getMaxHp() * 3) / 4.0)))
					{
						npc.setIsCastingNow(false); // just in case
						npc.setTarget(npc);
						if (npc.isPhysicalMuted())
						{
							return super.onAdvEvent(event, npc, player);
						}
						npc.doCast(getSkill(BAIUM_HEAL));
						npc.setIsCastingNow(true);
					}
					else if (!_Zone.isInsideZone(npc))
					{
						npc.teleToLocation(BAIUM_DESPAWN);
					}
					else if (FWB_MOVEATRANDOM && temp >= 60000 && ! npc.isAttackingNow())	//[JOJO] move at random.
					{
						if (getRandom(5) == 0)
						{
							_Zone.broadcastPacket(new SocialAction(npc, getRandom(1, 4)));
						}
						else
						{
							_Zone.updateKnownList(npc);
							Location pos = new Location(getRandom(112826, 116241), getRandom(15575, 16375), 10078, 0);
							npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, pos);
						}
					}
				}
				break;
			}
			case "pc_kill":
			{
				player.reduceCurrentHp(player.getMaxHp() + getRandom(player.getMaxHp()/2, player.getMaxHp()), npc, null);
				break;
			}
		}
		return super.onAdvEvent(event, npc, player);
	}
	
	@Override
	public String onTalk(L2Npc npc, L2PcInstance player)
	{
		String htmltext = "";
		if (_Zone == null)
		{
			_Zone = GrandBossManager.getInstance().getZone(113100, 14500, 10077);
		}
		if (_Zone == null)
		{
			return "<html><body>エンジェリック バーテックス:<br>You may not enter while admin disabled this zone</body></html>";
		}
		
		switch (npc.getId())
		{
			case STONE_BAIUM:
			{
				if (GrandBossManager.getInstance().getBossStatus(LIVE_BAIUM) == ASLEEP)
				{
					if (_Zone.isPlayerAllowed(player))
					{
						// once Baium is awaken, no more people may enter until he dies, the server reboots, or
						// 30 minutes pass with no attacks made against Baium.
						GrandBossManager.getInstance().setBossStatus(LIVE_BAIUM, AWAKE);
						npc.deleteMe();
						L2GrandBossInstance baium = (L2GrandBossInstance) addSpawn(LIVE_BAIUM, npc, true);
						GrandBossManager.getInstance().addBoss(baium);
						final L2PcInstance _player = player;
						final L2Npc _baium = baium;
						ThreadPoolManager.getInstance().scheduleGeneral(new Runnable()
						{
							@Override
							public void run()
							{
								try
								{
									_baium.setIsInvul(true);
									_baium.setRunning();
									_Zone.broadcastPacket(new SocialAction(_baium, 2)); // orz
									startQuestTimer("baium_wakeup", 15000, _baium, _player); // [JOJO] null ... _player
									_baium.setShowSummonAnimation(false);
								}
								catch (Throwable e)
								{
									_log.log(Level.WARNING, "", e);
								}
							}
						}, 100L);
					}
					else
					{
						htmltext = "Conditions are not right to wake up Baium";
					}
				}
				break;
			}
			case ANGELIC_VORTEX:
			{
				if (player.isFlying())
				{
					// print "Player "+player.getName()+" attempted to enter Baium's lair while flying!";
					return "<html><body>エンジェリック バーテックス:<br><font color=LEVEL>空を飛びながら中に入ることはできない。</font></body></html>"; //[JOJO]意訳
				//  return "<html><body>Angelic Vortex:<br>You may not enter while flying a wyvern</body></html>";
				}
				
				if ((GrandBossManager.getInstance().getBossStatus(LIVE_BAIUM) == ASLEEP) && hasQuestItems(player, BLOODED_FABRIC))
				{
					takeItems(player, BLOODED_FABRIC, 1);
					// allow entry for the player for the next 30 secs (more than enough time for the TP to happen)
					// Note: this just means 30secs to get in, no limits on how long it takes before we get out.
					_Zone.allowPlayerEntry(player, 30);
					player.teleToLocation(BAIUM_ENTER);
				}
				else
				{
					npc.showChatWindow(player, 1);	// data/html/default/31862-1.htm
				}
				break;
			}
			case TELEPORT_CUBIC:
			{
				final Location loc = TELEPORT_CUBIC_LOCATION[getRandom(TELEPORT_CUBIC_LOCATION.length)];
				player.teleToLocation(loc.getX() + getRandom(100), loc.getY() + getRandom(100), loc.getZ());
				break;
			}
		}
		return htmltext;
	}
	
	@Override
	public String onSpellFinished(L2Npc npc, L2PcInstance player, L2Skill skill)
	{
		if (npc.isInvul())
		{
			npc.getAI().setIntention(AI_INTENTION_IDLE);
			return null;
		}
		callSkillAI(npc);
		return super.onSpellFinished(npc, player, skill);
	}
	
	@Override
	public String onSpawn(L2Npc npc)
	{
		if (!npc.isTeleporting())
		{
			npc.disableCoreAI(true);
			if (FIX_AI_SYNCHRONIZED) _AILock = new ReentrantLock();
		}
		return super.onSpawn(npc);
	}
	
	@Override
	public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
	{
		if (!_Zone.isInsideZone(attacker))
		{
			attacker.reduceCurrentHp(attacker.getCurrentHp(), attacker, false, false, null);
			return super.onAttack(npc, attacker, damage, isSummon);
		}
		if (npc.isInvul())
		{
			npc.getAI().setIntention(AI_INTENTION_IDLE);
			return super.onAttack(npc, attacker, damage, isSummon);
		}
		
		if (attacker.getMountType() == MountType.STRIDER)
		{
			boolean hasStriderDebuff = false;
			for (L2Effect e : attacker.getAllEffects())
			{
				if (e.getSkill().getReuseHashCode() == HINDER_STRIDER)
				{
					hasStriderDebuff = true;
				}
			}
			if (!hasStriderDebuff)
			{
				npc.setTarget(attacker);
				if (npc.isMuted())
				{
					return super.onAttack(npc, attacker, damage, isSummon);
				}
				npc.doCast(getSkill(HINDER_STRIDER));
			}
		}
		// update a variable with the last action against baium
		_LastAttackVsBaiumTime = System.currentTimeMillis();
		callSkillAI(npc);
		return super.onAttack(npc, attacker, damage, isSummon);
	}
	
	@Override
	public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
	{
		cancelQuestTimer("baium_despawn", npc, null);
		cancelQuestTimer("skill_range", npc, null);
		cancelQuestTimer("clean_player", npc, null);
		if (FIX_AI_SYNCHRONIZED) _AILock = null;
		_Zone.broadcastPacket(new PlaySound(1, "BS01_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
		// spawn the "Teleportation Cubic" for 15 minutes (to allow players to exit the lair)
		addSpawn(TELEPORT_CUBIC, 115017, 15549, 10090, 0, false, 900000);
		// Calculate Min and Max respawn times randomly.
		long respawnTime = Config.BAIUM_SPAWN_INTERVAL + getRandom(-Config.BAIUM_SPAWN_RANDOM, Config.BAIUM_SPAWN_RANDOM);
		respawnTime *= 3600000;
		
		GrandBossManager.getInstance().setBossStatus(LIVE_BAIUM, DEAD);
		startQuestTimer("baium_unlock", respawnTime, null, null);
		// also save the respawn time so that the info is maintained past reboots
		StatsSet info = GrandBossManager.getInstance().getStatsSet(LIVE_BAIUM);
		info.set("respawn_time", System.currentTimeMillis() + respawnTime);
		GrandBossManager.getInstance().setStatsSet(LIVE_BAIUM, info);
		for (L2Npc minion : _Minions)
		{
			if (minion != null)
			{
				minion.getSpawn().stopRespawn();
				minion.deleteMe();
			}
		}
		_Minions.clear();
	//	final QuestTimer timer = getQuestTimer("skill_range", npc, null);
	//	if (timer != null)
	//	{
	//		timer.cancelAndRemove();
	//	}
		Broadcast.announceToOnlinePlayers("傲慢の塔のバイウムが死亡しました。次の復活は "+GrandBossManager.respawnTimeFormat(info)+" ごろです。");  //[JOJO]
		return super.onKill(npc, killer, isSummon);
	}
	
	public L2Character getRandomTarget(L2Npc npc)
	{
		Collection<L2Character> objs = _Zone.getCharactersInside();
		L2Character[] characters = new L2Character[objs.size()];
		int count = 0;
		{
			for (L2Character obj : objs)
			{
				if (obj.isPlayable() || (obj instanceof L2DecoyInstance))
				{
					if (obj.isPlayer())
					{
						if (obj.getActingPlayer().getAppearance().getInvisible())
						{
							continue;
						}
					}
					if (obj.isDead())
						continue;
					if (Math.abs(obj.getZ() - npc.getZ()) > 100)
						continue;
					if (!GeoData.getInstance().canSeeTarget(npc, obj))
						continue;
					if (!Util.checkIfInRange(9000, npc, obj, true))
						continue;
					
					characters[count++] = obj;
				}
			}
		}
		if (count == 0)
		{
			for (L2Npc minion : _Minions)
			{
				if (minion != null)
				{
					characters[count++] = minion;
				}
			}
		}
		
		if (count == 0)
		{
			return null;
		}
		
		cancelQuestTimer("clean_player", npc, null);
		startQuestTimer("clean_player", 20000, npc, null);
		return characters[getRandom(count)];
	}
	
	private void callSkillAI(L2Npc npc)
	{
if (FIX_AI_SYNCHRONIZED) {{
		ReentrantLock lock;
		if ((lock = _AILock).tryLock()) try { $callSkillAI(npc); } finally { lock.unlock(); }
}} else {{
		synchronized (this) { $callSkillAI(npc); }
}}
	}
	
	private /*public synchronized*/ void $callSkillAI(L2Npc npc)
	{
		if (npc.isInvul() || npc.isCastingNow())
		{
			return;
		}
		
		if ((_target == null) || _target.isDead() || !(_Zone.isInsideZone(_target)))
		{
			_target = getRandomTarget(npc);
			if (_target != null)
			{
				_skillHashCode = getRandomSkill(npc);
			}
		}
		
		L2Character target = _target;
		L2Skill skill = getSkill(_skillHashCode);
		if (skill == null)
		{
			skill = getSkill(getRandomSkill(npc));
		}
		
		if (npc.isPhysicalMuted())
		{
			return;
		}
		
		if ((target == null) || target.isDead() || !(_Zone.isInsideZone(target)))
		{
			npc.setIsCastingNow(false);
			return;
		}
		
		if (Util.checkIfInRange(skill.getCastRange(), npc, target, true))
		{
			_Zone.updateKnownList(npc);
			npc.getAI().setIntention(AI_INTENTION_IDLE);
			npc.setTarget(target);
			npc.setIsCastingNow(true);
			_target = null;
			_skillHashCode = 0;
			if (getDist(skill.getCastRange()) > 0)
			{
				npc.broadcastPacket(new MoveToPawn(npc, target, getDist(skill.getCastRange())));
			}
			try
			{
if (FIX_AI_CAST_SLEEP) {{
				if (_doCast == null) _doCast = new DoCast();
				ThreadPoolManager.getInstance().scheduleGeneral(_doCast.newCast(npc, skill), 1000);
}} else {{
				Thread.sleep(1000);
				npc.stopMove(null);
				npc.doCast(skill);
}}
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}
		else
		{
			_Zone.updateKnownList(npc);
			npc.getAI().setIntention(AI_INTENTION_FOLLOW, target, null);
			npc.setIsCastingNow(false);
		}
	}
	
	private DoCast _doCast;
	protected class DoCast implements Runnable
	{
		L2Npc npc;
		L2Skill skill;
		DoCast newCast(L2Npc npc, L2Skill skill)
		{
if (FIX_AI_CAST_SLEEP) {{
			this.npc = npc;
			this.skill = skill;
}}
			return this;
		}
		@Override
		public void run()
		{
if (FIX_AI_CAST_SLEEP) {{
			npc.stopMove(null);
			npc.doCast(skill);
}}
		}
	}
	
	public int getRandomSkill(L2Npc npc)
	{
		int skillHashCode;
		int chance = getRandom(100);
		final int hpRatio = (int) (100 * npc.getCurrentHp() / npc.getMaxHp());
		if (hpRatio > 75)
		{
			if ((chance -= 10) < 0)
			{
				skillHashCode = WIND_OF_FORCE;
			}
			else if ((chance -= 10) < 0)
			{
				skillHashCode = EARTHQUAKE;
			}
			else
			{
				skillHashCode = GENERAL_ATTACK;
			}
		}
		else if (hpRatio > 50)
		{
			if ((chance -= 10) < 0)
			{
				skillHashCode = STUN;
			}
			else if ((chance -= 10) < 0)
			{
				skillHashCode = WIND_OF_FORCE;
			}
			else if ((chance -= 10) < 0)
			{
				skillHashCode = EARTHQUAKE;
			}
			else
			{
				skillHashCode = GENERAL_ATTACK;
			}
		}
		else
		{
			if ((chance -= 10) < 0)
			{
				skillHashCode = STRIKING_OF_THUNDERBOLT;
			}
			else if ((chance -= 10) < 0)
			{
				skillHashCode = STUN;
			}
			else if ((chance -= 10) < 0)
			{
				skillHashCode = WIND_OF_FORCE;
			}
			else if ((chance -= 10) < 0)
			{
				skillHashCode = EARTHQUAKE;
			}
			else
			{
				skillHashCode = GENERAL_ATTACK;
			}
		}
		return skillHashCode;
	}
	
	@Override
	public String onSkillSee(L2Npc npc, L2PcInstance caster, L2Skill skill, L2Object[] targets, boolean isSummon)
	{
		if (npc.isInvul())
		{
			npc.getAI().setIntention(AI_INTENTION_IDLE);
			return null;
		}
		npc.setTarget(caster);
		return super.onSkillSee(npc, caster, skill, targets, isSummon);
	}
	
	public int getDist(int range)
	{
		int dist = 0;
		switch (range)
		{
			case -1:
				break;
			case 100:
				dist = 85;
				break;
			default:
				dist = range - 85;
				break;
		}
		return dist;
	}
	
	public static void main(String[] args)
	{
		new Baium(Baium.class.getSimpleName(), "ai");
	}
}
