/*
 * This program 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.
 * 
 * This program 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 instances.FinalEmperialTomb;

import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_MOVE_TO;
import gnu.trove.iterator.TIntObjectIterator;
import gnu.trove.set.hash.TIntHashSet;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import javolution.util.FastList;

import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.datatables.SkillTable;
import com.l2jserver.gameserver.instancemanager.InstanceManager;
import com.l2jserver.gameserver.instancemanager.InstanceManager.InstanceWorld;
import com.l2jserver.gameserver.instancemanager.ZoneManager;
import com.l2jserver.gameserver.model.L2CharPosition;
import com.l2jserver.gameserver.model.L2CommandChannel;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Object.InstanceType;
import com.l2jserver.gameserver.model.L2Party;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.L2Spawn;
import com.l2jserver.gameserver.model.L2World;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jserver.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.item.instance.L2ItemInstance;
import com.l2jserver.gameserver.model.quest.Quest;
import com.l2jserver.gameserver.model.quest.QuestState;
import com.l2jserver.gameserver.model.zone.L2ZoneType;
import com.l2jserver.gameserver.network.NpcStringId;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.clientpackets.Say2;
import com.l2jserver.gameserver.network.serverpackets.AbstractNpcInfo.NpcInfo;
import com.l2jserver.gameserver.network.serverpackets.Earthquake;
import com.l2jserver.gameserver.network.serverpackets.ExShowScreenMessage;
import com.l2jserver.gameserver.network.serverpackets.FlyToLocation;
import com.l2jserver.gameserver.network.serverpackets.FlyToLocation.FlyType;
import com.l2jserver.gameserver.network.serverpackets.L2GameServerPacket;
import com.l2jserver.gameserver.network.serverpackets.MagicSkillCanceld;
import com.l2jserver.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jserver.gameserver.network.serverpackets.NpcSay;
import com.l2jserver.gameserver.network.serverpackets.SocialAction;
import com.l2jserver.gameserver.network.serverpackets.SpecialCamera;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
import com.l2jserver.gameserver.network.serverpackets.ValidateLocation;
import com.l2jserver.gameserver.templates.effects.EffectTemplate;
import com.l2jserver.gameserver.templates.skills.L2SkillType;
import com.l2jserver.gameserver.util.Util;
import com.l2jserver.util.Rnd;

/**
 * Frintezza AI
 * 
 * @author Darki699
 * @author SANDMAN L2J_JP
 * @author JOJO
 * @author rocknow
 * @author L2jOff team
 */
/*
TODO:
- test when Frintezza song use 5008 effect skill
- maybe test more deeply halishas AI
- use correct Song names
- use proper zone spawn system
Contributing authors: Gigiikun
*/
public class FinalEmperialTomb extends Quest
{
	private static final boolean DEBUG = false;
	private static final boolean ASSERT = false;
	private static final boolean DETECT_ACTION_LOCK = true;
	
	private class FETWorld extends InstanceWorld
	{
		public         Lock                 lock                         = new ReentrantLock();
		public         FastList<L2Npc>      npcList                      = new FastList<L2Npc>();
		public         int                  npcMax                       = 0;
		public         int                  darkChoirPlayerCount         = 0;
		public         ScheduledFuture<?>   songTask                     = null;
		public         boolean              isVideo                      = false;
		public         L2Npc                frintezzaDummy               = null;
		public         L2Npc                overheadDummy                = null;
		public         L2Npc                portraitDummy1               = null;
		public         L2Npc                portraitDummy3               = null;
		public         L2Npc                scarletDummy                 = null;
		public         L2GrandBossInstance  frintezza                    = null;
		public         L2GrandBossInstance  activeScarlet                = null;
		public         L2MonsterInstance[]  ghosts                       = new L2MonsterInstance[4];
		public         L2MonsterInstance[]  portraits                    = new L2MonsterInstance[4];
		public         int                  scarlet_x                    = 0;
		public         int                  scarlet_y                    = 0;
		public         int                  scarlet_z                    = 0;
		public         int                  scarlet_h                    = 0;
		public         int                  scarlet_a                    = 0;
		private        long                 lastAction;

		public FETWorld()
		{
if (DETECT_ACTION_LOCK) {{
			class ActionLockListener implements Runnable
			{
				public void run()
				{
					if (status == 1 || status == 2)
					{
						if (System.currentTimeMillis() - lastAction > 300000)
						{
							if (status == 1)
							{
								if (InstanceManager.getInstance().getInstance(instanceId).getDoor(17130051).getOpen())
									addAggroToMobs(FETWorld.this, ROOM1_CENTER_X, ROOM1_CENTER_Y, ROOM1_CENTER_Z);
							}
							else if (status == 2)
							{
								if (InstanceManager.getInstance().getInstance(instanceId).getDoor(17130061).getOpen())
									addAggroToMobs(FETWorld.this, ROOM2_CENTER_X, ROOM2_CENTER_Y, ROOM2_CENTER_Z);
							}
							lastAction = System.currentTimeMillis();
						}
						ThreadPoolManager.getInstance().scheduleGeneral(ActionLockListener.this, 30000);
					}
				}
			}
			lastAction = System.currentTimeMillis();
			ThreadPoolManager.getInstance().scheduleGeneral(new ActionLockListener(), 60000);
}}
		}
	}
	private static class FrintezzaSong
	{
		public int songId, songLevel;
		public int effectId, effectLevel;
		public NpcStringId songName;
		public int chance;
		
		public FrintezzaSong(int songId, int songLevel, int effectId, int effectLevel, NpcStringId songName, int chance)
		{
			this.songId = songId;
			this.songLevel = songLevel;
			this.effectId = effectId;
			this.effectLevel = effectLevel;
			this.songName = songName;
			this.chance = chance;
		}
	}
	
	private static final String qn = "FinalEmperialTomb";
	private static final int INSTANCEID = 136; // this is the client number
	private static final int MIN_PLAYERS = 36;
	private static final int MAX_PLAYERS = 45;
	
	// Initialization at 6:30 am on Wednesday and Saturday
	private static final int RESET_HOUR_OF_DAY = 6;
	private static final int RESET_MINUTE = 30;
	private static final int[] RESET_DAY_OF_WEEK = { Calendar.WEDNESDAY, Calendar.SATURDAY, };
	
	private final TIntHashSet _mustKillMobsId = new TIntHashSet();
	
	//Items
	private static final int FRINTEZZA_SCROLL = 8073;		// Frintezza's Magic Force Field Removal Scroll | フリンテッサの結界解除スクロール
	private static final int SOUL_BREAKING_ARROW = 8192;	// Soul Breaking Arrow | 破魂の矢
	private static final int DEWDROP_OF_DESTRUCTION = 8556;	// Dewdrop of Destruction | 破魂の露
	
	@SuppressWarnings("unused") private static final int FIRST_SCARLET_WEAPON = 8204;	// --> npc.sql
	private static final int SECOND_SCARLET_WEAPON = 7903;
	@SuppressWarnings("unused") private static final int THIRD_SCARLET_WEAPON = 8222;	// --> npc.sql
	
	//NPCs
	private static final int GUIDE = 32011; // Imperial Tomb Guide | フリンテッサ テレポーター
	private static final int CUBE = 29061; // Teleportation Cubic | テレポート キューブ
	
	//mobs: ROOM 3
	private static final int FRINTEZZA = 29045;
	private static final int SCARLET1 = 29046; // Daemon #1,#2 Scarlet van Halisha | スカーレット ヴァン ハリシャ
	private static final int SCARLET2 = 29047; // Daemon #3    Scarlet van Halisha | スカーレット ヴァン ハリシャ
	private static final int PORTRAIT_FIGHTER = 29048; // Evil Spirit | エヴィレイト(ファイター)
	private static final int PORTRAIT_MAGE = 29049; // Evil Spirit | エヴィレイト(メイジ)
	private static final int GHOST_FIGHTER = 29050; // Breath of Halisha | ハリシャ ブレス(ファイター)
	private static final int GHOST_MAGE = 29051; // Breath of Halisha | ハリシャ ブレス(メイジ)
	@SuppressWarnings("unused") private static final int CAMERA_DUMMY = 29052;
	@SuppressWarnings("unused") private static final int DIMENSIONAL_SHOCK = 29053;
	//mobs: ROOM 1
	private static final int HALL_ALARM = 18328; // ホール アラーム
	private static final int HALL_KEEPER_CAPTAIN = 18329; // Hall Keeper Captain | ホールキーパー キャプテン
	private static final int HALL_KEEPER_WIZARD = 18330; // Hall Keeper Wizard | ホールキーパー ウィザード
	private static final int HALL_KEEPER_GUARD = 18331; // Hall Keeper Guard | ホールキーパー ガード
	@SuppressWarnings("unused") private static final int HALL_KEEPER_PATROL = 18332; // Hall Keeper Patrol | ホールキーパー パトロール
	private static final int HALL_KEEPER_SUICIDAL_SOLDIER_1 = 18333; // Hall Keeper Suicidal Soldier | ホールキーパー カミカゼ(攻撃力16かなり高め／スキル4614-9 NPC Death Bomb)
	//mobs: ROOM 2
	private static final int DARK_CHOIR_CAPTAIN = 18334; // Dark Choir Captain | 黒聖歌団長
	private static final int DARK_CHOIR_PRIMA_DONNA = 18335; // Dark Choir Prima Donna | 黒聖歌団 プリマ
	private static final int DARK_CHOIR_LANCER = 18336; // Dark Choir Lancer | 黒聖歌団 ランサー
	private static final int DARK_CHOIR_ARCHER = 18337; // Dark Choir Archer | 黒聖歌団 アーチャー
	private static final int DARK_CHOIR_WITCH_DOCTOR = 18338; // Dark Choir Witch Doctor | 黒聖歌団 ウィザード
	private static final int DARK_CHOIR_PLAYER = 18339; // Dark Choir Player | 黒聖歌団 プレイヤー
	@SuppressWarnings("unused") private static final int HALL_KEEPER_SUICIDAL_SOLDIER_2a = 18340; // Hall Keeper Suicidal Soldier | ホールキーパー カミカゼ(攻撃力11普通／スキル5042-9 NPC Dispel Bomb)
	@SuppressWarnings("unused") private static final int HALL_KEEPER_SUICIDAL_SOLDIER_2b = 18341; // Hall Keeper Suicidal Soldier | ホールキーパー カミカゼ(攻撃力16かなり高め／スキル5042-9 NPC Dispel Bomb)
	
	private static final int[] AI_DISABLED_MOBS = { HALL_ALARM };
	private static final int[] NO_AGGRO_MOBS = { DARK_CHOIR_CAPTAIN };
	
	// Skills
	private static final int FRINTEZZA_SONG = 5007, FRINTEZZA_EFFECT = 5008;
	private static final FrintezzaSong[] FRINTEZZA_SONG_LIST =
	{
		new FrintezzaSong(FRINTEZZA_SONG,1, FRINTEZZA_EFFECT,1, NpcStringId.REQUIEM_OF_HATRED, 5),			//  5% ヒール演奏。
		new FrintezzaSong(FRINTEZZA_SONG,2, FRINTEZZA_EFFECT,2, NpcStringId.RONDO_OF_SOLITUDE, 50),			// 45% 演出：ダッシュ+肖像画再生演奏。
		new FrintezzaSong(FRINTEZZA_SONG,3, FRINTEZZA_EFFECT,3, NpcStringId.FRENETIC_TOCCATA, 70),			// 20% 攻撃/速度演奏。
		new FrintezzaSong(FRINTEZZA_SONG,4, FRINTEZZA_EFFECT,4, NpcStringId.MOURNFUL_CHORALE_PRELUDE, 90),	// 20% 悲嘆のコラール
		new FrintezzaSong(FRINTEZZA_SONG,5, FRINTEZZA_EFFECT,5, NpcStringId.HYPNOTIC_MAZURKA, 100),			// 10% 魅惑のマズルカ
	};
	
