FinalEmperialTomb.java 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465
  1. /*
  2. * Copyright (C) 2004-2015 L2J DataPack
  3. *
  4. * This file is part of L2J DataPack.
  5. *
  6. * L2J DataPack is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * L2J DataPack is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. package instances.FinalEmperialTomb;
  20. import instances.AbstractInstance;
  21. import java.io.File;
  22. import java.util.ArrayList;
  23. import java.util.HashMap;
  24. import java.util.List;
  25. import java.util.Map;
  26. import java.util.concurrent.ConcurrentHashMap;
  27. import java.util.concurrent.CopyOnWriteArrayList;
  28. import java.util.concurrent.ScheduledFuture;
  29. import java.util.concurrent.locks.Lock;
  30. import java.util.concurrent.locks.ReentrantLock;
  31. import java.util.logging.Level;
  32. import javax.xml.parsers.DocumentBuilderFactory;
  33. import org.w3c.dom.Document;
  34. import org.w3c.dom.NamedNodeMap;
  35. import org.w3c.dom.Node;
  36. import com.l2jserver.Config;
  37. import com.l2jserver.gameserver.GeoData;
  38. import com.l2jserver.gameserver.ThreadPoolManager;
  39. import com.l2jserver.gameserver.ai.CtrlIntention;
  40. import com.l2jserver.gameserver.enums.InstanceType;
  41. import com.l2jserver.gameserver.instancemanager.InstanceManager;
  42. import com.l2jserver.gameserver.model.L2CommandChannel;
  43. import com.l2jserver.gameserver.model.L2Party;
  44. import com.l2jserver.gameserver.model.L2Territory;
  45. import com.l2jserver.gameserver.model.L2World;
  46. import com.l2jserver.gameserver.model.Location;
  47. import com.l2jserver.gameserver.model.PcCondOverride;
  48. import com.l2jserver.gameserver.model.actor.L2Attackable;
  49. import com.l2jserver.gameserver.model.actor.L2Character;
  50. import com.l2jserver.gameserver.model.actor.L2Npc;
  51. import com.l2jserver.gameserver.model.actor.instance.L2GrandBossInstance;
  52. import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
  53. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  54. import com.l2jserver.gameserver.model.effects.L2EffectType;
  55. import com.l2jserver.gameserver.model.holders.SkillHolder;
  56. import com.l2jserver.gameserver.model.instancezone.InstanceWorld;
  57. import com.l2jserver.gameserver.model.skills.Skill;
  58. import com.l2jserver.gameserver.network.NpcStringId;
  59. import com.l2jserver.gameserver.network.SystemMessageId;
  60. import com.l2jserver.gameserver.network.serverpackets.AbstractNpcInfo.NpcInfo;
  61. import com.l2jserver.gameserver.network.serverpackets.Earthquake;
  62. import com.l2jserver.gameserver.network.serverpackets.ExShowScreenMessage;
  63. import com.l2jserver.gameserver.network.serverpackets.L2GameServerPacket;
  64. import com.l2jserver.gameserver.network.serverpackets.MagicSkillCanceld;
  65. import com.l2jserver.gameserver.network.serverpackets.MagicSkillUse;
  66. import com.l2jserver.gameserver.network.serverpackets.SocialAction;
  67. import com.l2jserver.gameserver.network.serverpackets.SpecialCamera;
  68. import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
  69. import com.l2jserver.gameserver.util.Util;
  70. /**
  71. * Final Emperial Tomb instance zone. TODO:<br>
  72. * Test when Frintezza song use 5008 effect skill.<br>
  73. * Test deeply Scarlet van Halisha's AI.<br>
  74. * Use proper zone spawn system.
  75. * @author Gigiikun
  76. */
  77. public final class FinalEmperialTomb extends AbstractInstance
  78. {
  79. protected class FETWorld extends InstanceWorld
  80. {
  81. protected Lock lock = new ReentrantLock();
  82. protected List<L2Npc> npcList = new CopyOnWriteArrayList<>();
  83. protected int darkChoirPlayerCount = 0;
  84. protected FrintezzaSong OnSong = null;
  85. protected ScheduledFuture<?> songTask = null;
  86. protected ScheduledFuture<?> songEffectTask = null;
  87. protected boolean isVideo = false;
  88. protected L2Npc frintezzaDummy = null;
  89. protected L2Npc overheadDummy = null;
  90. protected L2Npc portraitDummy1 = null;
  91. protected L2Npc portraitDummy3 = null;
  92. protected L2Npc scarletDummy = null;
  93. protected L2GrandBossInstance frintezza = null;
  94. protected L2GrandBossInstance activeScarlet = null;
  95. protected List<L2MonsterInstance> demons = new CopyOnWriteArrayList<>();
  96. protected Map<L2MonsterInstance, Integer> portraits = new ConcurrentHashMap<>();
  97. protected int scarlet_x = 0;
  98. protected int scarlet_y = 0;
  99. protected int scarlet_z = 0;
  100. protected int scarlet_h = 0;
  101. protected int scarlet_a = 0;
  102. }
  103. protected static class FETSpawn
  104. {
  105. public boolean isZone = false;
  106. public boolean isNeededNextFlag = false;
  107. public int npcId;
  108. public int x = 0;
  109. public int y = 0;
  110. public int z = 0;
  111. public int h = 0;
  112. public int zone = 0;
  113. public int count = 0;
  114. }
  115. private static class FrintezzaSong
  116. {
  117. public SkillHolder skill;
  118. public SkillHolder effectSkill;
  119. public NpcStringId songName;
  120. public int chance;
  121. public FrintezzaSong(SkillHolder sk, SkillHolder esk, NpcStringId sn, int ch)
  122. {
  123. skill = sk;
  124. effectSkill = esk;
  125. songName = sn;
  126. chance = ch;
  127. }
  128. }
  129. // NPCs
  130. private static final int GUIDE = 32011;
  131. private static final int CUBE = 29061;
  132. private static final int SCARLET1 = 29046;
  133. private static final int SCARLET2 = 29047;
  134. private static final int FRINTEZZA = 29045;
  135. private static final int[] PORTRAITS =
  136. {
  137. 29048,
  138. 29049
  139. };
  140. private static final int[] DEMONS =
  141. {
  142. 29050,
  143. 29051
  144. };
  145. private static final int HALL_ALARM = 18328;
  146. private static final int HALL_KEEPER_CAPTAIN = 18329;
  147. // Items
  148. private static final int HALL_KEEPER_SUICIDAL_SOLDIER = 18333;
  149. private static final int DARK_CHOIR_PLAYER = 18339;
  150. private static final int[] AI_DISABLED_MOBS =
  151. {
  152. 18328
  153. };
  154. private static final int DEWDROP_OF_DESTRUCTION_ITEM_ID = 8556;
  155. private static final int FIRST_SCARLET_WEAPON = 8204;
  156. private static final int SECOND_SCARLET_WEAPON = 7903;
  157. // Skills
  158. private static final int DEWDROP_OF_DESTRUCTION_SKILL_ID = 2276;
  159. private static final int SOUL_BREAKING_ARROW_SKILL_ID = 2234;
  160. protected static final SkillHolder INTRO_SKILL = new SkillHolder(5004, 1);
  161. private static final SkillHolder FIRST_MORPH_SKILL = new SkillHolder(5017, 1);
  162. protected static final FrintezzaSong[] FRINTEZZASONGLIST =
  163. {
  164. new FrintezzaSong(new SkillHolder(5007, 1), new SkillHolder(5008, 1), NpcStringId.REQUIEM_OF_HATRED, 5),
  165. new FrintezzaSong(new SkillHolder(5007, 2), new SkillHolder(5008, 2), NpcStringId.RONDO_OF_SOLITUDE, 50),
  166. new FrintezzaSong(new SkillHolder(5007, 3), new SkillHolder(5008, 3), NpcStringId.FRENETIC_TOCCATA, 70),
  167. new FrintezzaSong(new SkillHolder(5007, 4), new SkillHolder(5008, 4), NpcStringId.FUGUE_OF_JUBILATION, 90),
  168. new FrintezzaSong(new SkillHolder(5007, 5), new SkillHolder(5008, 5), NpcStringId.HYPNOTIC_MAZURKA, 100),
  169. };
  170. // Locations
  171. private static final Location ENTER_TELEPORT = new Location(-88015, -141153, -9168);
  172. protected static final Location MOVE_TO_CENTER = new Location(-87904, -141296, -9168, 0);
  173. // Misc
  174. private static final int TEMPLATE_ID = 136; // this is the client number
  175. private static final int MIN_PLAYERS = 36;
  176. private static final int MAX_PLAYERS = 45;
  177. private static final int TIME_BETWEEN_DEMON_SPAWNS = 20000;
  178. private static final int MAX_DEMONS = 24;
  179. private static final boolean debug = false;
  180. private final Map<Integer, L2Territory> _spawnZoneList = new HashMap<>();
  181. private final Map<Integer, List<FETSpawn>> _spawnList = new HashMap<>();
  182. private final List<Integer> _mustKillMobsId = new ArrayList<>();
  183. protected static final int[] FIRST_ROOM_DOORS =
  184. {
  185. 17130051,
  186. 17130052,
  187. 17130053,
  188. 17130054,
  189. 17130055,
  190. 17130056,
  191. 17130057,
  192. 17130058
  193. };
  194. protected static final int[] SECOND_ROOM_DOORS =
  195. {
  196. 17130061,
  197. 17130062,
  198. 17130063,
  199. 17130064,
  200. 17130065,
  201. 17130066,
  202. 17130067,
  203. 17130068,
  204. 17130069,
  205. 17130070
  206. };
  207. protected static final int[] FIRST_ROUTE_DOORS =
  208. {
  209. 17130042,
  210. 17130043
  211. };
  212. protected static final int[] SECOND_ROUTE_DOORS =
  213. {
  214. 17130045,
  215. 17130046
  216. };
  217. // @formatter:off
  218. protected static final int[][] PORTRAIT_SPAWNS =
  219. {
  220. {29048, -89381, -153981, -9168, 3368, -89378, -153968, -9168, 3368},
  221. {29048, -86234, -152467, -9168, 37656, -86261, -152492, -9168, 37656},
  222. {29049, -89342, -152479, -9168, -5152, -89311, -152491, -9168, -5152},
  223. {29049, -86189, -153968, -9168, 29456, -86217, -153956, -9168, 29456},
  224. };
  225. // @formatter:on
  226. public FinalEmperialTomb()
  227. {
  228. super(FinalEmperialTomb.class.getSimpleName());
  229. load();
  230. addAttackId(SCARLET1, FRINTEZZA);
  231. addAttackId(PORTRAITS);
  232. addStartNpc(GUIDE, CUBE);
  233. addTalkId(GUIDE, CUBE);
  234. addKillId(HALL_ALARM, HALL_KEEPER_CAPTAIN, DARK_CHOIR_PLAYER, SCARLET2);
  235. addKillId(PORTRAITS);
  236. addKillId(DEMONS);
  237. addKillId(_mustKillMobsId);
  238. addSpellFinishedId(HALL_KEEPER_SUICIDAL_SOLDIER);
  239. }
  240. private void load()
  241. {
  242. @SuppressWarnings("unused")
  243. int spawnCount = 0;
  244. try
  245. {
  246. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  247. factory.setValidating(false);
  248. factory.setIgnoringComments(true);
  249. File file = new File(Config.DATAPACK_ROOT + "/data/spawnZones/final_emperial_tomb.xml");
  250. if (!file.exists())
  251. {
  252. _log.severe("[Final Emperial Tomb] Missing final_emperial_tomb.xml. The quest wont work without it!");
  253. return;
  254. }
  255. Document doc = factory.newDocumentBuilder().parse(file);
  256. Node first = doc.getFirstChild();
  257. if ((first != null) && "list".equalsIgnoreCase(first.getNodeName()))
  258. {
  259. for (Node n = first.getFirstChild(); n != null; n = n.getNextSibling())
  260. {
  261. if ("npc".equalsIgnoreCase(n.getNodeName()))
  262. {
  263. for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
  264. {
  265. if ("spawn".equalsIgnoreCase(d.getNodeName()))
  266. {
  267. NamedNodeMap attrs = d.getAttributes();
  268. Node att = attrs.getNamedItem("npcId");
  269. if (att == null)
  270. {
  271. _log.severe("[Final Emperial Tomb] Missing npcId in npc List, skipping");
  272. continue;
  273. }
  274. int npcId = Integer.parseInt(attrs.getNamedItem("npcId").getNodeValue());
  275. att = attrs.getNamedItem("flag");
  276. if (att == null)
  277. {
  278. _log.severe("[Final Emperial Tomb] Missing flag in npc List npcId: " + npcId + ", skipping");
  279. continue;
  280. }
  281. int flag = Integer.parseInt(attrs.getNamedItem("flag").getNodeValue());
  282. _spawnList.putIfAbsent(flag, new ArrayList<FETSpawn>());
  283. for (Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling())
  284. {
  285. if ("loc".equalsIgnoreCase(cd.getNodeName()))
  286. {
  287. attrs = cd.getAttributes();
  288. FETSpawn spw = new FETSpawn();
  289. spw.npcId = npcId;
  290. att = attrs.getNamedItem("x");
  291. if (att != null)
  292. {
  293. spw.x = Integer.parseInt(att.getNodeValue());
  294. }
  295. else
  296. {
  297. continue;
  298. }
  299. att = attrs.getNamedItem("y");
  300. if (att != null)
  301. {
  302. spw.y = Integer.parseInt(att.getNodeValue());
  303. }
  304. else
  305. {
  306. continue;
  307. }
  308. att = attrs.getNamedItem("z");
  309. if (att != null)
  310. {
  311. spw.z = Integer.parseInt(att.getNodeValue());
  312. }
  313. else
  314. {
  315. continue;
  316. }
  317. att = attrs.getNamedItem("heading");
  318. if (att != null)
  319. {
  320. spw.h = Integer.parseInt(att.getNodeValue());
  321. }
  322. else
  323. {
  324. continue;
  325. }
  326. att = attrs.getNamedItem("mustKill");
  327. if (att != null)
  328. {
  329. spw.isNeededNextFlag = Boolean.parseBoolean(att.getNodeValue());
  330. }
  331. if (spw.isNeededNextFlag)
  332. {
  333. _mustKillMobsId.add(npcId);
  334. }
  335. _spawnList.get(flag).add(spw);
  336. spawnCount++;
  337. }
  338. else if ("zone".equalsIgnoreCase(cd.getNodeName()))
  339. {
  340. attrs = cd.getAttributes();
  341. FETSpawn spw = new FETSpawn();
  342. spw.npcId = npcId;
  343. spw.isZone = true;
  344. att = attrs.getNamedItem("id");
  345. if (att != null)
  346. {
  347. spw.zone = Integer.parseInt(att.getNodeValue());
  348. }
  349. else
  350. {
  351. continue;
  352. }
  353. att = attrs.getNamedItem("count");
  354. if (att != null)
  355. {
  356. spw.count = Integer.parseInt(att.getNodeValue());
  357. }
  358. else
  359. {
  360. continue;
  361. }
  362. att = attrs.getNamedItem("mustKill");
  363. if (att != null)
  364. {
  365. spw.isNeededNextFlag = Boolean.parseBoolean(att.getNodeValue());
  366. }
  367. if (spw.isNeededNextFlag)
  368. {
  369. _mustKillMobsId.add(npcId);
  370. }
  371. _spawnList.get(flag).add(spw);
  372. spawnCount++;
  373. }
  374. }
  375. }
  376. }
  377. }
  378. else if ("spawnZones".equalsIgnoreCase(n.getNodeName()))
  379. {
  380. for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
  381. {
  382. if ("zone".equalsIgnoreCase(d.getNodeName()))
  383. {
  384. NamedNodeMap attrs = d.getAttributes();
  385. Node att = attrs.getNamedItem("id");
  386. if (att == null)
  387. {
  388. _log.severe("[Final Emperial Tomb] Missing id in spawnZones List, skipping");
  389. continue;
  390. }
  391. int id = Integer.parseInt(att.getNodeValue());
  392. att = attrs.getNamedItem("minZ");
  393. if (att == null)
  394. {
  395. _log.severe("[Final Emperial Tomb] Missing minZ in spawnZones List id: " + id + ", skipping");
  396. continue;
  397. }
  398. int minz = Integer.parseInt(att.getNodeValue());
  399. att = attrs.getNamedItem("maxZ");
  400. if (att == null)
  401. {
  402. _log.severe("[Final Emperial Tomb] Missing maxZ in spawnZones List id: " + id + ", skipping");
  403. continue;
  404. }
  405. int maxz = Integer.parseInt(att.getNodeValue());
  406. L2Territory ter = new L2Territory(id);
  407. for (Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling())
  408. {
  409. if ("point".equalsIgnoreCase(cd.getNodeName()))
  410. {
  411. attrs = cd.getAttributes();
  412. int x, y;
  413. att = attrs.getNamedItem("x");
  414. if (att != null)
  415. {
  416. x = Integer.parseInt(att.getNodeValue());
  417. }
  418. else
  419. {
  420. continue;
  421. }
  422. att = attrs.getNamedItem("y");
  423. if (att != null)
  424. {
  425. y = Integer.parseInt(att.getNodeValue());
  426. }
  427. else
  428. {
  429. continue;
  430. }
  431. ter.add(x, y, minz, maxz, 0);
  432. }
  433. }
  434. _spawnZoneList.put(id, ter);
  435. }
  436. }
  437. }
  438. }
  439. }
  440. }
  441. catch (Exception e)
  442. {
  443. _log.log(Level.WARNING, "[Final Emperial Tomb] Could not parse final_emperial_tomb.xml file: " + e.getMessage(), e);
  444. }
  445. if (debug)
  446. {
  447. _log.info("[Final Emperial Tomb] Loaded " + _spawnZoneList.size() + " spawn zones data.");
  448. _log.info("[Final Emperial Tomb] Loaded " + spawnCount + " spawns data.");
  449. }
  450. }
  451. @Override
  452. protected boolean checkConditions(L2PcInstance player)
  453. {
  454. if (debug || player.canOverrideCond(PcCondOverride.INSTANCE_CONDITIONS))
  455. {
  456. return true;
  457. }
  458. final L2Party party = player.getParty();
  459. if (party == null)
  460. {
  461. player.sendPacket(SystemMessageId.NOT_IN_PARTY_CANT_ENTER);
  462. return false;
  463. }
  464. final L2CommandChannel channel = player.getParty().getCommandChannel();
  465. if (channel == null)
  466. {
  467. player.sendPacket(SystemMessageId.NOT_IN_COMMAND_CHANNEL_CANT_ENTER);
  468. return false;
  469. }
  470. else if (channel.getLeader() != player)
  471. {
  472. player.sendPacket(SystemMessageId.ONLY_PARTY_LEADER_CAN_ENTER);
  473. return false;
  474. }
  475. else if (player.getInventory().getItemByItemId(8073) == null)
  476. {
  477. SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_ITEM_REQUIREMENT_NOT_SUFFICIENT);
  478. sm.addPcName(player);
  479. player.sendPacket(sm);
  480. return false;
  481. }
  482. else if ((channel.getMemberCount() < MIN_PLAYERS) || (channel.getMemberCount() > MAX_PLAYERS))
  483. {
  484. player.sendPacket(SystemMessageId.PARTY_EXCEEDED_THE_LIMIT_CANT_ENTER);
  485. return false;
  486. }
  487. for (L2PcInstance channelMember : channel.getMembers())
  488. {
  489. if (channelMember.getLevel() < 80)
  490. {
  491. party.broadcastPacket(SystemMessage.getSystemMessage(SystemMessageId.C1_S_LEVEL_REQUIREMENT_IS_NOT_SUFFICIENT_AND_CANNOT_BE_ENTERED).addPcName(channelMember));
  492. return false;
  493. }
  494. if (!Util.checkIfInRange(1000, player, channelMember, true))
  495. {
  496. party.broadcastPacket(SystemMessage.getSystemMessage(SystemMessageId.C1_IS_IN_A_LOCATION_WHICH_CANNOT_BE_ENTERED_THEREFORE_IT_CANNOT_BE_PROCESSED).addPcName(channelMember));
  497. return false;
  498. }
  499. final Long reentertime = InstanceManager.getInstance().getInstanceTime(channelMember.getObjectId(), TEMPLATE_ID);
  500. if (System.currentTimeMillis() < reentertime)
  501. {
  502. party.broadcastPacket(SystemMessage.getSystemMessage(SystemMessageId.C1_MAY_NOT_RE_ENTER_YET).addPcName(channelMember));
  503. return false;
  504. }
  505. }
  506. return true;
  507. }
  508. @Override
  509. public void onEnterInstance(L2PcInstance player, InstanceWorld world, boolean firstEntrance)
  510. {
  511. if (firstEntrance)
  512. {
  513. controlStatus((FETWorld) world);
  514. if ((player.getParty() == null) || (player.getParty().getCommandChannel() == null))
  515. {
  516. player.destroyItemByItemId(getName(), DEWDROP_OF_DESTRUCTION_ITEM_ID, player.getInventory().getInventoryItemCount(DEWDROP_OF_DESTRUCTION_ITEM_ID, -1), null, true);
  517. world.addAllowed(player.getObjectId());
  518. teleportPlayer(player, ENTER_TELEPORT, world.getInstanceId(), false);
  519. }
  520. else
  521. {
  522. for (L2PcInstance channelMember : player.getParty().getCommandChannel().getMembers())
  523. {
  524. channelMember.destroyItemByItemId(getName(), DEWDROP_OF_DESTRUCTION_ITEM_ID, channelMember.getInventory().getInventoryItemCount(DEWDROP_OF_DESTRUCTION_ITEM_ID, -1), null, true);
  525. world.addAllowed(channelMember.getObjectId());
  526. teleportPlayer(channelMember, ENTER_TELEPORT, world.getInstanceId(), false);
  527. }
  528. }
  529. }
  530. else
  531. {
  532. teleportPlayer(player, ENTER_TELEPORT, world.getInstanceId(), false);
  533. }
  534. }
  535. protected boolean checkKillProgress(L2Npc mob, FETWorld world)
  536. {
  537. if (world.npcList.contains(mob))
  538. {
  539. world.npcList.remove(mob);
  540. }
  541. return world.npcList.isEmpty();
  542. }
  543. private void spawnFlaggedNPCs(FETWorld world, int flag)
  544. {
  545. if (world.lock.tryLock())
  546. {
  547. try
  548. {
  549. for (FETSpawn spw : _spawnList.get(flag))
  550. {
  551. if (spw.isZone)
  552. {
  553. for (int i = 0; i < spw.count; i++)
  554. {
  555. if (_spawnZoneList.containsKey(spw.zone))
  556. {
  557. final Location location = _spawnZoneList.get(spw.zone).getRandomPoint();
  558. if (location != null)
  559. {
  560. spawn(world, spw.npcId, location.getX(), location.getY(), GeoData.getInstance().getSpawnHeight(location), getRandom(65535), spw.isNeededNextFlag);
  561. }
  562. }
  563. else
  564. {
  565. _log.info("[Final Emperial Tomb] Missing zone: " + spw.zone);
  566. }
  567. }
  568. }
  569. else
  570. {
  571. spawn(world, spw.npcId, spw.x, spw.y, spw.z, spw.h, spw.isNeededNextFlag);
  572. }
  573. }
  574. }
  575. finally
  576. {
  577. world.lock.unlock();
  578. }
  579. }
  580. }
  581. protected boolean controlStatus(FETWorld world)
  582. {
  583. if (world.lock.tryLock())
  584. {
  585. try
  586. {
  587. if (debug)
  588. {
  589. _log.info("[Final Emperial Tomb] Starting " + world.getStatus() + ". status.");
  590. }
  591. world.npcList.clear();
  592. switch (world.getStatus())
  593. {
  594. case 0:
  595. spawnFlaggedNPCs(world, 0);
  596. break;
  597. case 1:
  598. for (int doorId : FIRST_ROUTE_DOORS)
  599. {
  600. openDoor(doorId, world.getInstanceId());
  601. }
  602. spawnFlaggedNPCs(world, world.getStatus());
  603. break;
  604. case 2:
  605. for (int doorId : SECOND_ROUTE_DOORS)
  606. {
  607. openDoor(doorId, world.getInstanceId());
  608. }
  609. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(world, 0), 600000);
  610. break;
  611. case 3: // first morph
  612. if (world.songEffectTask != null)
  613. {
  614. world.songEffectTask.cancel(false);
  615. }
  616. world.songEffectTask = null;
  617. world.activeScarlet.setIsInvul(true);
  618. if (world.activeScarlet.isCastingNow())
  619. {
  620. world.activeScarlet.abortCast();
  621. }
  622. handleReenterTime(world);
  623. world.activeScarlet.doCast(FIRST_MORPH_SKILL.getSkill());
  624. ThreadPoolManager.getInstance().scheduleGeneral(new SongTask(world, 2), 1500);
  625. break;
  626. case 4: // second morph
  627. world.isVideo = true;
  628. broadCastPacket(world, new MagicSkillCanceld(world.frintezza.getObjectId()));
  629. if (world.songEffectTask != null)
  630. {
  631. world.songEffectTask.cancel(false);
  632. }
  633. world.songEffectTask = null;
  634. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(world, 23), 2000);
  635. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(world, 24), 2100);
  636. break;
  637. case 5: // raid success
  638. world.isVideo = true;
  639. broadCastPacket(world, new MagicSkillCanceld(world.frintezza.getObjectId()));
  640. if (world.songTask != null)
  641. {
  642. world.songTask.cancel(true);
  643. }
  644. if (world.songEffectTask != null)
  645. {
  646. world.songEffectTask.cancel(false);
  647. }
  648. world.songTask = null;
  649. world.songEffectTask = null;
  650. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(world, 33), 500);
  651. break;
  652. case 6: // open doors
  653. InstanceManager.getInstance().getInstance(world.getInstanceId()).setDuration(300000);
  654. for (int doorId : FIRST_ROOM_DOORS)
  655. {
  656. openDoor(doorId, world.getInstanceId());
  657. }
  658. for (int doorId : FIRST_ROUTE_DOORS)
  659. {
  660. openDoor(doorId, world.getInstanceId());
  661. }
  662. for (int doorId : SECOND_ROUTE_DOORS)
  663. {
  664. openDoor(doorId, world.getInstanceId());
  665. }
  666. for (int doorId : SECOND_ROOM_DOORS)
  667. {
  668. closeDoor(doorId, world.getInstanceId());
  669. }
  670. break;
  671. }
  672. world.incStatus();
  673. return true;
  674. }
  675. finally
  676. {
  677. world.lock.unlock();
  678. }
  679. }
  680. return false;
  681. }
  682. protected void spawn(FETWorld world, int npcId, int x, int y, int z, int h, boolean addToKillTable)
  683. {
  684. final L2Npc npc = addSpawn(npcId, x, y, z, h, false, 0, false, world.getInstanceId());
  685. if (addToKillTable)
  686. {
  687. world.npcList.add(npc);
  688. }
  689. npc.setIsNoRndWalk(true);
  690. if (npc.isInstanceTypes(InstanceType.L2Attackable))
  691. {
  692. ((L2Attackable) npc).setSeeThroughSilentMove(true);
  693. }
  694. if (Util.contains(AI_DISABLED_MOBS, npcId))
  695. {
  696. npc.disableCoreAI(true);
  697. }
  698. if (npcId == DARK_CHOIR_PLAYER)
  699. {
  700. world.darkChoirPlayerCount++;
  701. }
  702. }
  703. private class DemonSpawnTask implements Runnable
  704. {
  705. private final FETWorld _world;
  706. DemonSpawnTask(FETWorld world)
  707. {
  708. _world = world;
  709. }
  710. @Override
  711. public void run()
  712. {
  713. if ((InstanceManager.getInstance().getWorld(_world.getInstanceId()) != _world) || _world.portraits.isEmpty())
  714. {
  715. if (debug)
  716. {
  717. _log.info("[Final Emperial Tomb] Instance is deleted or all Portraits is killed.");
  718. }
  719. return;
  720. }
  721. for (int i : _world.portraits.values())
  722. {
  723. if (_world.demons.size() > MAX_DEMONS)
  724. {
  725. break;
  726. }
  727. L2MonsterInstance demon = (L2MonsterInstance) addSpawn(PORTRAIT_SPAWNS[i][0] + 2, PORTRAIT_SPAWNS[i][5], PORTRAIT_SPAWNS[i][6], PORTRAIT_SPAWNS[i][7], PORTRAIT_SPAWNS[i][8], false, 0, false, _world.getInstanceId());
  728. updateKnownList(_world, demon);
  729. _world.demons.add(demon);
  730. }
  731. ThreadPoolManager.getInstance().scheduleGeneral(new DemonSpawnTask(_world), TIME_BETWEEN_DEMON_SPAWNS);
  732. }
  733. }
  734. private class SoulBreakingArrow implements Runnable
  735. {
  736. private final L2Npc _npc;
  737. protected SoulBreakingArrow(L2Npc npc)
  738. {
  739. _npc = npc;
  740. }
  741. @Override
  742. public void run()
  743. {
  744. _npc.setScriptValue(0);
  745. }
  746. }
  747. private class SongTask implements Runnable
  748. {
  749. private final FETWorld _world;
  750. private final int _status;
  751. SongTask(FETWorld world, int status)
  752. {
  753. _world = world;
  754. _status = status;
  755. }
  756. @Override
  757. public void run()
  758. {
  759. if (InstanceManager.getInstance().getWorld(_world.getInstanceId()) != _world)
  760. {
  761. return;
  762. }
  763. switch (_status)
  764. {
  765. case 0: // new song play
  766. if (_world.isVideo)
  767. {
  768. _world.songTask = ThreadPoolManager.getInstance().scheduleGeneral(new SongTask(_world, 0), 1000);
  769. }
  770. else if ((_world.frintezza != null) && !_world.frintezza.isDead())
  771. {
  772. if (_world.frintezza.getScriptValue() != 1)
  773. {
  774. int rnd = getRandom(100);
  775. for (FrintezzaSong element : FRINTEZZASONGLIST)
  776. {
  777. if (rnd < element.chance)
  778. {
  779. _world.OnSong = element;
  780. broadCastPacket(_world, new ExShowScreenMessage(2, -1, 2, 0, 0, 0, 0, true, 4000, false, null, element.songName, null));
  781. broadCastPacket(_world, new MagicSkillUse(_world.frintezza, _world.frintezza, element.skill.getSkillId(), element.skill.getSkillLvl(), element.skill.getSkill().getHitTime(), 0));
  782. _world.songEffectTask = ThreadPoolManager.getInstance().scheduleGeneral(new SongTask(_world, 1), element.skill.getSkill().getHitTime() - 10000);
  783. _world.songTask = ThreadPoolManager.getInstance().scheduleGeneral(new SongTask(_world, 0), element.skill.getSkill().getHitTime());
  784. break;
  785. }
  786. }
  787. }
  788. else
  789. {
  790. ThreadPoolManager.getInstance().scheduleGeneral(new SoulBreakingArrow(_world.frintezza), 35000);
  791. }
  792. }
  793. break;
  794. case 1: // Frintezza song effect
  795. _world.songEffectTask = null;
  796. Skill skill = _world.OnSong.effectSkill.getSkill();
  797. if (skill == null)
  798. {
  799. return;
  800. }
  801. if ((_world.frintezza != null) && !_world.frintezza.isDead() && (_world.activeScarlet != null) && !_world.activeScarlet.isDead())
  802. {
  803. final List<L2Character> targetList = new ArrayList<>();
  804. if (skill.hasEffectType(L2EffectType.STUN) || skill.isDebuff())
  805. {
  806. for (int objId : _world.getAllowed())
  807. {
  808. L2PcInstance player = L2World.getInstance().getPlayer(objId);
  809. if ((player != null) && player.isOnline() && (player.getInstanceId() == _world.getInstanceId()))
  810. {
  811. if (!player.isDead())
  812. {
  813. targetList.add(player);
  814. }
  815. if (player.hasSummon() && !player.getSummon().isDead())
  816. {
  817. targetList.add(player.getSummon());
  818. }
  819. }
  820. }
  821. }
  822. else
  823. {
  824. targetList.add(_world.activeScarlet);
  825. }
  826. if (!targetList.isEmpty())
  827. {
  828. _world.frintezza.doCast(skill, targetList.get(0), targetList.toArray(new L2Character[targetList.size()]));
  829. }
  830. }
  831. break;
  832. case 2: // finish morph
  833. _world.activeScarlet.setRHandId(SECOND_SCARLET_WEAPON);
  834. _world.activeScarlet.setIsInvul(false);
  835. break;
  836. }
  837. }
  838. }
  839. private class IntroTask implements Runnable
  840. {
  841. private final FETWorld _world;
  842. private final int _status;
  843. IntroTask(FETWorld world, int status)
  844. {
  845. _world = world;
  846. _status = status;
  847. }
  848. @Override
  849. public void run()
  850. {
  851. switch (_status)
  852. {
  853. case 0:
  854. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 1), 27000);
  855. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 2), 30000);
  856. broadCastPacket(_world, new Earthquake(-87784, -155083, -9087, 45, 27));
  857. break;
  858. case 1:
  859. for (int doorId : FIRST_ROOM_DOORS)
  860. {
  861. closeDoor(doorId, _world.getInstanceId());
  862. }
  863. for (int doorId : FIRST_ROUTE_DOORS)
  864. {
  865. closeDoor(doorId, _world.getInstanceId());
  866. }
  867. for (int doorId : SECOND_ROOM_DOORS)
  868. {
  869. closeDoor(doorId, _world.getInstanceId());
  870. }
  871. for (int doorId : SECOND_ROUTE_DOORS)
  872. {
  873. closeDoor(doorId, _world.getInstanceId());
  874. }
  875. addSpawn(29061, -87904, -141296, -9168, 0, false, 0, false, _world.getInstanceId());
  876. break;
  877. case 2:
  878. _world.frintezzaDummy = addSpawn(29052, -87784, -155083, -9087, 16048, false, 0, false, _world.getInstanceId());
  879. _world.frintezzaDummy.setIsInvul(true);
  880. _world.frintezzaDummy.setIsImmobilized(true);
  881. _world.overheadDummy = addSpawn(29052, -87784, -153298, -9175, 16384, false, 0, false, _world.getInstanceId());
  882. _world.overheadDummy.setIsInvul(true);
  883. _world.overheadDummy.setIsImmobilized(true);
  884. _world.overheadDummy.setCollisionHeight(600);
  885. broadCastPacket(_world, new NpcInfo(_world.overheadDummy, null));
  886. _world.portraitDummy1 = addSpawn(29052, -89566, -153168, -9165, 16048, false, 0, false, _world.getInstanceId());
  887. _world.portraitDummy1.setIsImmobilized(true);
  888. _world.portraitDummy1.setIsInvul(true);
  889. _world.portraitDummy3 = addSpawn(29052, -86004, -153168, -9165, 16048, false, 0, false, _world.getInstanceId());
  890. _world.portraitDummy3.setIsImmobilized(true);
  891. _world.portraitDummy3.setIsInvul(true);
  892. _world.scarletDummy = addSpawn(29053, -87784, -153298, -9175, 16384, false, 0, false, _world.getInstanceId());
  893. _world.scarletDummy.setIsInvul(true);
  894. _world.scarletDummy.setIsImmobilized(true);
  895. stopPc();
  896. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 3), 1000);
  897. break;
  898. case 3:
  899. broadCastPacket(_world, new SpecialCamera(_world.overheadDummy, 0, 75, -89, 0, 100, 0, 0, 1, 0, 0));
  900. broadCastPacket(_world, new SpecialCamera(_world.overheadDummy, 0, 75, -89, 0, 100, 0, 0, 1, 0, 0));
  901. broadCastPacket(_world, new SpecialCamera(_world.overheadDummy, 300, 90, -10, 6500, 7000, 0, 0, 1, 0, 0));
  902. _world.frintezza = (L2GrandBossInstance) addSpawn(FRINTEZZA, -87780, -155086, -9080, 16384, false, 0, false, _world.getInstanceId());
  903. _world.frintezza.setIsImmobilized(true);
  904. _world.frintezza.setIsInvul(true);
  905. _world.frintezza.disableAllSkills();
  906. updateKnownList(_world, _world.frintezza);
  907. for (int[] element : PORTRAIT_SPAWNS)
  908. {
  909. L2MonsterInstance demon = (L2MonsterInstance) addSpawn(element[0] + 2, element[5], element[6], element[7], element[8], false, 0, false, _world.getInstanceId());
  910. demon.setIsImmobilized(true);
  911. demon.disableAllSkills();
  912. updateKnownList(_world, demon);
  913. _world.demons.add(demon);
  914. }
  915. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 4), 6500);
  916. break;
  917. case 4:
  918. broadCastPacket(_world, new SpecialCamera(_world.frintezzaDummy, 1800, 90, 8, 6500, 7000, 0, 0, 1, 0, 0));
  919. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 5), 900);
  920. break;
  921. case 5:
  922. broadCastPacket(_world, new SpecialCamera(_world.frintezzaDummy, 140, 90, 10, 2500, 4500, 0, 0, 1, 0, 0));
  923. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 6), 4000);
  924. break;
  925. case 6:
  926. broadCastPacket(_world, new SpecialCamera(_world.frintezza, 40, 75, -10, 0, 1000, 0, 0, 1, 0, 0));
  927. broadCastPacket(_world, new SpecialCamera(_world.frintezza, 40, 75, -10, 0, 12000, 0, 0, 1, 0, 0));
  928. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 7), 1350);
  929. break;
  930. case 7:
  931. broadCastPacket(_world, new SocialAction(_world.frintezza.getObjectId(), 2));
  932. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 8), 7000);
  933. break;
  934. case 8:
  935. _world.frintezzaDummy.deleteMe();
  936. _world.frintezzaDummy = null;
  937. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 9), 1000);
  938. break;
  939. case 9:
  940. broadCastPacket(_world, new SocialAction(_world.demons.get(1).getObjectId(), 1));
  941. broadCastPacket(_world, new SocialAction(_world.demons.get(2).getObjectId(), 1));
  942. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 10), 400);
  943. break;
  944. case 10:
  945. broadCastPacket(_world, new SocialAction(_world.demons.get(0).getObjectId(), 1));
  946. broadCastPacket(_world, new SocialAction(_world.demons.get(3).getObjectId(), 1));
  947. sendPacketX(new SpecialCamera(_world.portraitDummy1, 1000, 118, 0, 0, 1000, 0, 0, 1, 0, 0), new SpecialCamera(_world.portraitDummy3, 1000, 62, 0, 0, 1000, 0, 0, 1, 0, 0), -87784);
  948. sendPacketX(new SpecialCamera(_world.portraitDummy1, 1000, 118, 0, 0, 10000, 0, 0, 1, 0, 0), new SpecialCamera(_world.portraitDummy3, 1000, 62, 0, 0, 10000, 0, 0, 1, 0, 0), -87784);
  949. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 11), 2000);
  950. break;
  951. case 11:
  952. broadCastPacket(_world, new SpecialCamera(_world.frintezza, 240, 90, 0, 0, 1000, 0, 0, 1, 0, 0));
  953. broadCastPacket(_world, new SpecialCamera(_world.frintezza, 240, 90, 25, 5500, 10000, 0, 0, 1, 0, 0));
  954. broadCastPacket(_world, new SocialAction(_world.frintezza.getObjectId(), 3));
  955. _world.portraitDummy1.deleteMe();
  956. _world.portraitDummy3.deleteMe();
  957. _world.portraitDummy1 = null;
  958. _world.portraitDummy3 = null;
  959. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 12), 4500);
  960. break;
  961. case 12:
  962. broadCastPacket(_world, new SpecialCamera(_world.frintezza, 100, 195, 35, 0, 10000, 0, 0, 1, 0, 0));
  963. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 13), 700);
  964. break;
  965. case 13:
  966. broadCastPacket(_world, new SpecialCamera(_world.frintezza, 100, 195, 35, 0, 10000, 0, 0, 1, 0, 0));
  967. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 14), 1300);
  968. break;
  969. case 14:
  970. broadCastPacket(_world, new ExShowScreenMessage(NpcStringId.MOURNFUL_CHORALE_PRELUDE, 2, 5000));
  971. broadCastPacket(_world, new SpecialCamera(_world.frintezza, 120, 180, 45, 1500, 10000, 0, 0, 1, 0, 0));
  972. broadCastPacket(_world, new MagicSkillUse(_world.frintezza, _world.frintezza, 5006, 1, 34000, 0));
  973. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 15), 1500);
  974. break;
  975. case 15:
  976. broadCastPacket(_world, new SpecialCamera(_world.frintezza, 520, 135, 45, 8000, 10000, 0, 0, 1, 0, 0));
  977. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 16), 7500);
  978. break;
  979. case 16:
  980. broadCastPacket(_world, new SpecialCamera(_world.frintezza, 1500, 110, 25, 10000, 13000, 0, 0, 1, 0, 0));
  981. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 17), 9500);
  982. break;
  983. case 17:
  984. broadCastPacket(_world, new SpecialCamera(_world.overheadDummy, 930, 160, -20, 0, 1000, 0, 0, 1, 0, 0));
  985. broadCastPacket(_world, new SpecialCamera(_world.overheadDummy, 600, 180, -25, 0, 10000, 0, 0, 1, 0, 0));
  986. broadCastPacket(_world, new MagicSkillUse(_world.scarletDummy, _world.overheadDummy, 5004, 1, 5800, 0));
  987. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 18), 5000);
  988. break;
  989. case 18:
  990. _world.activeScarlet = (L2GrandBossInstance) addSpawn(29046, -87789, -153295, -9176, 16384, false, 0, false, _world.getInstanceId());
  991. _world.activeScarlet.setRHandId(FIRST_SCARLET_WEAPON);
  992. _world.activeScarlet.setIsInvul(true);
  993. _world.activeScarlet.setIsImmobilized(true);
  994. _world.activeScarlet.disableAllSkills();
  995. updateKnownList(_world, _world.activeScarlet);
  996. broadCastPacket(_world, new SocialAction(_world.activeScarlet.getObjectId(), 3));
  997. broadCastPacket(_world, new SpecialCamera(_world.scarletDummy, 800, 180, 10, 1000, 10000, 0, 0, 1, 0, 0));
  998. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 19), 2100);
  999. break;
  1000. case 19:
  1001. broadCastPacket(_world, new SpecialCamera(_world.activeScarlet, 300, 60, 8, 0, 10000, 0, 0, 1, 0, 0));
  1002. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 20), 2000);
  1003. break;
  1004. case 20:
  1005. broadCastPacket(_world, new SpecialCamera(_world.activeScarlet, 500, 90, 10, 3000, 5000, 0, 0, 1, 0, 0));
  1006. _world.songTask = ThreadPoolManager.getInstance().scheduleGeneral(new SongTask(_world, 0), 100);
  1007. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 21), 3000);
  1008. break;
  1009. case 21:
  1010. for (int i = 0; i < PORTRAIT_SPAWNS.length; i++)
  1011. {
  1012. L2MonsterInstance portrait = (L2MonsterInstance) addSpawn(PORTRAIT_SPAWNS[i][0], PORTRAIT_SPAWNS[i][1], PORTRAIT_SPAWNS[i][2], PORTRAIT_SPAWNS[i][3], PORTRAIT_SPAWNS[i][4], false, 0, false, _world.getInstanceId());
  1013. updateKnownList(_world, portrait);
  1014. _world.portraits.put(portrait, i);
  1015. }
  1016. _world.overheadDummy.deleteMe();
  1017. _world.scarletDummy.deleteMe();
  1018. _world.overheadDummy = null;
  1019. _world.scarletDummy = null;
  1020. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 22), 2000);
  1021. break;
  1022. case 22:
  1023. for (L2MonsterInstance demon : _world.demons)
  1024. {
  1025. demon.setIsImmobilized(false);
  1026. demon.enableAllSkills();
  1027. }
  1028. _world.activeScarlet.setIsInvul(false);
  1029. _world.activeScarlet.setIsImmobilized(false);
  1030. _world.activeScarlet.enableAllSkills();
  1031. _world.activeScarlet.setRunning();
  1032. _world.activeScarlet.doCast(INTRO_SKILL.getSkill());
  1033. _world.frintezza.enableAllSkills();
  1034. _world.frintezza.disableCoreAI(true);
  1035. _world.frintezza.setIsMortal(false);
  1036. startPc();
  1037. ThreadPoolManager.getInstance().scheduleGeneral(new DemonSpawnTask(_world), TIME_BETWEEN_DEMON_SPAWNS);
  1038. break;
  1039. case 23:
  1040. broadCastPacket(_world, new SocialAction(_world.frintezza.getObjectId(), 4));
  1041. break;
  1042. case 24:
  1043. stopPc();
  1044. broadCastPacket(_world, new SpecialCamera(_world.frintezza, 250, 120, 15, 0, 1000, 0, 0, 1, 0, 0));
  1045. broadCastPacket(_world, new SpecialCamera(_world.frintezza, 250, 120, 15, 0, 10000, 0, 0, 1, 0, 0));
  1046. _world.activeScarlet.abortAttack();
  1047. _world.activeScarlet.abortCast();
  1048. _world.activeScarlet.setIsInvul(true);
  1049. _world.activeScarlet.setIsImmobilized(true);
  1050. _world.activeScarlet.disableAllSkills();
  1051. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 25), 7000);
  1052. break;
  1053. case 25:
  1054. broadCastPacket(_world, new MagicSkillUse(_world.frintezza, _world.frintezza, 5006, 1, 34000, 0));
  1055. broadCastPacket(_world, new SpecialCamera(_world.frintezza, 500, 70, 15, 3000, 10000, 0, 0, 1, 0, 0));
  1056. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 26), 3000);
  1057. break;
  1058. case 26:
  1059. broadCastPacket(_world, new SpecialCamera(_world.frintezza, 2500, 90, 12, 6000, 10000, 0, 0, 1, 0, 0));
  1060. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 27), 3000);
  1061. break;
  1062. case 27:
  1063. _world.scarlet_x = _world.activeScarlet.getX();
  1064. _world.scarlet_y = _world.activeScarlet.getY();
  1065. _world.scarlet_z = _world.activeScarlet.getZ();
  1066. _world.scarlet_h = _world.activeScarlet.getHeading();
  1067. if (_world.scarlet_h < 32768)
  1068. {
  1069. _world.scarlet_a = Math.abs(180 - (int) (_world.scarlet_h / 182.044444444));
  1070. }
  1071. else
  1072. {
  1073. _world.scarlet_a = Math.abs(540 - (int) (_world.scarlet_h / 182.044444444));
  1074. }
  1075. broadCastPacket(_world, new SpecialCamera(_world.activeScarlet, 250, _world.scarlet_a, 12, 0, 1000, 0, 0, 1, 0, 0));
  1076. broadCastPacket(_world, new SpecialCamera(_world.activeScarlet, 250, _world.scarlet_a, 12, 0, 10000, 0, 0, 1, 0, 0));
  1077. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 28), 500);
  1078. break;
  1079. case 28:
  1080. _world.activeScarlet.doDie(_world.activeScarlet);
  1081. broadCastPacket(_world, new SpecialCamera(_world.activeScarlet, 450, _world.scarlet_a, 14, 8000, 8000, 0, 0, 1, 0, 0));
  1082. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 29), 6250);
  1083. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 30), 7200);
  1084. break;
  1085. case 29:
  1086. _world.activeScarlet.deleteMe();
  1087. _world.activeScarlet = null;
  1088. break;
  1089. case 30:
  1090. _world.activeScarlet = (L2GrandBossInstance) addSpawn(SCARLET2, _world.scarlet_x, _world.scarlet_y, _world.scarlet_z, _world.scarlet_h, false, 0, false, _world.getInstanceId());
  1091. _world.activeScarlet.setIsInvul(true);
  1092. _world.activeScarlet.setIsImmobilized(true);
  1093. _world.activeScarlet.disableAllSkills();
  1094. updateKnownList(_world, _world.activeScarlet);
  1095. broadCastPacket(_world, new SpecialCamera(_world.activeScarlet, 450, _world.scarlet_a, 12, 500, 14000, 0, 0, 1, 0, 0));
  1096. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 31), 8100);
  1097. break;
  1098. case 31:
  1099. broadCastPacket(_world, new SocialAction(_world.activeScarlet.getObjectId(), 2));
  1100. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 32), 9000);
  1101. break;
  1102. case 32:
  1103. startPc();
  1104. _world.activeScarlet.setIsInvul(false);
  1105. _world.activeScarlet.setIsImmobilized(false);
  1106. _world.activeScarlet.enableAllSkills();
  1107. _world.isVideo = false;
  1108. break;
  1109. case 33:
  1110. broadCastPacket(_world, new SpecialCamera(_world.activeScarlet, 300, _world.scarlet_a - 180, 5, 0, 7000, 0, 0, 1, 0, 0));
  1111. broadCastPacket(_world, new SpecialCamera(_world.activeScarlet, 200, _world.scarlet_a, 85, 4000, 10000, 0, 0, 1, 0, 0));
  1112. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 34), 7400);
  1113. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 35), 7500);
  1114. break;
  1115. case 34:
  1116. _world.frintezza.doDie(_world.frintezza);
  1117. break;
  1118. case 35:
  1119. broadCastPacket(_world, new SpecialCamera(_world.frintezza, 100, 120, 5, 0, 7000, 0, 0, 1, 0, 0));
  1120. broadCastPacket(_world, new SpecialCamera(_world.frintezza, 100, 90, 5, 5000, 15000, 0, 0, 1, 0, 0));
  1121. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 36), 7000);
  1122. break;
  1123. case 36:
  1124. broadCastPacket(_world, new SpecialCamera(_world.frintezza, 900, 90, 25, 7000, 10000, 0, 0, 1, 0, 0));
  1125. ThreadPoolManager.getInstance().scheduleGeneral(new IntroTask(_world, 37), 9000);
  1126. break;
  1127. case 37:
  1128. controlStatus(_world);
  1129. _world.isVideo = false;
  1130. startPc();
  1131. break;
  1132. }
  1133. }
  1134. private void stopPc()
  1135. {
  1136. for (int objId : _world.getAllowed())
  1137. {
  1138. L2PcInstance player = L2World.getInstance().getPlayer(objId);
  1139. if ((player != null) && player.isOnline() && (player.getInstanceId() == _world.getInstanceId()))
  1140. {
  1141. player.abortAttack();
  1142. player.abortCast();
  1143. player.disableAllSkills();
  1144. player.setTarget(null);
  1145. player.stopMove(null);
  1146. player.setIsImmobilized(true);
  1147. player.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
  1148. }
  1149. }
  1150. }
  1151. private void startPc()
  1152. {
  1153. for (int objId : _world.getAllowed())
  1154. {
  1155. L2PcInstance player = L2World.getInstance().getPlayer(objId);
  1156. if ((player != null) && player.isOnline() && (player.getInstanceId() == _world.getInstanceId()))
  1157. {
  1158. player.enableAllSkills();
  1159. player.setIsImmobilized(false);
  1160. }
  1161. }
  1162. }
  1163. private void sendPacketX(L2GameServerPacket packet1, L2GameServerPacket packet2, int x)
  1164. {
  1165. for (int objId : _world.getAllowed())
  1166. {
  1167. L2PcInstance player = L2World.getInstance().getPlayer(objId);
  1168. if ((player != null) && player.isOnline() && (player.getInstanceId() == _world.getInstanceId()))
  1169. {
  1170. if (player.getX() < x)
  1171. {
  1172. player.sendPacket(packet1);
  1173. }
  1174. else
  1175. {
  1176. player.sendPacket(packet2);
  1177. }
  1178. }
  1179. }
  1180. }
  1181. }
  1182. private class StatusTask implements Runnable
  1183. {
  1184. private final FETWorld _world;
  1185. private final int _status;
  1186. StatusTask(FETWorld world, int status)
  1187. {
  1188. _world = world;
  1189. _status = status;
  1190. }
  1191. @Override
  1192. public void run()
  1193. {
  1194. if (InstanceManager.getInstance().getWorld(_world.getInstanceId()) != _world)
  1195. {
  1196. return;
  1197. }
  1198. switch (_status)
  1199. {
  1200. case 0:
  1201. ThreadPoolManager.getInstance().scheduleGeneral(new StatusTask(_world, 1), 2000);
  1202. for (int doorId : FIRST_ROOM_DOORS)
  1203. {
  1204. openDoor(doorId, _world.getInstanceId());
  1205. }
  1206. break;
  1207. case 1:
  1208. addAggroToMobs();
  1209. break;
  1210. case 2:
  1211. ThreadPoolManager.getInstance().scheduleGeneral(new StatusTask(_world, 3), 100);
  1212. for (int doorId : SECOND_ROOM_DOORS)
  1213. {
  1214. openDoor(doorId, _world.getInstanceId());
  1215. }
  1216. break;
  1217. case 3:
  1218. addAggroToMobs();
  1219. break;
  1220. case 4:
  1221. controlStatus(_world);
  1222. break;
  1223. }
  1224. }
  1225. private void addAggroToMobs()
  1226. {
  1227. L2PcInstance target = L2World.getInstance().getPlayer(_world.getAllowed().get(getRandom(_world.getAllowed().size())));
  1228. if ((target == null) || (target.getInstanceId() != _world.getInstanceId()) || target.isDead() || target.isFakeDeath())
  1229. {
  1230. for (int objId : _world.getAllowed())
  1231. {
  1232. target = L2World.getInstance().getPlayer(objId);
  1233. if ((target != null) && (target.getInstanceId() == _world.getInstanceId()) && !target.isDead() && !target.isFakeDeath())
  1234. {
  1235. break;
  1236. }
  1237. target = null;
  1238. }
  1239. }
  1240. for (L2Npc mob : _world.npcList)
  1241. {
  1242. mob.setRunning();
  1243. if (target != null)
  1244. {
  1245. ((L2MonsterInstance) mob).addDamageHate(target, 0, 500);
  1246. mob.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
  1247. }
  1248. else
  1249. {
  1250. mob.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, MOVE_TO_CENTER);
  1251. }
  1252. }
  1253. }
  1254. }
  1255. protected void broadCastPacket(FETWorld world, L2GameServerPacket packet)
  1256. {
  1257. for (int objId : world.getAllowed())
  1258. {
  1259. L2PcInstance player = L2World.getInstance().getPlayer(objId);
  1260. if ((player != null) && player.isOnline() && (player.getInstanceId() == world.getInstanceId()))
  1261. {
  1262. player.sendPacket(packet);
  1263. }
  1264. }
  1265. }
  1266. protected void updateKnownList(FETWorld world, L2Npc npc)
  1267. {
  1268. Map<Integer, L2PcInstance> npcKnownPlayers = npc.getKnownList().getKnownPlayers();
  1269. for (int objId : world.getAllowed())
  1270. {
  1271. L2PcInstance player = L2World.getInstance().getPlayer(objId);
  1272. if ((player != null) && player.isOnline() && (player.getInstanceId() == world.getInstanceId()))
  1273. {
  1274. npcKnownPlayers.put(player.getObjectId(), player);
  1275. }
  1276. }
  1277. }
  1278. @Override
  1279. public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon, Skill skill)
  1280. {
  1281. final InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(npc.getInstanceId());
  1282. if (tmpworld instanceof FETWorld)
  1283. {
  1284. final FETWorld world = (FETWorld) tmpworld;
  1285. if ((npc.getId() == SCARLET1) && (world.getStatus() == 3) && (npc.getCurrentHp() < (npc.getMaxHp() * 0.80)))
  1286. {
  1287. controlStatus(world);
  1288. }
  1289. else if ((npc.getId() == SCARLET1) && (world.getStatus() == 4) && (npc.getCurrentHp() < (npc.getMaxHp() * 0.20)))
  1290. {
  1291. controlStatus(world);
  1292. }
  1293. if (skill != null)
  1294. {
  1295. // When Dewdrop of Destruction is used on Portraits they suicide.
  1296. if (Util.contains(PORTRAITS, npc.getId()) && (skill.getId() == DEWDROP_OF_DESTRUCTION_SKILL_ID))
  1297. {
  1298. npc.doDie(attacker);
  1299. }
  1300. else if ((npc.getId() == FRINTEZZA) && (skill.getId() == SOUL_BREAKING_ARROW_SKILL_ID))
  1301. {
  1302. npc.setScriptValue(1);
  1303. npc.setTarget(null);
  1304. npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
  1305. }
  1306. }
  1307. }
  1308. return null;
  1309. }
  1310. @Override
  1311. public String onSpellFinished(L2Npc npc, L2PcInstance player, Skill skill)
  1312. {
  1313. if (skill.isSuicideAttack())
  1314. {
  1315. return onKill(npc, null, false);
  1316. }
  1317. return super.onSpellFinished(npc, player, skill);
  1318. }
  1319. @Override
  1320. public String onKill(L2Npc npc, L2PcInstance player, boolean isSummon)
  1321. {
  1322. InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(npc.getInstanceId());
  1323. if (tmpworld instanceof FETWorld)
  1324. {
  1325. FETWorld world = (FETWorld) tmpworld;
  1326. if (npc.getId() == HALL_ALARM)
  1327. {
  1328. ThreadPoolManager.getInstance().scheduleGeneral(new StatusTask(world, 0), 2000);
  1329. if (debug)
  1330. {
  1331. _log.info("[Final Emperial Tomb] Hall alarm is disabled, doors will open!");
  1332. }
  1333. }
  1334. else if (npc.getId() == DARK_CHOIR_PLAYER)
  1335. {
  1336. world.darkChoirPlayerCount--;
  1337. if (world.darkChoirPlayerCount < 1)
  1338. {
  1339. ThreadPoolManager.getInstance().scheduleGeneral(new StatusTask(world, 2), 2000);
  1340. if (debug)
  1341. {
  1342. _log.info("[Final Emperial Tomb] All Dark Choir Players are killed, doors will open!");
  1343. }
  1344. }
  1345. }
  1346. else if (npc.getId() == SCARLET2)
  1347. {
  1348. controlStatus(world);
  1349. }
  1350. else if (world.getStatus() <= 2)
  1351. {
  1352. if (npc.getId() == HALL_KEEPER_CAPTAIN)
  1353. {
  1354. if (getRandom(100) < 5)
  1355. {
  1356. npc.dropItem(player, DEWDROP_OF_DESTRUCTION_ITEM_ID, 1);
  1357. }
  1358. }
  1359. if (checkKillProgress(npc, world))
  1360. {
  1361. controlStatus(world);
  1362. }
  1363. }
  1364. else if (world.demons.contains(npc))
  1365. {
  1366. world.demons.remove(npc);
  1367. }
  1368. else if (world.portraits.containsKey(npc))
  1369. {
  1370. world.portraits.remove(npc);
  1371. }
  1372. }
  1373. return "";
  1374. }
  1375. @Override
  1376. public String onTalk(L2Npc npc, L2PcInstance player)
  1377. {
  1378. int npcId = npc.getId();
  1379. getQuestState(player, true);
  1380. if (npcId == GUIDE)
  1381. {
  1382. enterInstance(player, new FETWorld(), "FinalEmperialTomb.xml", TEMPLATE_ID);
  1383. }
  1384. else if (npc.getId() == CUBE)
  1385. {
  1386. int x = -87534 + getRandom(500);
  1387. int y = -153048 + getRandom(500);
  1388. player.teleToLocation(x, y, -9165);
  1389. return null;
  1390. }
  1391. return "";
  1392. }
  1393. }