	// Doors/Walls/Zones
	private static final int[] FIRST_ROOM_DOORS = 
	{ 
		17130051, 17130052, 17130053, 17130054, 17130055,
		17130056, 17130057, 17130058
	};
	private static final int[] SECOND_ROOM_DOORS = 
	{
		17130061, 17130062, 17130063, 17130064, 17130065,
		17130066, 17130067, 17130068, 17130069, 17130070
	};
	
	private static final int[] FIRST_ROUTE_DOORS = { 17130042, 17130043 };
	private static final int[] SECOND_ROUTE_DOORS = { 17130045, 17130046 };
	
	private static final int ROOM1_CENTER_X = -87904, ROOM1_CENTER_Y = -141296, ROOM1_CENTER_Z = -9168;
	private static final int ROOM2_CENTER_X = -87904, ROOM2_CENTER_Y = -147065, ROOM2_CENTER_Z = -9168;
	private static final int ROOM3_ZONE = 12911;
	
	// Teleports
	private static final int[] ENTER_TELEPORT = { -88015,-141153,-9168 };
	
	// spawns
	private static final int GHOST_RESPAWN_DELAY = 10; //sec.
	private static final int[][] PORTRAIT_SPAWNS = 
	{
		{ PORTRAIT_FIGHTER, -89381, -153981, -9168, 3368 },
		{ PORTRAIT_FIGHTER, -86234, -152467, -9168, 37656 },
		{ PORTRAIT_MAGE, -89342, -152479, -9168, -5152 },
		{ PORTRAIT_MAGE, -86189, -153968, -9168, 29456 }
	};
	private static final int[][] GHOST_SPAWNS = 
	{
		{ GHOST_FIGHTER, -89378, -153968, -9168, 3368 },
		{ GHOST_FIGHTER, -86261, -152492, -9168, 37656 },
		{ GHOST_MAGE, -89311, -152491, -9168, -5152 },
		{ GHOST_MAGE, -86217, -153956, -9168, 29456 }
	};
	
	private void openDoors(int[]doorIds, int instanceId)
	{
		for (int doorId : doorIds)
			openDoor(doorId, instanceId);
	}
	
	private void closeDoors(int[]doorIds, int instanceId)
	{
		for (int doorId : doorIds)
			closeDoor(doorId, instanceId);
	}
	
	private void openDoor(int doorId, int instanceId)
	{
		for (L2DoorInstance door : InstanceManager.getInstance().getInstance(instanceId).getDoors())
			if (door.getDoorId() == doorId)
				door.openMe();
	}
	
	private void closeDoor(int doorId, int instanceId)
	{
		for (L2DoorInstance door : InstanceManager.getInstance().getInstance(instanceId).getDoors())
			if (door.getDoorId() == doorId)
				if (door.getOpen())
					door.closeMe();
	}
	
	private boolean checkConditions(L2PcInstance player)
	{
		if (DEBUG || player.isGM())
			return true;
		L2Party party = player.getParty();
		if (party == null)
		{
			player.sendPacket(SystemMessageId.NOT_IN_PARTY_CANT_ENTER);
			return false;
		}
		L2CommandChannel channel = player.getParty().getCommandChannel();
		if (channel == null)
		{
			player.sendPacket(SystemMessageId.NOT_IN_COMMAND_CHANNEL_CANT_ENTER);
			return false;
		}
		else if (channel.getChannelLeader() != player)
		{
			player.sendPacket(SystemMessageId.ONLY_PARTY_LEADER_CAN_ENTER);
			return false;
		}
		else if (player.getInventory().getItemByItemId(FRINTEZZA_SCROLL) == null)
		{
			SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_ITEM_REQUIREMENT_NOT_SUFFICIENT);
			sm.addPcName(player);
			player.sendPacket(sm);
			return false;
		}
		else if (channel.getMemberCount() < MIN_PLAYERS || channel.getMemberCount() > MAX_PLAYERS)
		{
			player.sendPacket(SystemMessageId.PARTY_EXCEEDED_THE_LIMIT_CANT_ENTER);
			return false;
		}
		boolean condition = true;
		for (L2PcInstance channelMember : channel.getMembers())
		{
			if (channelMember.getLevel() < 80)
			{
				SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_LEVEL_REQUIREMENT_NOT_SUFFICIENT);
				sm.addPcName(channelMember);
				party.broadcastToPartyMembers(sm);
				condition = false;
			}
			if (!Util.checkIfInRange(1000, player, channelMember, true))
			{
				SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_IN_LOCATION_THAT_CANNOT_BE_ENTERED);
				sm.addPcName(channelMember);
				party.broadcastToPartyMembers(sm);
				condition = false;
			}
			long reentertime = InstanceManager.getInstance().getInstanceTime(channelMember.getObjectId(), INSTANCEID);
			if (System.currentTimeMillis() < reentertime)
			{
				SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_MAY_NOT_REENTER_YET);
				sm.addPcName(channelMember);
				party.broadcastToPartyMembers(sm);
				condition = false;
			}
		}
		return condition;
	}
	
	private void teleportPlayer(L2PcInstance player, int[] coords, int instanceId)/*テスト済*/
	{
		player.setInstanceId(instanceId);
		player.teleToLocation(coords[0], coords[1], coords[2]);
		destroyAllItem(player, SOUL_BREAKING_ARROW);
		destroyAllItem(player, DEWDROP_OF_DESTRUCTION);
	}
	
	private void destroyAllItem(L2PcInstance player, int itemId)/*テスト済*/
	{
		L2ItemInstance item = player.getInventory().getItemByItemId(itemId);
		if (item != null)
			player.destroyItemByItemId("Quest", itemId, item.getCount(), player, true);
	}
	
	private int enterInstance(L2PcInstance player, String template, int[] coords)
	{
		int instanceId = 0;
		//check for existing instances for this player
		InstanceWorld world = InstanceManager.getInstance().getPlayerWorld(player);
		//existing instance
		if (world != null)
		{
			if (!(world instanceof FETWorld))
			{
				player.sendPacket(SystemMessageId.ALREADY_ENTERED_ANOTHER_INSTANCE_CANT_ENTER);
				return 0;
			}
			teleportPlayer(player, coords, world.instanceId);
			return world.instanceId;
		}
		//New instance
		else
		{
			if (!checkConditions(player))
				return 0;
			if (!player.isGM() && !player.destroyItemByItemId("Quest", FRINTEZZA_SCROLL, 1, player, true))
				return 0;
			instanceId = InstanceManager.getInstance().createDynamicInstance(template);
			//Instance ins = InstanceManager.getInstance().getInstance(instanceId);
			//ins.setSpawnLoc(new int[]{player.getX(),player.getY(),player.getZ()});
			world = new FETWorld();
			world.instanceId = instanceId;
			world.status = 0;
			InstanceManager.getInstance().addWorld(world);
			controlStatus((FETWorld) world);
			_log.info("Final Emperial Tomb started " + template + " Instance: " + instanceId + " created by player: " + player.getName());
			// teleport players
			if (player.getParty() == null || player.getParty().getCommandChannel() == null)
			{
				world.allowed.add(player.getObjectId());
				teleportPlayer(player, coords, instanceId);
			}
			else
			{
				for (L2PcInstance channelMember : player.getParty().getCommandChannel().getMembers())
				{
					world.allowed.add(channelMember.getObjectId());
					teleportPlayer(channelMember, coords, instanceId);
				}
			}
			return instanceId;
		}
	}
	
	/**
	 * モンスター配置：１部屋め ホールアラーム
	 * @param world
	 */
	private void spawnHallAlarm(FETWorld world)/*テスト済*/
	{
		spawn(world, HALL_ALARM, -87904, -141296, -9168, 0, false);
	}
	/**
	 * モンスター配置：１部屋め ホールキーパー
	 * @param world
	 */
	private void spawnHallKeepers(FETWorld world)/*テスト済*/
	{
		spawn(world, HALL_KEEPER_WIZARD, -89179, -141151, -9084, 29201, true);
		spawn(world, HALL_KEEPER_WIZARD, -89072, -141422, -9084, 55195, true);
		spawn(world, HALL_KEEPER_WIZARD, -89241, -140900, -9084, 29568, true);
		spawn(world, HALL_KEEPER_GUARD, -88982, -141058, -9084, 18641, true);
		spawn(world, HALL_KEEPER_GUARD, -89168, -141063, -9084, 24129, true);
		spawn(world, HALL_KEEPER_GUARD, -89013, -141080, -9084, 15361, true);
		spawn(world, HALL_KEEPER_GUARD, -89060, -141558, -9084, 12654, true);
		spawn(world, HALL_KEEPER_GUARD, -89277, -141133, -9084, 27853, true);
		spawn(world, HALL_KEEPER_GUARD, -88982, -141441, -9084, 41976, true);
		spawn(world, HALL_KEEPER_GUARD, -89154, -141486, -9084, 55794, true);
		spawn(world, HALL_KEEPER_GUARD, -89002, -141243, -9084, 46318, true);
		spawn(world, HALL_KEEPER_GUARD, -89175, -141221, -9084, 32141, true);
		spawn(world, HALL_KEEPER_GUARD, -89286, -141786, -9084, 59388, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -89265, -141731, -9084, 4186, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -89154, -141696, -9084, 40154, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -89004, -141261, -9084, 26412, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -89098, -141667, -9084, 6500, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -89238, -140994, -9084, 34003, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -89221, -140948, -9084, 413, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -89177, -141249, -9084, 32846, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -89277, -141646, -9084, 50123, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -89289, -141179, -9084, 38433, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -89048, -141471, -9084, 23960, true);
		spawn(world, HALL_KEEPER_WIZARD, -89293, -141554, -9084, 44386, true);
		spawn(world, HALL_KEEPER_WIZARD, -89279, -141608, -9084, 17601, true);
		spawn(world, HALL_KEEPER_WIZARD, -89293, -141733, -9084, 22291, true);
		spawn(world, HALL_KEEPER_WIZARD, -89261, -140966, -9084, 33093, true);
		spawn(world, HALL_KEEPER_WIZARD, -89110, -141304, -9084, 49199, true);
		spawn(world, HALL_KEEPER_WIZARD, -89201, -141057, -9084, 61192, true);
		spawn(world, HALL_KEEPER_WIZARD, -88970, -141444, -9084, 33115, true);
		spawn(world, HALL_KEEPER_WIZARD, -89287, -141117, -9084, 31752, true);
		spawn(world, HALL_KEEPER_WIZARD, -89144, -141588, -9084, 9834, true);
		spawn(world, HALL_KEEPER_WIZARD, -89141, -141262, -9084, 48686, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -89206, -141647, -9084, 2679, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88991, -141322, -9084, 9016, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -89094, -141219, -9084, 54854, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -89041, -141506, -9084, 46264, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -89206, -141299, -9084, 7060, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -89137, -141194, -9084, 46678, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -89255, -141383, -9084, 1658, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -89239, -141546, -9084, 4935, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -89253, -141120, -9084, 15924, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -89236, -140921, -9084, 37100, true);
		spawn(world, HALL_KEEPER_WIZARD, -88994, -141895, -9084, 40023, true);
		spawn(world, HALL_KEEPER_WIZARD, -88671, -142486, -9084, 63707, true);
		spawn(world, HALL_KEEPER_WIZARD, -89070, -141952, -9084, 55610, true);
		spawn(world, HALL_KEEPER_GUARD, -88677, -142231, -9084, 5076, true);
		spawn(world, HALL_KEEPER_GUARD, -88911, -142162, -9084, 46095, true);
		spawn(world, HALL_KEEPER_GUARD, -89206, -141915, -9084, 29714, true);
		spawn(world, HALL_KEEPER_GUARD, -88913, -142183, -9084, 9773, true);
		spawn(world, HALL_KEEPER_GUARD, -88940, -141918, -9084, 59795, true);
		spawn(world, HALL_KEEPER_GUARD, -88750, -142240, -9084, 40924, true);
		spawn(world, HALL_KEEPER_GUARD, -88995, -141945, -9084, 4964, true);
		spawn(world, HALL_KEEPER_GUARD, -88456, -142398, -9084, 28245, true);
		spawn(world, HALL_KEEPER_GUARD, -89184, -141910, -9084, 31201, true);
		spawn(world, HALL_KEEPER_GUARD, -88621, -142366, -9084, 14877, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88581, -142228, -9084, 59733, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88605, -142268, -9084, 16013, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88804, -142360, -9084, 2054, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -89085, -141940, -9084, 24413, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88521, -142542, -9084, 42030, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88856, -142048, -9084, 56049, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -89033, -142038, -9084, 7498, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88685, -142335, -9084, 12201, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88827, -142060, -9084, 23417, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88895, -142065, -9084, 56831, true);
		spawn(world, HALL_KEEPER_WIZARD, -88890, -142145, -9084, 13966, true);
		spawn(world, HALL_KEEPER_WIZARD, -88814, -142315, -9084, 23378, true);
		spawn(world, HALL_KEEPER_WIZARD, -88985, -141993, -9084, 20346, true);
		spawn(world, HALL_KEEPER_WIZARD, -88882, -141894, -9084, 39953, true);
		spawn(world, HALL_KEEPER_WIZARD, -88772, -142064, -9084, 8081, true);
		spawn(world, HALL_KEEPER_WIZARD, -89193, -141924, -9084, 1410, true);
		spawn(world, HALL_KEEPER_WIZARD, -88515, -142586, -9084, 50268, true);
		spawn(world, HALL_KEEPER_WIZARD, -88951, -141997, -9084, 36420, true);
		spawn(world, HALL_KEEPER_WIZARD, -89080, -141960, -9084, 64618, true);
		spawn(world, HALL_KEEPER_WIZARD, -88911, -142051, -9084, 47432, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88630, -142205, -9084, 34636, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88511, -142481, -9084, 61532, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88854, -141942, -9084, 19805, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88888, -142146, -9084, 41516, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88811, -142349, -9084, 34329, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88515, -142514, -9084, 46043, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -89187, -141975, -9084, 18674, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88540, -142353, -9084, 51463, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -89009, -142081, -9084, 52367, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -89073, -141879, -9084, 36950, true);
		spawn(world, HALL_KEEPER_WIZARD, -87487, -142622, -9084, 11560, true);
		spawn(world, HALL_KEEPER_WIZARD, -87699, -142648, -9084, 8491, true);
		spawn(world, HALL_KEEPER_WIZARD, -87977, -142597, -9084, 20714, true);
		spawn(world, HALL_KEEPER_GUARD, -87625, -142520, -9084, 23555, true);
		spawn(world, HALL_KEEPER_GUARD, -88273, -142655, -9084, 55342, true);
		spawn(world, HALL_KEEPER_GUARD, -87945, -142633, -9084, 35172, true);
		spawn(world, HALL_KEEPER_GUARD, -87736, -142630, -9084, 24731, true);
		spawn(world, HALL_KEEPER_GUARD, -87968, -142406, -9084, 60800, true);
		spawn(world, HALL_KEEPER_GUARD, -87796, -142378, -9084, 58660, true);
		spawn(world, HALL_KEEPER_GUARD, -87632, -142640, -9084, 56686, true);
		spawn(world, HALL_KEEPER_GUARD, -87678, -142539, -9084, 7582, true);
		spawn(world, HALL_KEEPER_GUARD, -87793, -142541, -9084, 29086, true);
		spawn(world, HALL_KEEPER_GUARD, -87447, -142630, -9084, 60299, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87799, -142466, -9084, 5759, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87514, -142628, -9084, 58262, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87724, -142647, -9084, 24200, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88087, -142588, -9084, 10858, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87967, -142663, -9084, 57780, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87720, -142648, -9084, 37602, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87929, -142660, -9084, 46137, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88174, -142673, -9084, 24488, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88240, -142449, -9084, 13398, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87607, -142680, -9084, 17097, true);
		spawn(world, HALL_KEEPER_WIZARD, -88200, -142534, -9084, 15141, true);
		spawn(world, HALL_KEEPER_WIZARD, -88108, -142534, -9084, 32296, true);
		spawn(world, HALL_KEEPER_WIZARD, -87730, -142419, -9084, 42508, true);
		spawn(world, HALL_KEEPER_WIZARD, -87719, -142525, -9084, 49712, true);
		spawn(world, HALL_KEEPER_WIZARD, -88154, -142633, -9084, 46219, true);
		spawn(world, HALL_KEEPER_WIZARD, -87627, -142460, -9084, 41723, true);
		spawn(world, HALL_KEEPER_WIZARD, -87838, -142485, -9084, 1086, true);
		spawn(world, HALL_KEEPER_WIZARD, -87938, -142561, -9084, 8226, true);
		spawn(world, HALL_KEEPER_WIZARD, -87762, -142527, -9084, 17686, true);
		spawn(world, HALL_KEEPER_WIZARD, -88098, -142438, -9084, 13467, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87900, -142655, -9084, 53098, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87862, -142433, -9084, 23101, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87887, -142604, -9084, 16537, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88230, -142612, -9084, 38105, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88049, -142431, -9084, 26056, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87878, -142463, -9084, 31627, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88044, -142632, -9084, 41814, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87675, -142577, -9084, 35302, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87983, -142414, -9084, 24927, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87884, -142401, -9084, 46450, true);
		spawn(world, HALL_KEEPER_WIZARD, -86759, -141907, -9084, 17429, true);
		spawn(world, HALL_KEEPER_WIZARD, -86651, -141971, -9084, 5614, true);
		spawn(world, HALL_KEEPER_WIZARD, -86955, -142198, -9084, 31911, true);
		spawn(world, HALL_KEEPER_GUARD, -87092, -142250, -9084, 22242, true);
		spawn(world, HALL_KEEPER_GUARD, -86888, -142003, -9084, 3622, true);
		spawn(world, HALL_KEEPER_GUARD, -87177, -142347, -9084, 30199, true);
		spawn(world, HALL_KEEPER_GUARD, -86769, -141937, -9084, 9524, true);
		spawn(world, HALL_KEEPER_GUARD, -87163, -142476, -9084, 62322, true);
		spawn(world, HALL_KEEPER_GUARD, -86909, -142200, -9084, 13244, true);
		spawn(world, HALL_KEEPER_GUARD, -86788, -141977, -9084, 19113, true);
		spawn(world, HALL_KEEPER_GUARD, -87025, -142281, -9084, 40342, true);
		spawn(world, HALL_KEEPER_GUARD, -87125, -142427, -9084, 23676, true);
		spawn(world, HALL_KEEPER_GUARD, -87043, -142051, -9084, 61011, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86660, -141918, -9084, 60818, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87041, -142298, -9084, 4384, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87024, -142242, -9084, 52296, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86942, -142164, -9084, 18800, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87334, -142391, -9084, 26082, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86811, -141878, -9084, 24000, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86886, -141984, -9084, 52192, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87362, -142430, -9084, 362, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87313, -142321, -9084, 35934, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87164, -142092, -9084, 2405, true);
		spawn(world, HALL_KEEPER_WIZARD, -87174, -142324, -9084, 40368, true);
		spawn(world, HALL_KEEPER_WIZARD, -87022, -142014, -9084, 49873, true);
		spawn(world, HALL_KEEPER_WIZARD, -86978, -142210, -9084, 27160, true);
		spawn(world, HALL_KEEPER_WIZARD, -87316, -142380, -9084, 24693, true);
		spawn(world, HALL_KEEPER_WIZARD, -87166, -142212, -9084, 55605, true);
		spawn(world, HALL_KEEPER_WIZARD, -87147, -142416, -9084, 28904, true);
		spawn(world, HALL_KEEPER_WIZARD, -87393, -142346, -9084, 8960, true);
		spawn(world, HALL_KEEPER_WIZARD, -86909, -141964, -9084, 28331, true);
		spawn(world, HALL_KEEPER_WIZARD, -86680, -141996, -9084, 25744, true);
		spawn(world, HALL_KEEPER_WIZARD, -87047, -142082, -9084, 29196, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -86952, -141993, -9084, 40622, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -86960, -142294, -9084, 35741, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87257, -142281, -9084, 39057, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -86915, -141969, -9084, 52851, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87180, -142479, -9084, 59051, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -86946, -142118, -9084, 7156, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87216, -142452, -9084, 30191, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87169, -142482, -9084, 31494, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87087, -142319, -9084, 59175, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87244, -142336, -9084, 2847, true);
		spawn(world, HALL_KEEPER_WIZARD, -86553, -140940, -9084, 42599, true);
		spawn(world, HALL_KEEPER_WIZARD, -86573, -140862, -9084, 27920, true);
		spawn(world, HALL_KEEPER_WIZARD, -86687, -141658, -9084, 50112, true);
		spawn(world, HALL_KEEPER_GUARD, -86578, -141628, -9084, 16570, true);
		spawn(world, HALL_KEEPER_GUARD, -86845, -141272, -9084, 49416, true);
		spawn(world, HALL_KEEPER_GUARD, -86543, -141609, -9084, 9735, true);
		spawn(world, HALL_KEEPER_GUARD, -86702, -141546, -9084, 18913, true);
		spawn(world, HALL_KEEPER_GUARD, -86634, -141286, -9084, 25878, true);
		spawn(world, HALL_KEEPER_GUARD, -86833, -141524, -9084, 36512, true);
		spawn(world, HALL_KEEPER_GUARD, -86642, -140920, -9084, 12438, true);
		spawn(world, HALL_KEEPER_GUARD, -86627, -141565, -9084, 10380, true);
		spawn(world, HALL_KEEPER_GUARD, -86746, -140969, -9084, 4535, true);
		spawn(world, HALL_KEEPER_GUARD, -86806, -141341, -9084, 25441, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86568, -141314, -9084, 54899, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86798, -141130, -9084, 11892, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86836, -141468, -9084, 29780, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86717, -141395, -9084, 37205, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86711, -141351, -9084, 16553, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86625, -141329, -9084, 12887, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86629, -141758, -9084, 13472, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86700, -141048, -9084, 58459, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86649, -140899, -9084, 37420, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86656, -141659, -9084, 53390, true);
		spawn(world, HALL_KEEPER_WIZARD, -86639, -141628, -9084, 27370, true);
		spawn(world, HALL_KEEPER_WIZARD, -86678, -140895, -9084, 51579, true);
		spawn(world, HALL_KEEPER_WIZARD, -86666, -141401, -9084, 2166, true);
		spawn(world, HALL_KEEPER_WIZARD, -86707, -141364, -9084, 38717, true);
		spawn(world, HALL_KEEPER_WIZARD, -86626, -141263, -9084, 34845, true);
		spawn(world, HALL_KEEPER_WIZARD, -86843, -141133, -9084, 43750, true);
		spawn(world, HALL_KEEPER_WIZARD, -86683, -141644, -9084, 46859, true);
		spawn(world, HALL_KEEPER_WIZARD, -86540, -140925, -9084, 52340, true);
		spawn(world, HALL_KEEPER_WIZARD, -86764, -141468, -9084, 29290, true);
		spawn(world, HALL_KEEPER_WIZARD, -86789, -141479, -9084, 39464, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -86821, -141526, -9084, 586, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -86836, -141079, -9084, 2316, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -86583, -140867, -9084, 55682, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -86723, -141179, -9084, 57311, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -86551, -140986, -9084, 36818, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -86825, -141415, -9084, 57390, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -86549, -141026, -9084, 34174, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -86671, -141631, -9084, 4159, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -86631, -140963, -9084, 49098, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -86552, -140935, -9084, 54831, true);
		spawn(world, HALL_KEEPER_WIZARD, -86913, -140358, -9084, 29722, true);
		spawn(world, HALL_KEEPER_WIZARD, -87255, -140089, -9084, 21995, true);
		spawn(world, HALL_KEEPER_WIZARD, -87118, -140500, -9084, 64831, true);
		spawn(world, HALL_KEEPER_GUARD, -87362, -140225, -9084, 18420, true);
		spawn(world, HALL_KEEPER_GUARD, -87353, -140230, -9084, 57857, true);
		spawn(world, HALL_KEEPER_GUARD, -87044, -140238, -9084, 14115, true);
		spawn(world, HALL_KEEPER_GUARD, -87321, -140279, -9084, 56692, true);
		spawn(world, HALL_KEEPER_GUARD, -87178, -140473, -9084, 29072, true);
		spawn(world, HALL_KEEPER_GUARD, -86888, -140620, -9084, 28810, true);
		spawn(world, HALL_KEEPER_GUARD, -87132, -140419, -9084, 53381, true);
		spawn(world, HALL_KEEPER_GUARD, -87162, -140553, -9084, 65457, true);
		spawn(world, HALL_KEEPER_GUARD, -87102, -140306, -9084, 34336, true);
		spawn(world, HALL_KEEPER_GUARD, -87145, -140561, -9084, 31080, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86925, -140704, -9084, 36929, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87049, -140669, -9084, 52241, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87164, -140348, -9084, 886, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87088, -140315, -9084, 45956, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87091, -140383, -9084, 59410, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86991, -140683, -9084, 16050, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86954, -140636, -9084, 62620, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86778, -140547, -9084, 38397, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -86569, -140711, -9084, 19800, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87137, -140466, -9084, 47134, true);
		spawn(world, HALL_KEEPER_WIZARD, -87090, -140437, -9084, 54990, true);
		spawn(world, HALL_KEEPER_WIZARD, -86914, -140597, -9084, 10165, true);
		spawn(world, HALL_KEEPER_WIZARD, -87228, -140344, -9084, 38409, true);
		spawn(world, HALL_KEEPER_WIZARD, -86788, -140669, -9084, 56995, true);
		spawn(world, HALL_KEEPER_WIZARD, -86970, -140551, -9084, 2111, true);
		spawn(world, HALL_KEEPER_WIZARD, -87113, -140269, -9084, 45123, true);
		spawn(world, HALL_KEEPER_WIZARD, -86771, -140659, -9084, 62476, true);
		spawn(world, HALL_KEEPER_WIZARD, -86998, -140535, -9084, 17946, true);
		spawn(world, HALL_KEEPER_WIZARD, -87164, -140367, -9084, 31052, true);
		spawn(world, HALL_KEEPER_WIZARD, -87177, -140427, -9084, 21561, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87074, -140212, -9084, 54927, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87216, -140397, -9084, 50949, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -86945, -140425, -9084, 3892, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87195, -140156, -9084, 5887, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87204, -140445, -9084, 25114, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87006, -140498, -9084, 39595, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87155, -140363, -9084, 10302, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87189, -140528, -9084, 64655, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87052, -140527, -9084, 28893, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87317, -139959, -9084, 54399, true);
		spawn(world, HALL_KEEPER_WIZARD, -87628, -140026, -9084, 57208, true);
		spawn(world, HALL_KEEPER_WIZARD, -87744, -139968, -9084, 9834, true);
		spawn(world, HALL_KEEPER_WIZARD, -88052, -140041, -9084, 49080, true);
		spawn(world, HALL_KEEPER_GUARD, -88286, -140125, -9084, 34428, true);
		spawn(world, HALL_KEEPER_GUARD, -87949, -139989, -9084, 44173, true);
		spawn(world, HALL_KEEPER_GUARD, -87503, -139971, -9084, 63468, true);
		spawn(world, HALL_KEEPER_GUARD, -88041, -140029, -9084, 63562, true);
		spawn(world, HALL_KEEPER_GUARD, -88072, -140021, -9084, 60924, true);
		spawn(world, HALL_KEEPER_GUARD, -88138, -140250, -9084, 54354, true);
		spawn(world, HALL_KEEPER_GUARD, -87913, -140068, -9084, 5959, true);
		spawn(world, HALL_KEEPER_GUARD, -87615, -140033, -9084, 54464, true);
		spawn(world, HALL_KEEPER_GUARD, -88242, -140194, -9084, 57541, true);
		spawn(world, HALL_KEEPER_GUARD, -88269, -139985, -9084, 65308, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88139, -140250, -9084, 62428, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87949, -140037, -9084, 21905, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87569, -140051, -9084, 58704, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88137, -140234, -9084, 58580, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87661, -140093, -9084, 38266, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87577, -140146, -9084, 27046, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87773, -140149, -9084, 37681, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88014, -140241, -9084, 7654, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88087, -140070, -9084, 7795, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -87570, -140181, -9084, 36646, true);
		spawn(world, HALL_KEEPER_WIZARD, -87994, -139974, -9084, 57714, true);
		spawn(world, HALL_KEEPER_WIZARD, -88248, -139972, -9084, 62214, true);
		spawn(world, HALL_KEEPER_WIZARD, -87858, -140172, -9084, 46664, true);
		spawn(world, HALL_KEEPER_WIZARD, -88101, -140173, -9084, 61120, true);
		spawn(world, HALL_KEEPER_WIZARD, -88131, -140048, -9084, 60111, true);
		spawn(world, HALL_KEEPER_WIZARD, -88184, -140116, -9084, 58359, true);
		spawn(world, HALL_KEEPER_WIZARD, -87658, -139936, -9084, 11270, true);
		spawn(world, HALL_KEEPER_WIZARD, -87877, -140104, -9084, 5007, true);
		spawn(world, HALL_KEEPER_WIZARD, -87618, -140158, -9084, 57288, true);
		spawn(world, HALL_KEEPER_WIZARD, -88337, -140037, -9084, 50516, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87572, -140110, -9084, 14254, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88267, -140147, -9084, 12254, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -87423, -139957, -9084, 54758, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88355, -140024, -9084, 35328, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88422, -139969, -9084, 39172, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88084, -140054, -9084, 30771, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88076, -140072, -9084, 12242, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88271, -140150, -9084, 37892, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88025, -140147, -9084, 23699, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88163, -140079, -9084, 40986, true);
		spawn(world, HALL_KEEPER_WIZARD, -88733, -140567, -9084, 9785, true);
		spawn(world, HALL_KEEPER_WIZARD, -88547, -140103, -9084, 20344, true);
		spawn(world, HALL_KEEPER_WIZARD, -88617, -140237, -9084, 48681, true);
		spawn(world, HALL_KEEPER_GUARD, -88425, -140302, -9084, 33198, true);
		spawn(world, HALL_KEEPER_GUARD, -88985, -140693, -9084, 61882, true);
		spawn(world, HALL_KEEPER_GUARD, -88587, -140341, -9084, 6286, true);
		spawn(world, HALL_KEEPER_GUARD, -88555, -140020, -9084, 25728, true);
		spawn(world, HALL_KEEPER_GUARD, -88632, -140197, -9084, 49223, true);
		spawn(world, HALL_KEEPER_GUARD, -88693, -140230, -9084, 49954, true);
		spawn(world, HALL_KEEPER_GUARD, -89118, -140666, -9084, 61663, true);
		spawn(world, HALL_KEEPER_GUARD, -88966, -140668, -9084, 39800, true);
		spawn(world, HALL_KEEPER_GUARD, -88902, -140795, -9084, 10329, true);
		spawn(world, HALL_KEEPER_GUARD, -89137, -140658, -9084, 26689, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -89014, -140617, -9084, 18805, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88674, -140157, -9084, 19431, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88816, -140546, -9084, 11754, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -89023, -140482, -9084, 50721, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88634, -140389, -9084, 53263, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -89019, -140784, -9084, 31464, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88593, -140403, -9084, 55532, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88511, -140243, -9084, 57893, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88919, -140751, -9084, 31574, true);
		spawn(world, HALL_KEEPER_CAPTAIN, -88901, -140622, -9084, 2091, true);
		spawn(world, HALL_KEEPER_WIZARD, -88496, -139996, -9084, 60873, true);
		spawn(world, HALL_KEEPER_WIZARD, -88854, -140695, -9084, 51659, true);
		spawn(world, HALL_KEEPER_WIZARD, -88998, -140537, -9084, 46494, true);
		spawn(world, HALL_KEEPER_WIZARD, -88746, -140309, -9084, 58583, true);
		spawn(world, HALL_KEEPER_WIZARD, -88617, -140235, -9084, 23701, true);
		spawn(world, HALL_KEEPER_WIZARD, -88848, -140390, -9084, 38252, true);
		spawn(world, HALL_KEEPER_WIZARD, -88776, -140566, -9084, 33157, true);
		spawn(world, HALL_KEEPER_WIZARD, -88859, -140367, -9084, 53480, true);
		spawn(world, HALL_KEEPER_WIZARD, -89087, -140682, -9084, 13235, true);
		spawn(world, HALL_KEEPER_WIZARD, -88506, -140087, -9084, 17858, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88770, -140340, -9084, 22287, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88770, -140441, -9084, 2029, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88421, -140322, -9084, 28902, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88942, -140701, -9084, 10314, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88546, -140214, -9084, 65055, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88503, -139978, -9084, 17454, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88629, -140177, -9084, 48872, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88934, -140417, -9084, 32545, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88874, -140323, -9084, 64196, true);
		spawn(world, HALL_KEEPER_SUICIDAL_SOLDIER_1, -88833, -140384, -9084, 33, true);
	}
	
	/**
	 * モンスター配置：２部屋め 聖歌団プレイヤー
	 * @param world
	 */
	private void spawnDarkPlayers(FETWorld world)/*テスト済*/
	{
		spawn(world, DARK_CHOIR_PLAYER, -87875, -147001, -9128, 39939, false);
		spawn(world, DARK_CHOIR_PLAYER, -88014, -147087, -9128, 35800, false);
		spawn(world, DARK_CHOIR_PLAYER, -87785, -147219, -9128, 53478, false);
		spawn(world, DARK_CHOIR_PLAYER, -87825, -147176, -9128, 59347, false);
	}
	/**
	 * モンスター配置：２部屋め 黒聖歌団
	 * @param world
	 */
	private void spawnDarkChoirs(FETWorld world)/*テスト済*/
	{
		spawn(world, DARK_CHOIR_CAPTAIN, -88755, -147395, -9138, 0, true);
		spawn(world, DARK_CHOIR_CAPTAIN, -88755, -147187, -9138, 0, true);
		spawn(world, DARK_CHOIR_CAPTAIN, -88755, -146963, -9138, 0, true);
		spawn(world, DARK_CHOIR_CAPTAIN, -88755, -146723, -9138, 0, true);
		spawn(world, DARK_CHOIR_CAPTAIN, -87155, -147411, -9138, 33000, true);
		spawn(world, DARK_CHOIR_CAPTAIN, -87155, -147219, -9138, 33000, true);
		spawn(world, DARK_CHOIR_CAPTAIN, -87155, -146963, -9138, 33000, true);
		spawn(world, DARK_CHOIR_CAPTAIN, -87171, -146739, -9138, 33000, true);
		
		spawn(world, DARK_CHOIR_LANCER, -88467, -148467, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -88467, -148403, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -88467, -148339, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -88467, -148271, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -88471, -148199, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -88499, -148435, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -88503, -148375, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -88499, -148307, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -88503, -148239, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -87427, -148191, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87427, -148263, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87427, -148331, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87427, -148395, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87427, -148467, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87395, -148435, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87395, -148371, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87395, -148303, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87395, -148227, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87427, -145683, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87427, -145747, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87427, -145883, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87427, -145819, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87427, -145955, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87395, -145715, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87395, -145779, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87395, -145859, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -87395, -145923, -9170, 33000, true);
		spawn(world, DARK_CHOIR_LANCER, -88463, -145971, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -88467, -145899, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -88467, -145827, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -88467, -145763, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -88471, -145699, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -88495, -145939, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -88499, -145863, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -88499, -145795, -9170, 0, true);
		spawn(world, DARK_CHOIR_LANCER, -88499, -145731, -9170, 0, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88708, -146105, -9152, 46242, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88931, -146103, -9152, 15665, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88846, -146548, -9152, 57906, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88745, -146356, -9152, 47356, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88867, -146608, -9152, 2847, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88734, -146033, -9152, 249, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88813, -146453, -9152, 34935, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88773, -145967, -9152, 63174, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88928, -146028, -9152, 43447, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88918, -146165, -9152, 26885, true);
		spawn(world, DARK_CHOIR_ARCHER, -89207, -147428, -9156, 45072, true);
		spawn(world, DARK_CHOIR_ARCHER, -89018, -147611, -9156, 59002, true);
		spawn(world, DARK_CHOIR_ARCHER, -89053, -147079, -9156, 61936, true);
		spawn(world, DARK_CHOIR_ARCHER, -89158, -147440, -9156, 10110, true);
		spawn(world, DARK_CHOIR_ARCHER, -89047, -147321, -9156, 42674, true);
		spawn(world, DARK_CHOIR_ARCHER, -89102, -146927, -9156, 55423, true);
		spawn(world, DARK_CHOIR_ARCHER, -89238, -146461, -9156, 46669, true);
		spawn(world, DARK_CHOIR_ARCHER, -89074, -146800, -9156, 42740, true);
		spawn(world, DARK_CHOIR_ARCHER, -89080, -146722, -9156, 51097, true);
		spawn(world, DARK_CHOIR_ARCHER, -89094, -146927, -9156, 57530, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -89292, -146968, -9156, 23921, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -89098, -146973, -9156, 53398, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -89364, -146683, -9156, 55886, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -89137, -147813, -9156, 58589, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -89031, -146677, -9156, 16478, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -89248, -147458, -9156, 28103, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -89192, -146584, -9156, 60165, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -89267, -147106, -9156, 2957, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -89100, -147886, -9156, 29995, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -89233, -147463, -9156, 4825, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88958, -147968, -9152, 27850, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88924, -147685, -9152, 26191, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88877, -147770, -9152, 12542, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88663, -148105, -9152, 62369, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88898, -147524, -9152, 49103, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88826, -147954, -9152, 5382, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88691, -148079, -9152, 10623, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88900, -148144, -9152, 60510, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88674, -148034, -9152, 48606, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -88780, -148206, -9152, 30841, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87198, -148242, -9132, 2239, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87006, -147837, -9132, 23704, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87106, -147738, -9132, 20373, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87024, -147805, -9132, 10273, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87133, -147746, -9132, 63628, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87200, -148138, -9132, 36796, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87178, -147893, -9132, 53531, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87018, -147727, -9132, 39064, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87162, -148270, -9132, 44769, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87232, -148216, -9132, 23745, true);
		spawn(world, DARK_CHOIR_ARCHER, -86848, -146626, -9140, 21800, true);
		spawn(world, DARK_CHOIR_ARCHER, -86898, -147680, -9140, 12664, true);
		spawn(world, DARK_CHOIR_ARCHER, -86803, -146525, -9140, 4869, true);
		spawn(world, DARK_CHOIR_ARCHER, -86809, -147543, -9140, 32242, true);
		spawn(world, DARK_CHOIR_ARCHER, -86682, -146528, -9140, 26051, true);
		spawn(world, DARK_CHOIR_ARCHER, -86843, -147847, -9140, 37485, true);
		spawn(world, DARK_CHOIR_ARCHER, -86793, -146556, -9140, 17726, true);
		spawn(world, DARK_CHOIR_ARCHER, -86594, -147369, -9140, 25664, true);
		spawn(world, DARK_CHOIR_ARCHER, -86729, -147721, -9140, 39674, true);
		spawn(world, DARK_CHOIR_ARCHER, -86706, -147356, -9140, 64275, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -86892, -146732, -9140, 44902, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -86972, -148050, -9140, 64642, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -86822, -147296, -9140, 39669, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -86748, -146511, -9140, 59277, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -86811, -147359, -9140, 54652, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -86930, -146945, -9140, 16040, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -86741, -147577, -9140, 53106, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -86614, -146629, -9140, 36495, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -86899, -146940, -9140, 62921, true);
		spawn(world, DARK_CHOIR_WITCH_DOCTOR, -86650, -146646, -9140, 56177, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87162, -146112, -9132, 59727, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87187, -146185, -9132, 21514, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87308, -146022, -9132, 22939, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87152, -146145, -9132, 20344, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87235, -146167, -9132, 12091, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -86976, -146437, -9132, 17215, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -86990, -146411, -9132, 12879, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -86957, -146378, -9132, 28758, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87042, -146025, -9132, 26909, true);
		spawn(world, DARK_CHOIR_PRIMA_DONNA, -87142, -146307, -9132, 17233, true);
	}
	
	private boolean controlStatus(FETWorld world)
	{
		if (world.lock.tryLock())
		{
			try
			{
				if (DEBUG)
					_log.info("[Final Emperial Tomb] Starting " + world.status + ". status.");
				switch (world.status)
				{
					case 0:
						spawnHallAlarm(world);
						break;
					case 1:
						if (ASSERT) if (!(world.npcList.size() == 0)) throw new RuntimeException("npcList.size()=" + world.npcList.size());
						spawnDarkPlayers(world);
						break;
					case 2:
						ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(world, 0), 600000);
						break;
					case 3:
						ThreadPoolManager.getInstance().executeTask(new IntroTask(world, 200));
						break;
					case 4:
						ThreadPoolManager.getInstance().executeTask(new IntroTask(world, 300));
						break;
					case 5:
						ThreadPoolManager.getInstance().executeTask(new IntroTask(world, 400));
						break;
					case 6:
						InstanceManager.getInstance().getInstance(world.instanceId).setDuration(300000);
						openDoors(FIRST_ROOM_DOORS, world.instanceId);
						openDoors(FIRST_ROUTE_DOORS, world.instanceId);
						openDoors(SECOND_ROUTE_DOORS, world.instanceId);
						openDoors(SECOND_ROOM_DOORS, world.instanceId);
						break;
					default:
						if (ASSERT) throw new RuntimeException("status=" + world.status);
				}
				++world.status;
				if (DEBUG) broadcastPacket(world, new ExShowScreenMessage("status="+world.status, 1, 5000));
				return true;
			}
			finally
			{
				world.lock.unlock();
			}
		}
		return false;
	}
	
	private void spawn(FETWorld world, int npcId, int x, int y, int z, int h, boolean addToKillTable)
	{
		L2Npc npc = addSpawn(npcId, x, y, z, h, false, 0, false, world.instanceId);
		if (addToKillTable)
		{
			world.npcList.add(npc);
			world.npcMax = world.npcList.size();
			final boolean add;
			synchronized (_mustKillMobsId)
			{
				add = _mustKillMobsId.add(npcId);
			}
			if (add)
			{
				addKillId(npcId);
				if (npc.getTemplate().getSuicideSkills().size() > 0)
					addSpellFinishedId(npcId);
			}
			npc.setIsNoRndWalk(true);
		}
		if (npc.isInstanceType(InstanceType.L2Attackable))
			((L2Attackable) npc).setSeeThroughSilentMove(true);
		if (Util.contains(AI_DISABLED_MOBS, npcId))
			npc.disableCoreAI(true);
		if (npcId == DARK_CHOIR_PLAYER)
			++world.darkChoirPlayerCount;
	}
	
	private boolean isZZZ(L2Character character)
	{
		return character.isStunned() || character.isSleeping() || character.isParalyzed();
	}
	
	private boolean isZZZ(L2Skill skill)
	{
		for (EffectTemplate i : skill.getEffectTemplates())
		{
			L2SkillType t = i.effectType;
			if (t == L2SkillType.STUN
			 || t == L2SkillType.SLEEP
			 || t == L2SkillType.PARALYZE)
				return true;
		}
		return false;
	}
	
	private class SongTask implements Runnable/*テスト済*/
	{
		private final FETWorld _world;
		
		SongTask(FETWorld world)
		{
			_world = world;
		}
		
		@Override
		public void run()
		{
			if (InstanceManager.getInstance().getWorld(_world.instanceId) != _world)
				return;
			if (_world.frintezza == null || _world.frintezza.isDead() || !_world.frintezza.isVisible())
				return;
			if (isZZZ(_world.frintezza))
			{
				_world.songTask = ThreadPoolManager.getInstance().scheduleGeneral(SongTask.this, 1000);
				return;
			}
			if (_world.isVideo)
			{
				_world.songTask = ThreadPoolManager.getInstance().scheduleGeneral(SongTask.this, 1000);
				return;
			}
			
			// new song play
			int rnd = Rnd.get(100);
			for (FrintezzaSong song : FRINTEZZA_SONG_LIST)
			{
				if (rnd < song.chance)
				{
					L2Skill skill = SkillTable.getInstance().getInfo(song.songId, song.songLevel);
					broadcastSongTitle(_world, song.songName);
					broadcastPacket(_world, new MagicSkillUse(_world.frintezza, _world.frintezza, skill.getId(), skill.getLevel(), skill.getHitTime(), 0));
					doSongEffect(song.effectId, song.effectLevel);
					_world.songTask = ThreadPoolManager.getInstance().scheduleGeneral(SongTask.this, skill.getHitTime() + Rnd.get(5000));
					break;
				}
			}
		}
		
		public void doSongEffect(int effectId, int effectLevel)
		{
			// Frintezza song effect
			if (_world.activeScarlet == null || _world.activeScarlet.isDead() || !_world.activeScarlet.isVisible())
				return;
			if (_world.isVideo)
				return;
			
			_world.activeScarlet.doCast(SkillTable.getInstance().getInfo(effectId, effectLevel));
		}
	}
	
	private class IntroTask implements Runnable
	{
		private final FETWorld _world;
		private final int _taskId;
		
		IntroTask(FETWorld world, int taskId)
		{
			_world = world;
			_taskId = taskId;
		}
//TODO:	void scheduleNextTask(int taskId, long delay)
//		{
//			_taskId = taskId;
//			ThreadPoolManager.getInstance().scheduleGeneral(this, delay);
//		}
		
		@Override
		public void run()
		{
			if (DEBUG) broadcastPacket(_world, new ExShowScreenMessage(String.valueOf(_taskId), 7, 5000));
			switch (_taskId)
			{
				/********************/
				/* SPAWN DAEMON 1ST */
				/********************/
				case 0:
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 1), 28000);
					broadcastPacket(_world, new Earthquake(-87784, -155083, -9087, 45, 27));
					_world.activeScarlet = (L2GrandBossInstance) addSpawn(SCARLET1, -88595, -153695, -7446, 16384, false, 0, false, _world.instanceId);
					_world.activeScarlet.setOnKillDelay(100);
					_world.activeScarlet.setIsInvul(true);
					_world.activeScarlet.setIsImmobilized(true);
					_world.activeScarlet.disableAllSkills();
					_world.activeScarlet.disableCoreAI(true);
					updateKnownList(_world, _world.activeScarlet);
					break;
				case 1:
					closeDoors(FIRST_ROOM_DOORS, _world.instanceId);
					closeDoors(FIRST_ROUTE_DOORS, _world.instanceId);
					closeDoors(SECOND_ROOM_DOORS, _world.instanceId);
					closeDoors(SECOND_ROUTE_DOORS, _world.instanceId);
					for (L2Npc n : _world.npcList)	// remove Dark Choirs
						n.deleteMe();
					_world.npcList.clear();
					addSpawn(CUBE, -87904, -141296, -9168, 0, false, 0, false, _world.instanceId);
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 2), 1000);
					break;
				case 2:
					_world.frintezzaDummy = addSpawn(29052, -87784, -155083, -9087, 16048, false, 0, false, _world.instanceId);
					_world.frintezzaDummy.setIsInvul(true);
					_world.frintezzaDummy.setIsImmobilized(true);
					
					_world.overheadDummy = addSpawn(29052, -87784, -153298, -9175, 16384, false, 0, false, _world.instanceId);
					_world.overheadDummy.setIsInvul(true);
					_world.overheadDummy.setIsImmobilized(true);
					_world.overheadDummy.setCollisionHeight(600);
					broadcastPacket(_world, new NpcInfo(_world.overheadDummy, null));
					
					_world.portraitDummy1 = addSpawn(29052, -89566, -153168, -9165, 16048, false, 0, false, _world.instanceId);
					_world.portraitDummy1.setIsImmobilized(true);
					_world.portraitDummy1.setIsInvul(true);
					
					_world.portraitDummy3 = addSpawn(29052, -86004, -153168, -9165, 16048, false, 0, false, _world.instanceId);
					_world.portraitDummy3.setIsImmobilized(true);
					_world.portraitDummy3.setIsInvul(true);
					
					_world.scarletDummy = addSpawn(29053, -87784, -153298, -9175, 16384, false, 0, false, _world.instanceId);
					_world.scarletDummy.setIsInvul(true);
					_world.scarletDummy.setIsImmobilized(true);
					
					_world.isVideo = true;
					stopNpc();
					stopPc();
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 3), 1000);
					break;
				case 3:
					broadcastPacket(_world, new SpecialCamera(_world.overheadDummy.getObjectId(), 0, 75, -89, 0, 100, 0, 0, 1, 0));
					broadcastPacket(_world, new SpecialCamera(_world.overheadDummy.getObjectId(), 0, 75, -89, 0, 100, 0, 0, 1, 0));
					broadcastPacket(_world, new SpecialCamera(_world.overheadDummy.getObjectId(), 300, 90, -10, 6500, 7000, 0, 0, 1, 0));
					
					_world.frintezza = (L2GrandBossInstance) addSpawn(FRINTEZZA, -87784, -155083, -9087, 16048, false, 0, false, _world.instanceId);
					_world.frintezza.setIsImmobilized(true);
					_world.frintezza.disableAllSkills();
					_world.frintezza.disableCoreAI(true);
					_world.frintezza.setIsInvul(true);
					updateKnownList(_world, _world.frintezza);
					
					for (int i = 0; i < 4; ++i)
					{
						int[] gs = GHOST_SPAWNS[i]; //{npcId,x,y,z,h}
						L2MonsterInstance ghost = _world.ghosts[i] = (L2MonsterInstance) addSpawn(gs[0], gs[1], gs[2], gs[3], gs[4], false, 0, false, _world.instanceId);
						ghost.setIsImmobilized(true);
						ghost.setIsNoRndWalk(true);
						ghost.disableAllSkills();
						updateKnownList(_world, ghost);
						
						L2Spawn spawn = ghost.getSpawn();
						spawn.setAmount(1);
						spawn.setRespawnDelay(GHOST_RESPAWN_DELAY);//TODO: spawn.setRespawnDelay(0);
						spawn.startRespawn();
					}
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 4), 6500);
					break;
				case 4:
					broadcastPacket(_world, new SpecialCamera(_world.frintezzaDummy.getObjectId(), 1800, 90, 8, 6500, 7000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 5), 900);
					break;
				case 5:
					broadcastPacket(_world, new SpecialCamera(_world.frintezzaDummy.getObjectId(), 140, 90, 10, 2500, 4500, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 6), 4000);
					break;
				case 6:
					broadcastPacket(_world, new SpecialCamera(_world.frintezza.getObjectId(), 40, 75, -10, 0, 1000, 0, 0, 1, 0));
					broadcastPacket(_world, new SpecialCamera(_world.frintezza.getObjectId(), 40, 75, -10, 0, 12000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 7), 1350);
					break;
				case 7:
					broadcastPacket(_world, new SocialAction(_world.frintezza.getObjectId(), 2));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 8), 7000);
					break;
				case 8:
					_world.frintezzaDummy.deleteMe();
					_world.frintezzaDummy = null;
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 9), 1000);
					break;
				case 9:
					broadcastPacket(_world, new SocialAction(_world.ghosts[1].getObjectId(), 1));
					broadcastPacket(_world, new SocialAction(_world.ghosts[2].getObjectId(), 1));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 10), 400);
					break;
				case 10:
					broadcastPacket(_world, new SocialAction(_world.ghosts[0].getObjectId(), 1));
					broadcastPacket(_world, new SocialAction(_world.ghosts[3].getObjectId(), 1));
					sendPacketX(new SpecialCamera(_world.portraitDummy1.getObjectId(), 1000, 118, 0, 0, 1000, 0, 0, 1, 0), new SpecialCamera(_world.portraitDummy3.getObjectId(), 1000, 62, 0, 0, 1000, 0, 0, 1, 0), -87784);
					sendPacketX(new SpecialCamera(_world.portraitDummy1.getObjectId(), 1000, 118, 0, 0, 10000, 0, 0, 1, 0), new SpecialCamera(_world.portraitDummy3.getObjectId(), 1000, 62, 0, 0, 10000, 0, 0, 1, 0), -87784);
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 11), 2000);
					break;
				case 11:
					broadcastPacket(_world, new SpecialCamera(_world.frintezza.getObjectId(), 240, 90, 0, 0, 1000, 0, 0, 1, 0));
					broadcastPacket(_world, new SpecialCamera(_world.frintezza.getObjectId(), 240, 90, 25, 5500, 10000, 0, 0, 1, 0));
					broadcastPacket(_world, new SocialAction(_world.frintezza.getObjectId(), 3));
					_world.portraitDummy1.deleteMe();
					_world.portraitDummy3.deleteMe();
					_world.portraitDummy1 = null;
					_world.portraitDummy3 = null;
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 12), 4500);
					break;
				case 12:
					broadcastPacket(_world, new SpecialCamera(_world.frintezza.getObjectId(), 100, 195, 35, 0, 10000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 13), 700);
					break;
				case 13:
					broadcastPacket(_world, new SpecialCamera(_world.frintezza.getObjectId(), 100, 195, 35, 0, 10000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 14), 1300);
					break;
				case 14:
					broadcastPacket(_world, new SpecialCamera(_world.frintezza.getObjectId(), 120, 180, 45, 1500, 10000, 0, 0, 1, 0));
					broadcastSongTitle(_world, NpcStringId.RONDO_OF_SOLITUDE); // RONDO_OF_SOLITUDE ? MOURNFUL_CHORALE_PRELUDE ?
					broadcastPacket(_world, new MagicSkillUse(_world.frintezza, _world.frintezza, 5006, 1, 34000, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 15), 1500);
					break;
				case 15:
					broadcastPacket(_world, new SpecialCamera(_world.frintezza.getObjectId(), 520, 135, 45, 8000, 10000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 16), 7500);
					break;
				case 16:
					broadcastPacket(_world, new SpecialCamera(_world.frintezza.getObjectId(), 1500, 110, 25, 10000, 13000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 17), 9500);
					break;
				case 17:
					broadcastPacket(_world, new SpecialCamera(_world.overheadDummy.getObjectId(), 930, 160, -20, 0, 1000, 0, 0, 1, 0));
					broadcastPacket(_world, new SpecialCamera(_world.overheadDummy.getObjectId(), 600, 180, -25, 0, 10000, 0, 0, 1, 0));
					broadcastPacket(_world, new MagicSkillUse(_world.scarletDummy, _world.overheadDummy, 5004, 1, 5800, 0));
					
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 18), 2500);
					break;
				case 18:
					_world.activeScarlet.teleToLocation(-87784, -153298, -9175);
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 19), 2000);
					break;
				case 19:
					broadcastPacket(_world, new SocialAction(_world.activeScarlet.getObjectId(), 3));
					broadcastPacket(_world, new SpecialCamera(_world.scarletDummy.getObjectId(), 800, 180, 10, 1000, 10000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 20), 1500);
					break;
				case 20:
					updateKnownList(_world, _world.scarletDummy);
					throwUp(_world.scarletDummy, 500, SystemMessage.getSystemMessage(SystemMessageId.YOU_FEEL_S1_EFFECT).addSkillName(5004, 1));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 21), 2600);
					break;
				case 21:
					broadcastPacket(_world, new SpecialCamera(_world.scarletDummy.getObjectId(), 300, 60, 8, 0, 10000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 22), 2000);
					break;
				case 22:
					broadcastPacket(_world, new SpecialCamera(_world.activeScarlet.getObjectId(), 500, 90, 10, 3000, 5000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 23), 3000);
					break;
				case 23:
					_world.overheadDummy.deleteMe();
					_world.scarletDummy.deleteMe();
					_world.overheadDummy = null;
					_world.scarletDummy = null;
					
					for (int i = 0; i < 4; ++i)
					{
						int[] ps = PORTRAIT_SPAWNS[i]; //{npcId,x,y,z,h}
						L2MonsterInstance portrait = _world.portraits[i] = (L2MonsterInstance) addSpawn(ps[0], ps[1], ps[2], ps[3], ps[4], false, 0, false, _world.instanceId);
						updateKnownList(_world, portrait);
					}
					
					startPc();
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 24), 10000);
					break;
				case 24:
					_world.activeScarlet.setIsInvul(false);
					_world.activeScarlet.setIsImmobilized(false);
					_world.activeScarlet.enableAllSkills();
					_world.activeScarlet.disableCoreAI(false);
					_world.activeScarlet.setRunning();
					
					_world.frintezza.setIsInvul(false);
					_world.frintezza.setIsMortal(false);
					_world.songTask = ThreadPoolManager.getInstance().scheduleGeneral(new SongTask(_world), 5000);	//+
					
					startNpc();
					_world.isVideo = false;
					break;
				/********************/
				/* MORPH DAEMON 2ND */
				/********************/
				case 200:
					_world.activeScarlet.setIsInvul(true);
					if (_world.activeScarlet.isCastingNow())
						_world.activeScarlet.abortCast();
					setInstanceTimeRestrictions(_world);
					_world.activeScarlet.doCast(SkillTable.getInstance().getInfo(5017, 1));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 201), 1500);
					break;
				case 201:
					_world.activeScarlet.setRHandId(SECOND_SCARLET_WEAPON);
					_world.activeScarlet.setIsInvul(false);
					break;
				/********************/
				/* MORPH DAEMON 3RD */
				/********************/
				case 300:
					_world.isVideo = true;
					stopNpc();
					stopPc();
					_world.activeScarlet.abortAttack();
					_world.activeScarlet.abortCast();
					_world.activeScarlet.setIsInvul(true);
					_world.activeScarlet.setIsImmobilized(true);
					_world.activeScarlet.disableAllSkills();
					broadcastPacket(_world, new SpecialCamera(_world.frintezza.getObjectId(), 250, 120, 15, 0, 1000, 0, 0, 1, 0));
					broadcastPacket(_world, new SpecialCamera(_world.frintezza.getObjectId(), 250, 120, 15, 0, 10000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 301), 1000);
					break;
				case 301:
					_world.frintezza.stopAllEffects();
					broadcastPacket(_world, new MagicSkillCanceld(_world.frintezza.getObjectId()));
					broadcastPacket(_world, new SocialAction(_world.frintezza.getObjectId(), 4));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 302), 4000);
					break;
				case 302:
					broadcastPacket(_world, new MagicSkillUse(_world.frintezza, _world.frintezza, 5006, 1, 34000, 0));
					broadcastPacket(_world, new SpecialCamera(_world.frintezza.getObjectId(), 500, 70, 15, 3000, 10000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 303), 3000);
					break;
				case 303:
					broadcastPacket(_world, new SpecialCamera(_world.frintezza.getObjectId(), 2500, 90, 12, 6000, 10000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 304), 3000);
					break;
				case 304:
					_world.scarlet_x = _world.activeScarlet.getX();
					_world.scarlet_y = _world.activeScarlet.getY();
					_world.scarlet_z = _world.activeScarlet.getZ();
					_world.scarlet_h = _world.activeScarlet.getHeading();
					if (_world.scarlet_h < 32768)
						_world.scarlet_a = Math.abs(180 - (int) (_world.scarlet_h / 182.044444444));
					else
						_world.scarlet_a = Math.abs(540 - (int) (_world.scarlet_h / 182.044444444));
					broadcastPacket(_world, new SpecialCamera(_world.activeScarlet.getObjectId(), 250, _world.scarlet_a, 12, 0, 1000, 0, 0, 1, 0));
					broadcastPacket(_world, new SpecialCamera(_world.activeScarlet.getObjectId(), 250, _world.scarlet_a, 12, 0, 10000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 305), 500);
					break;
				case 305:
					_world.activeScarlet.doDie(_world.activeScarlet);
					broadcastPacket(_world, new SpecialCamera(_world.activeScarlet.getObjectId(), 450, _world.scarlet_a, 14, 8000, 8000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 306), 6250);
					break;
				case 306:
					_world.activeScarlet.deleteMe();
					_world.activeScarlet = null;
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 307), 950);
					break;
				case 307:
					_world.activeScarlet = (L2GrandBossInstance) addSpawn(SCARLET2, _world.scarlet_x, _world.scarlet_y, _world.scarlet_z, _world.scarlet_h, false, 0, false, _world.instanceId);
					_world.activeScarlet.setOnKillDelay(100);
					_world.activeScarlet.setIsInvul(true);
					_world.activeScarlet.setIsImmobilized(true);
					_world.activeScarlet.disableAllSkills();
					updateKnownList(_world, _world.activeScarlet);
					
					broadcastPacket(_world, new SpecialCamera(_world.activeScarlet.getObjectId(), 450, _world.scarlet_a, 12, 500, 14000, 0, 0, 1, 0));
					
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 308), 8100);
					break;
				case 308:
					broadcastPacket(_world, new SocialAction(_world.activeScarlet.getObjectId(), 2));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 309), 9000);
					break;
				case 309:
					startPc();
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 310), 10000);
					break;
				case 310:
					_world.activeScarlet.setIsInvul(false);
					_world.activeScarlet.setIsImmobilized(false);
					_world.activeScarlet.enableAllSkills();
					startNpc();
					_world.isVideo = false;
					break;
				/********************/
				/*    DIE DAEMON    */
				/********************/
				case 400:
					_world.isVideo = true;
					stopNpc();
					stopPc();
					if (_world.songTask != null)
					{
						_world.songTask.cancel(true);
						_world.songTask = null;
					}
					broadcastPacket(_world, new MagicSkillCanceld(_world.frintezza.getObjectId()));
					broadcastPacket(_world, new SpecialCamera(_world.activeScarlet.getObjectId(), 300, _world.scarlet_a - 180, 5, 0, 7000, 0, 0, 1, 0));
					broadcastPacket(_world, new SpecialCamera(_world.activeScarlet.getObjectId(), 200, _world.scarlet_a, 85, 4000, 10000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 401), 7400);
					break;
				case 401:
					_world.frintezza.doDie(_world.frintezza);
					for (int i = 0; i < 4; ++i)
					{
						L2MonsterInstance portrait = _world.portraits[i];
						if (portrait != null)
						{
							portrait.deleteMe();
							_world.portraits[i] = null;
						}
						L2MonsterInstance ghost = _world.ghosts[i];
						if (ghost != null)
						{
							ghost.getSpawn().stopRespawn();
						}
					}
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 402), 100);
					break;
				case 402:
					broadcastPacket(_world, new SpecialCamera(_world.frintezza.getObjectId(), 100, 120, 5, 0, 7000, 0, 0, 1, 0));
					broadcastPacket(_world, new SpecialCamera(_world.frintezza.getObjectId(), 100, 90, 5, 5000, 15000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 403), 7000);
					break;
				case 403:
					broadcastPacket(_world, new SpecialCamera(_world.frintezza.getObjectId(), 900, 90, 25, 7000, 10000, 0, 0, 1, 0));
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 404), 9000);
					break;
				case 404:
					if (ASSERT) if (!(_world.status == 6)) throw new RuntimeException("status=" + _world.status);
					controlStatus(_world);
					startPc();
					ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 405), 10000);
					break;
				case 405:
					startNpc();
					_world.isVideo = false;
					break;
				default:
					if (ASSERT) throw new RuntimeException("_taskId=" + _taskId);
			}
		}
		
		private void stopNpc(L2MonsterInstance npc)/*テスト済*/
		{
			npc.abortAttack();
			npc.abortCast();
			npc.disableAllSkills();
			npc.setTarget(null);
			npc.stopMove(null);
			npc.setIsImmobilized(true);
			if (npc.hasAI()) npc.getAI().setIntention(AI_INTENTION_IDLE);
		}
		
		private void startNpc(L2MonsterInstance npc)/*テスト済*/
		{
			npc.setIsImmobilized(false);
			npc.enableAllSkills();
		}
		
		private void stopNpc()/*テスト済*/
		{
			final int instanceId = _world.instanceId;
			L2ZoneType zone = ZoneManager.getInstance().getZoneById(ROOM3_ZONE);
			
			for (TIntObjectIterator<L2Character> it = zone.getCharactersInside().iterator(); it.hasNext(); )
			{
				it.advance();
				L2Character c = it.value();
				if (c == null || c.getInstanceId() != instanceId || c.isDead() || !c.isVisible())
					continue;
				if (c.isImmobilized()) continue;
				if (c.isAllSkillsDisabled()) continue;
				if (c instanceof L2MonsterInstance)
				{
					L2MonsterInstance monster = (L2MonsterInstance) c;
					stopNpc(monster);
					monster.setBusyMessage("STOP");
				}
			}
		}
		
		private boolean isActiveMinion(L2MonsterInstance npc)/*テスト済*/
		{
			switch (npc.getNpcId())
			{
				case GHOST_FIGHTER:
				case GHOST_MAGE:
				case PORTRAIT_FIGHTER:
				case PORTRAIT_MAGE:
					return true;
				default:
					return false;
			}
		}
		
		private void startNpc()/*テスト済*/
		{
			final int instanceId = _world.instanceId;
			L2ZoneType zone = ZoneManager.getInstance().getZoneById(ROOM3_ZONE);
			
			for (TIntObjectIterator<L2Character> it = zone.getCharactersInside().iterator(); it.hasNext(); )
			{
				it.advance();
				L2Character c = it.value();
				if (c == null || c.getInstanceId() != instanceId || c.isDead() || !c.isVisible())
					continue;
				if (c instanceof L2MonsterInstance)
				{
					L2MonsterInstance monster = (L2MonsterInstance) c;
					if (monster.getBusyMessage() == "STOP" || isActiveMinion(monster))
					{
						monster.setBusyMessage(null);
						startNpc(monster);
					}
				}
			}
		}
		
		private void stopPc()/*テスト済*/
		{
			for (int objId : _world.allowed)
			{
				L2PcInstance player = L2World.getInstance().getPlayer(objId);
				if (player != null && player.isOnline() && player.getInstanceId() == _world.instanceId)
				{
					player.abortAttack();
					player.abortCast();
					player.disableAllSkills();
					player.setTarget(null);
					player.stopMove(null);
					player.setIsImmobilized(true);
					player.getAI().setIntention(AI_INTENTION_IDLE);
				}
			}
		}
		
		private void startPc()/*テスト済*/
		{
			for (int objId : _world.allowed)
			{
				L2PcInstance player = L2World.getInstance().getPlayer(objId);
				if (player != null && player.isOnline() && player.getInstanceId() == _world.instanceId)
				{
					player.enableAllSkills();
					player.setIsImmobilized(false);
				}
			}
		}
		
		private void sendPacketX(L2GameServerPacket packet1, L2GameServerPacket packet2, int x)/*テスト済*/
		{
			for (int objId : _world.allowed)
			{
				L2PcInstance player = L2World.getInstance().getPlayer(objId);
				if (player != null && player.isOnline() && player.getInstanceId() == _world.instanceId)
				{
					if (player.getX() < x)
						player.sendPacket(packet1);
					else
						player.sendPacket(packet2);
				}
			}
		}
	}
	
	private class OnKillHallAlarmTask implements Runnable/*テスト済*/
	{
		private final FETWorld _world;
		private int _taskId;
		
		OnKillHallAlarmTask(FETWorld world)
		{
			_world = world;
			_taskId = 0;
		}
		void scheduleNextTask(int taskId, long delay)
		{
			_taskId = taskId;
			ThreadPoolManager.getInstance().scheduleGeneral(this, delay);
		}
		
		@Override
		public void run()
		{
			if (InstanceManager.getInstance().getWorld(_world.instanceId) != _world)
				return;
			switch (_taskId)
			{
				case 0:
					spawnHallKeepers(_world);
					scheduleNextTask(1, 1000);
					break;
				case 1:
					openDoors(FIRST_ROOM_DOORS, _world.instanceId);
					scheduleNextTask(2, 1000);
					break;
				case 2:
					addAggroToMobs(_world, ROOM1_CENTER_X, ROOM1_CENTER_Y, ROOM1_CENTER_Z);
					break;
			}
		}
		
	}
	
	private class OnKillDarkChoirPlayerTask implements Runnable/*テスト済*/
	{
		private final FETWorld _world;
		private int _taskId;
		
		OnKillDarkChoirPlayerTask(FETWorld world)
		{
			_world = world;
			_taskId = 0;
		}
		void scheduleNextTask(int taskId, long delay)
		{
			_taskId = taskId;
			ThreadPoolManager.getInstance().scheduleGeneral(this, delay);
		}
		
		@Override
		public void run()
		{
			if (InstanceManager.getInstance().getWorld(_world.instanceId) != _world)
				return;
			switch (_taskId)
			{
				case 0:
					closeDoors(SECOND_ROUTE_DOORS, _world.instanceId);
					spawnDarkChoirs(_world);
					scheduleNextTask(1, 1000);
					break;
				case 1:
					openDoors(SECOND_ROOM_DOORS, _world.instanceId);
					scheduleNextTask(2, 1000);
					break;
				case 2:
					for (L2Npc actor : _world.npcList)
						if (actor.getNpcId() == DARK_CHOIR_CAPTAIN)
						{
							// 1010645 黒聖歌団の演奏を妨げる邪魔者を消せ！
							// 1010646 死の演奏が聞こえないのか！黒聖歌団の恐ろしさを見せてやれ！
							// 1010644 黒聖歌団のステージをぶち壊すとは．．．許せぬ！
							int npcstring = Rnd.get(1010644, 1010646);
							actor.broadcastPacket(new NpcSay(actor.getObjectId(), Say2.SHOUT, actor.getNpcId(), npcstring));
							break;
						}
					addAggroToMobs(_world, ROOM2_CENTER_X, ROOM2_CENTER_Y, ROOM2_CENTER_Z);
					break;
			}
		}
		
	}
	
	private void addAggroToMobs(FETWorld _world, int x, int y, int z)/*テスト済*/
	{
		L2PcInstance target = L2World.getInstance().getPlayer(_world.allowed.get(Rnd.get(_world.allowed.size())));
		if (target == null || target.getInstanceId() != _world.instanceId || target.isDead() || target.isFakeDeath())
			for (int objId : _world.allowed)
			{
				target = L2World.getInstance().getPlayer(objId);
				if (target != null && target.getInstanceId() == _world.instanceId && !target.isDead() && !target.isFakeDeath())
					break;
				target = null;
			}
		for (L2Npc mob : _world.npcList)
		{
			if (Util.contains(NO_AGGRO_MOBS, mob.getNpcId()))/*テスト済*/
				continue;
			if (mob.getAI().getIntention() != AI_INTENTION_ACTIVE
			 && mob.getAI().getIntention() != AI_INTENTION_IDLE
			 && mob.isInCombat())
				continue;
			mob.setRunning();
			if (target != null)
			{
				((L2MonsterInstance) mob).addDamageHate(target, 0, 500);
				mob.getAI().setIntention(AI_INTENTION_ATTACK, target);
			}
			else
				mob.getAI().setIntention(AI_INTENTION_MOVE_TO, new L2CharPosition(x, y, z, 0));/*TODO:一点に集中しておだんごになってしまう*/
		}
	}
	
	private void setInstanceTimeRestrictions(FETWorld world)/*テスト済*/
	{
		long now = System.currentTimeMillis();
		GregorianCalendar reenter = new GregorianCalendar();
		reenter.setTimeInMillis(now);
		reenter.set(Calendar.MILLISECOND, 0);
		reenter.set(Calendar.SECOND, 0);
		reenter.set(Calendar.MINUTE, RESET_MINUTE);
		reenter.set(Calendar.HOUR_OF_DAY, RESET_HOUR_OF_DAY);
		// if time is >= RESET_HOUR - roll to the next day
		if (reenter.getTimeInMillis() <= now)
			reenter.add(Calendar.DAY_OF_MONTH, 1);
		while (!Util.contains(RESET_DAY_OF_WEEK, reenter.get(Calendar.DAY_OF_WEEK)))
			reenter.add(Calendar.DAY_OF_MONTH, 1);
		
		SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.INSTANT_ZONE_S1_RESTRICTED);
		sm.addInstanceName(INSTANCEID);
		
		// set instance reenter time for all allowed players
		for (int objectId : world.allowed)
		{
			L2PcInstance player = L2World.getInstance().getPlayer(objectId);
			InstanceManager.getInstance().setInstanceTime(objectId, INSTANCEID, reenter.getTimeInMillis());
			if (player != null && player.isOnline())
				player.sendPacket(sm);
		}
	}
	
	private void broadcastPacket(FETWorld world, L2GameServerPacket packet)
	{
		for (int objId : world.allowed)
		{
			L2PcInstance player = L2World.getInstance().getPlayer(objId);
			if (player != null && player.isOnline() && player.getInstanceId() == world.instanceId)
				player.sendPacket(packet);
		}
	}
	private void broadcastSongTitle(FETWorld world, NpcStringId song)/*テスト済*/
	{
		broadcastPacket(world, new ExShowScreenMessage(/*type=*/2, /*messageId=*/-1, /*position=*/2, /*unk1=*/0, /*size=*/0, /*unk2=*/0, /*unk3=*/0, /*showEffect=*/true, /*time=*/3000, /*fade=*/false, /*text=*/null, song));
	}
	
	private void updateKnownList(FETWorld world, L2Npc npc)
	{
		Map<Integer, L2PcInstance> npcKnownPlayers = npc.getKnownList().getKnownPlayers();
		for (int objId : world.allowed)
		{
			L2PcInstance player = L2World.getInstance().getPlayer(objId);
			if (player != null && player.isOnline() && player.getInstanceId() == world.instanceId)
				npcKnownPlayers.put(player.getObjectId(), player);
		}
	}
	
	private void throwUp(L2Character attacker, final double range, SystemMessage msg)/*テスト済*/
	{
		final int mx = attacker.getX(), my = attacker.getY();
		for (L2Object obj : attacker.getKnownList().getKnownObjects().values())
		{
			if (!(obj instanceof L2Character))
				continue;
			L2Character target = (L2Character)obj;
			if (obj == attacker || isFrintezzaFriend(target))
				continue;
			double dx = target.getX() - mx;
			double dy = target.getY() - my;
			if (dx == 0 && dy == 0) dx = dy = range / 2;
			double aa = range / Math.sqrt(dx * dx + dy * dy);
			if (aa > 1.0)
			{
				int x = mx + (int)(dx * aa);
				int y = my + (int)(dy * aa);
				int z = target.getZ();
				
				target.getAI().setIntention(AI_INTENTION_IDLE);
				target.abortAttack();
				target.abortCast();
				
				target.broadcastPacket(new FlyToLocation(target, x, y, z, FlyType.THROW_UP));
				target.setXYZ(x, y, z);
				target.setHeading(Util.calculateHeadingFrom(x, y, mx, my));
				target.broadcastPacket(new ValidateLocation(target));
				if (msg != null) target.sendPacket(msg);
				if (target instanceof L2PcInstance) ((L2PcInstance)target).standUp();
			}
		}
	}
	
	private boolean isFrintezzaFriend(L2Object target)/*テスト済*/
	{
		if (target instanceof L2Npc)
		{
			int npcId = ((L2Npc)target).getNpcId();
			return npcId >= 29045 && npcId <= 29053;
		}
		return false;
	}
	
	@Override
	public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isPet, L2Skill skill)
	{
		InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(npc.getInstanceId());
		if (tmpworld instanceof FETWorld)
		{
			FETWorld world = (FETWorld) tmpworld;
			if (DETECT_ACTION_LOCK) world.lastAction = System.currentTimeMillis();
			switch (npc.getNpcId())
			{
			case FRINTEZZA:
				if (!npc.isDead() && npc.isVisible())
					npc.getStatus().setCurrentHp(npc.getMaxHp(), false);	//TODO: npc.sql側で調整できないか
				break;
			case SCARLET1:
				if (world.status == 3 && npc.getCurrentHp() < npc.getMaxHp() * 0.80)/*テスト済*/
				{
					controlStatus(world);
				}
				else if (world.status == 4 && npc.getCurrentHp() < npc.getMaxHp() * 0.20)/*テスト済*/
				{
					controlStatus(world);
				}
				break;
			}
		}
		return null;
	}
	
	@Override
	public String onSkillSee(L2Npc npc, L2PcInstance player, L2Skill skill, L2Object[] targets, boolean isPet)
	{
		InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(npc.getInstanceId());
		if (tmpworld instanceof FETWorld)
		{
			FETWorld world = (FETWorld) tmpworld;
			if (DETECT_ACTION_LOCK) world.lastAction = System.currentTimeMillis();
			if (npc == world.frintezza && !npc.isDead() && npc.isVisible())
				npc.getStatus().setCurrentHp(npc.getMaxHp(), false);	//TODO: npc.sql側で調整できないか
			if (targets.length > 0 && targets[0] == npc && npc == world.frintezza)
			{
				// skill 2234 Soul Breaking Arrow ...
				if (isZZZ(npc) && isZZZ(skill))
					broadcastPacket(world, new MagicSkillCanceld(npc.getObjectId()));
			}
		}
		return super.onSkillSee(npc, player, skill, targets, isPet);
	}
	
	@Override
	public String onSpellFinished(L2Npc npc, L2PcInstance player, L2Skill skill)/*テスト済*/
	{
		if (skill.isSuicideAttack())
			return onKill(npc, null, false);
		return super.onSpellFinished(npc, player, skill);
	}
	
	@Override
	public String onKill(L2Npc npc, L2PcInstance player, boolean isPet)
	{
		InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(npc.getInstanceId());
		if (tmpworld instanceof FETWorld)
		{
			FETWorld world = (FETWorld) tmpworld;
			if (DETECT_ACTION_LOCK) world.lastAction = System.currentTimeMillis();
			switch (npc.getNpcId())
			{
				case HALL_ALARM:/*テスト済*/
					if (ASSERT) if (!(world.status == 1)) throw new RuntimeException("status=" + world.status);
					new OnKillHallAlarmTask(world).run();
				//	if (Rnd.get(100) < 33)
				//		player.addItem("Quest", DEWDROP_OF_DESTRUCTION, 1, npc, true);	// Dewdrop of Destruction
					if (DEBUG)
						_log.info("[Final Emperial Tomb] Hall alarm is disabled, doors will open!");
					break;
					
				case DARK_CHOIR_PLAYER:/*テスト済*/
					if (ASSERT) if (!(world.status >= 2)) throw new RuntimeException("status=" + world.status);
					// note: world.status は変化しない.ドアの開閉のみ制御する.
					/*if (world.status == 2)*/
					{
						final int count;
						synchronized (world)
						{
							count = --world.darkChoirPlayerCount;
						}
						if (count == 0)
						{
							new OnKillDarkChoirPlayerTask(world).run();
							if (DEBUG)
								_log.info("[Final Emperial Tomb] All Dark Choir Players are killed, doors will open!");
						}
					}
					break;
					
				default:
					if (world.status == 1)
					{
						// 1st room - Hall Keepers /*テスト済*/
						final boolean done;
						synchronized (world)
						{
							done = world.npcList.remove(npc) && world.npcList.size() == 0;
						}
						if (done)
						{
							controlStatus(world);
							openDoors(FIRST_ROUTE_DOORS, world.instanceId);
							openDoors(SECOND_ROUTE_DOORS, world.instanceId);
						}
						
						if (player != null && Rnd.get(world.npcMax) < 3)
							player.addItem("Quest", DEWDROP_OF_DESTRUCTION, 1, npc, true);	// Dewdrop of Destruction
					}
					else /*if (world.status == 2)*/
					{
						// 2nd room - Dark Choirs/*テスト済*/
						final boolean done;
						synchronized (world)
						{
							done = world.npcList.remove(npc) && world.npcList.size() == 0;
						}
						if (done)
						{
							openDoors(SECOND_ROUTE_DOORS, world.instanceId);
						}
						
						if (player != null && Rnd.get(world.npcMax) < 5)
							player.addItem("Quest", SOUL_BREAKING_ARROW, 1, npc, true);	// Soul Breaking Arrow
						
						if (npc.getNpcId() == DARK_CHOIR_CAPTAIN)
						{
							// 1010645 黒聖歌団の演奏を妨げる邪魔者を消せ！
							// 1010646 死の演奏が聞こえないのか！黒聖歌団の恐ろしさを見せてやれ！
							// 1010644 黒聖歌団のステージをぶち壊すとは．．．許せぬ！
							int npcstring = Rnd.get(1010644, 1010646);
							npc.broadcastPacket(new NpcSay(npc.getObjectId(), Say2.SHOUT, npc.getNpcId(), npcstring));
						}
					}
					break;
					
				case SCARLET1:/*テスト済*/
					if (ASSERT) if (!(world.status == 3 || world.status == 4)) throw new RuntimeException("status=" + world.status);
					world.status = 5;
					controlStatus(world);
					break;
					
				case SCARLET2:/*テスト済*/
					if (ASSERT) if (!(world.status == 5)) throw new RuntimeException("status=" + world.status);
					controlStatus(world);
					break;
					
				case PORTRAIT_FIGHTER:/*テスト済*/
				case PORTRAIT_MAGE:/*テスト済*/
					for (int i = 0; i < 4; ++i)
					{
						if (npc == world.portraits[i])
						{
							L2MonsterInstance ghost = world.ghosts[i];
							ghost.getSpawn().stopRespawn();
							world.portraits[i] = null;
							return null;
						}
					}
					if (ASSERT) throw new RuntimeException();
					else break;
			}
		}
		return "";
	}
	
//	@Override
//	public String onDeath(L2Character killer, L2Character victim, QuestState qs)
//	{
//		TRACE("onDeath("+STR(killer)+","+STR(victim)+","+(qs == null ? "NULL" : qs.getQuest() == null ? "NUL" : qs.getQuest().getName())+")");
//		TODO: キャラクターが死亡して○○分以内に復活しないと場外にとばされてしまう
//		return super.onDeath(killer, victim, qs);
//	}
	
	@Override
	public String onEnterZone(L2Character character, L2ZoneType zone)/*テスト済*/
	{
		if (character instanceof L2PcInstance)
		{
			if (ASSERT) if (!(zone.getId() == ROOM3_ZONE)) throw new RuntimeException();
			InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(character.getInstanceId());
			if (tmpworld instanceof FETWorld)
			{
				FETWorld world = (FETWorld) tmpworld;
				if (world.status == 2)
					controlStatus(world);
			}
		}
		return super.onEnterZone(character, zone);
	}
	
	@Override
	public String onTalk(L2Npc npc, L2PcInstance player)
	{
		QuestState st = player.getQuestState(qn);
		if (st == null)
			st = newQuestState(player);
		switch (npc.getNpcId())
		{
			case GUIDE:
				enterInstance(player, "FinalEmperialTomb.xml", ENTER_TELEPORT);
				break;
			case CUBE:
				player.teleToLocation(-87784 + Rnd.get(-250, 250), -153298 + Rnd.get(-250, 250), -9175);
				return null;
		}
		return "";
	}
	
	public FinalEmperialTomb(int questId, String name, String descr)
	{
		super(questId, name, descr);
		
		addStartNpc(GUIDE);
		addTalkId(GUIDE);
		addStartNpc(CUBE);
		addTalkId(CUBE);
		addKillId(HALL_ALARM);
		addKillId(DARK_CHOIR_PLAYER);
		addSkillSeeId(FRINTEZZA);
		addAttackId(FRINTEZZA);
		addAttackId(SCARLET1);
		addKillId(SCARLET1);
		addKillId(SCARLET2);
		addKillId(PORTRAIT_FIGHTER);
		addKillId(PORTRAIT_MAGE);
		addEnterZoneId(ROOM3_ZONE);
		if (ASSERT) if (!(ZoneManager.getInstance().getZoneById(ROOM3_ZONE) != null)) throw new RuntimeException();	//<zone id="12911" type="ScriptZone" shape="Cuboid" ... />
	}
	
	public static void main(String[] args)
	{
		// now call the constructor (starts up the)
		new FinalEmperialTomb(-1, qn, "instances");
	}
}