package instance;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import com.aionemu.commons.utils.Rnd;
import com.aionemu.gameserver.ai.AIActions;
import com.aionemu.gameserver.instance.handlers.GeneralInstanceHandler;
import com.aionemu.gameserver.instance.handlers.InstanceID;
import com.aionemu.gameserver.model.CreatureType;
import com.aionemu.gameserver.model.gameobjects.Creature;
import com.aionemu.gameserver.model.gameobjects.Npc;
import com.aionemu.gameserver.model.gameobjects.VisibleObject;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.network.aion.serverpackets.SM_QUEST_ACTION;
import com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE;
import com.aionemu.gameserver.services.player.PlayerReviveService;
import com.aionemu.gameserver.services.teleport.TeleportService;
import com.aionemu.gameserver.skillengine.SkillEngine;
import com.aionemu.gameserver.skillengine.model.Effect;
import com.aionemu.gameserver.utils.PacketSendUtility;
import com.aionemu.gameserver.utils.ThreadPoolManager;
import com.aionemu.gameserver.world.WorldMapInstance;
import com.aionemu.gameserver.world.WorldPosition;
/**
* @author bobobear, Luzien, Estrayl
*/
@InstanceID(300520000)
public class DragonLordsRefugeInstance extends GeneralInstanceHandler {
private final List<WorldPosition> respawnLocations = new ArrayList<>();
protected final AtomicInteger raceId = new AtomicInteger(10);
protected final AtomicInteger incarnationKills = new AtomicInteger();
protected final AtomicInteger progress = new AtomicInteger();
protected Future<?> failTask;
public DragonLordsRefugeInstance(WorldMapInstance instance) {
super(instance);
// Retail positions
respawnLocations.add(new WorldPosition(300520000, 493.72f, 507.67f, 240.5f, (byte) 0));
respawnLocations.add(new WorldPosition(300520000, 497.52f, 526.03f, 240.5f, (byte) 0));
respawnLocations.add(new WorldPosition(300520000, 513.02f, 524.57f, 240.5f, (byte) 0));
respawnLocations.add(new WorldPosition(300520000, 499.57f, 510.19f, 240.5f, (byte) 0));
respawnLocations.add(new WorldPosition(300520000, 513.22f, 508.36f, 240.5f, (byte) 0));
respawnLocations.add(new WorldPosition(300520000, 505.05f, 525.03f, 240.5f, (byte) 0));
respawnLocations.add(new WorldPosition(300520000, 498.65f, 519.93f, 240.5f, (byte) 0));
respawnLocations.add(new WorldPosition(300520000, 511.44f, 515.36f, 240.5f, (byte) 0));
respawnLocations.add(new WorldPosition(300520000, 495.27f, 517.07f, 240.5f, (byte) 0));
respawnLocations.add(new WorldPosition(300520000, 492.62f, 525.37f, 240.5f, (byte) 0));
respawnLocations.add(new WorldPosition(300520000, 507.56f, 520.36f, 240.5f, (byte) 0));
respawnLocations.add(new WorldPosition(300520000, 508.20f, 506.85f, 240.5f, (byte) 0));
}
@Override
public void onSpawn(VisibleObject object) {
if (object instanceof Npc) {
switch (((Npc) object).getNpcId()) {
case 219361: // Tiamat Dragon
ThreadPoolManager.getInstance().schedule(() -> {
spawn(730673, 459.548f, 456.849f, 417.405f, (byte) 21);
spawn(730674, 547.909f, 456.568f, 417.405f, (byte) 45);
spawn(730675, 460.082f, 571.978f, 417.405f, (byte) 98);
spawn(730676, 547.822f, 571.876f, 417.405f, (byte) 74);
}, 60000);
break;
case 219362: // Tiamat Weakened Dragon
sendMsg(SM_SYSTEM_MESSAGE.IDTIAMAT_TIAMAT_COUNTDOWN_START(), 2000);
PacketSendUtility.broadcastToMap(instance, new SM_QUEST_ACTION(0, 1800));
failTask = ThreadPoolManager.getInstance().schedule(() -> {
Npc tiamat = getNpc(219362);
if (tiamat != null && !tiamat.isDead()) {
endInstance(Arrays.asList(730625, 730633, 730634, 730635, 730636));
sendMsg(SM_SYSTEM_MESSAGE.IDTIAMAT_TIAMAT_COUNTDOWN_OVER());
}
}, 1800000); // 30'
break;
case 219488: // Kaisinel 1st Phase
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_IDTIAMAT_TIAMAT_2PHASE_START_LIGHT(), 20000);
break;
case 219489: // Kaisinel 2nd Phase
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_IDTIAMAT_KAISINEL_2PHASE_DEADLYATK(), 3000);
break;
case 219490: // Kaisinel 3rd Phase
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_IDTIAMAT_KAISINEL_2PHASE_GROGGY(), 15000);
break;
case 219491: // Marchutan 1st Phase
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_IDTIAMAT_TIAMAT_2PHASE_START_DARK(), 20000);
break;
case 219492: // Marchutan 2nd Phase
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_IDTIAMAT_MARCHUTAN_2PHASE_DEADLYATK(), 3000);
break;
case 219493: // Marchutan 3rd Phase
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_IDTIAMAT_MARCHUTAN_2PHASE_GROGGY(), 15000);
break;
case 283140:
sendMsg(SM_SYSTEM_MESSAGE.STR_IDTIAMAT_TIAMAT_SPAWN_BLACKHOLE(), 2500);
break;
case 730673:
ThreadPoolManager.getInstance().schedule(() -> {
spawn(283163, 463f, 568f, 417.405f, (byte) 105);
spawn(283164, 545f, 568f, 417.405f, (byte) 78);
spawn(283165, 545f, 461f, 417.405f, (byte) 46);
spawn(283166, 463f, 461f, 417.405f, (byte) 17);
}, 10000);
break;
case 730695: // Surkana
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_IDTIAMAT_KALYNDI_SURKANA_SPAWN(), 2500);
break;
}
}
}
@Override
public void onStartEffect(Effect effect) {
switch (effect.getSkillId()) {
case 20918:
PacketSendUtility.broadcastMessage(getNpc(800341), 1500612);
break;
case 20920:
if (progress.compareAndSet(1, 2)) {
ThreadPoolManager.getInstance().schedule(() -> spawn(219488 + raceId.get() * 3, 504f, 515f, 417.405f, (byte) 60), 6000);
spawn(219532, 469f, 563f, 417.41f, (byte) 103);
spawn(219535, 466f, 560f, 417.41f, (byte) 103);
spawn(219533, 542f, 559f, 417.41f, (byte) 79);
spawn(219538, 538f, 562f, 417.41f, (byte) 79);
spawn(219534, 537f, 466f, 417.41f, (byte) 42);
spawn(219537, 541f, 469f, 417.41f, (byte) 42);
spawn(219536, 466f, 471f, 417.41f, (byte) 18);
spawn(219539, 470f, 467f, 417.41f, (byte) 18);
}
break;
case 20993:
case 20994:
case 20995:
case 20996:
sendMsg(SM_SYSTEM_MESSAGE.IDTIAMAT_TIAMAT_DRAKAN_ON_DIE());
break;
}
}
@Override
public void onEndEffect(Effect effect) {
switch (effect.getSkillId()) {
case 20975:
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_IDTIAMAT_TIAMAT_2PHASE_CLOSE_CRACK());
break;
case 20976:
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_IDTIAMAT_TIAMAT_2PHASE_CLOSE_RAGE());
break;
case 20977:
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_IDTIAMAT_TIAMAT_2PHASE_CLOSE_GRAVITY());
break;
case 20978:
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_IDTIAMAT_TIAMAT_2PHASE_CLOSE_CRYSTAL());
break;
case 20983:
if (((Npc) effect.getEffector()).getNpcId() == 219361)
endInstance(Arrays.asList(730625, 730633, 730634, 730635, 730636));
break;
}
}
private void endInstance(List<Integer> despawnExceptions) {
instance.forEachNpc(npc -> {
if (!despawnExceptions.contains(npc.getNpcId()))
npc.getController().delete();
});
spawn(730630, 548.18683f, 514.54523f, 420f, (byte) 0, 23);
}
@Override
public void onDie(Npc npc) {
super.onDie(npc);
switch (npc.getNpcId()) {
case 219359: // Calindi Flamelord
deleteAliveNpcs(730695, 730696); // Surkana
ThreadPoolManager.getInstance().schedule(() -> AIActions.useSkill(getNpc(219360).getAi(), 20919), 4000);
ThreadPoolManager.getInstance().schedule(() -> deleteAliveNpcs(730694), 6000); // Aetheric field
break;
case 219361: // Tiamat Dragon - killed by Empyrean Lord
getNpc(730699).getController().die(); // Animates roof destruction
getNpc(730700).getController().die();
spawn(283134, 451.97f, 514.55f, 417.40436f, (byte) 0);
spawn(219362, 451.97f, 514.55f, 417.40436f, (byte) 0);
spawn(730704, 437.541f, 513.487f, 415.824f, (byte) 0, 17); // Collapsed Debris impaling Tiamat
break;
case 219362:
failTask.cancel(true);
PacketSendUtility.broadcastToMap(instance, new SM_QUEST_ACTION(0, 0));
// TODO: play movie
endInstance(Arrays.asList(219490, 219493, 219362, 730625, 730633, 730634, 730635, 730636));
spawn(701542, 480f, 514f, 417.405f, (byte) 0); // Treasure Chest
spawn(800430, 506.8f, 511.4f, 417.405f, (byte) 60); // Kahrun
spawn(800350 + raceId.get() * 6, 506.7f, 518.4f, 417.405f, (byte) 60); // human Kaisinel/Marchutan
spawn(800464, 544.964f, 517.898f, 417.405f, (byte) 113);
spawn(800465, 545.605f, 510.325f, 417.405f, (byte) 17);
break;
case 219365: // Incarnations
case 219366:
case 219367:
case 219368:
if (incarnationKills.incrementAndGet() == 4)
handlePhaseProgress();
SkillEngine.getInstance().applyEffectDirectly(npc.getNpcId() - 198386, npc, getNpc(219361)); // 20979 - 20982
break;
case 283163: // Balaur Spiritualist
case 283164:
case 283165:
case 283166:
Npc empyreanLord = getNpc(219488 + raceId.get() * 3);
if (empyreanLord != null)
SkillEngine.getInstance().applyEffectDirectly(npc.getNpcId() - 262170, npc, empyreanLord); // 20993 - 20996
break;
case 219488: // Kaisinel 1st Phase
case 219491: // Marchutan 1st Phase
if (incarnationKills.get() == 4) // in rare cases the empyrean lord dies while the instance have to wait for progress
return;
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_IDTIAMAT_TIAMAT_DEADLYHOWLING());
for (int i = 219365; i <= 219368; i++) {
Npc incarnation = getNpc(i);
if (incarnation != null)
AIActions.useSkill(incarnation.getAi(), 20983);
}
AIActions.useSkill(getNpc(219361).getAi(), 20983);
ThreadPoolManager.getInstance().schedule(() -> endInstance(Arrays.asList(730625, 730633, 730634, 730635, 730636, 730699, 730700)), 5000);
break;
}
}
private void handlePhaseProgress() {
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_IDTIAMAT_TIAMAT_2PHASE_CLOSE_ALL());
int empyreanLordId = 219488 + raceId.get() * 3;
getNpc(219361).getEffectController().removeEffect(20984); // Dispel Unbreakable Wing
// schedule spawn of empyrean lords for final attack to tiamat before became exhausted
ThreadPoolManager.getInstance().schedule(() -> {
deleteAliveNpcs(empyreanLordId);
spawn(219489 + raceId.get() * 3, 516.285f, 514.84f, 417.405f, (byte) 60);
}, 30000);
}
/**
* Smalltalk between Tiamat and Kahrun
*/
private void handleDialogueEvent(Npc tiamat) {
Npc kahrun = getNpc(800341);
AIActions.targetCreature(tiamat.getAi(), kahrun);
PacketSendUtility.broadcastMessage(tiamat, 1500613, 5000);
PacketSendUtility.broadcastMessage(kahrun, 1500609, 10000);
PacketSendUtility.broadcastMessage(tiamat, 1500614, 15000);
PacketSendUtility.broadcastMessage(kahrun, 1500610, 20000);
PacketSendUtility.broadcastMessage(tiamat, 1500615, 26500);
PacketSendUtility.broadcastMessage(kahrun, 1500611, 31500);
ThreadPoolManager.getInstance().schedule(() -> AIActions.useSkill(kahrun.getAi(), 20597), 35500);
PacketSendUtility.broadcastMessage(tiamat, 1500616, 40000);
ThreadPoolManager.getInstance().schedule(() -> AIActions.useSkill(tiamat.getAi(), 20918), 49000);
PacketSendUtility.broadcastMessage(tiamat, 1500617, 44500);
ThreadPoolManager.getInstance().schedule(() -> {
kahrun.getController().delete();
tiamat.getController().delete();
spawnTiamat();
spawnCalindi();
}, 54500);
}
protected void spawnTiamat() {
spawn(219360, 452, 514, 432, (byte) 0);
}
protected void spawnCalindi() {
spawn(219359, 483.463f, 514.519f, 417.404f, (byte) 0);
}
@Override
public void onEnterInstance(Player player) {
raceId.compareAndSet(10, player.getRace().getRaceId());
}
@Override
public void onCreatureDetected(Npc detector, Creature detected) {
if (detector.getNpcId() == 219360 && detected instanceof Player && progress.compareAndSet(0, 1))
handleDialogueEvent(detector);
}
@Override
public void handleUseItemFinish(Player player, Npc npc) {
switch (npc.getNpcId()) {
case 730625:
float distance = Rnd.get(250, 450) * 0.1f;
double radian = Math.toRadians(Rnd.get(-45, 60));
float x = (float) (Math.cos(radian) * distance);
float y = (float) (Math.sin(radian) * distance);
TeleportService.teleportTo(player, instance.getMapId(), 503.389f + x, 514.661f + y, 417.404f);
Npc tiamat = getNpc(219360);
if (tiamat != null)
tiamat.overrideNpcType(CreatureType.PEACE);
break;
case 730630: // Exit
TeleportService.moveToInstanceExit(player, mapId, player.getRace());
break;
case 730673:
TeleportService.teleportTo(player, instance.getMapId(), 217.144f, 195.616f, 246.0712f);
break;
case 730674:
TeleportService.teleportTo(player, instance.getMapId(), 785.866f, 197.713f, 246.0712f);
break;
case 730675:
TeleportService.teleportTo(player, instance.getMapId(), 217.947f, 832.552f, 246.0712f);
break;
case 730676:
TeleportService.teleportTo(player, instance.getMapId(), 779.178f, 833.055f, 246.0712f);
break;
case 730633:
TeleportService.teleportTo(player, instance.getMapId(), 461.493f, 459.308f, 417.405f);
break;
case 730634:
TeleportService.teleportTo(player, instance.getMapId(), 546f, 458.934f, 417.405f);
break;
case 730635:
TeleportService.teleportTo(player, instance.getMapId(), 462.188f, 568.913f, 417.405f);
break;
case 730636:
TeleportService.teleportTo(player, instance.getMapId(), 545.773f, 569.225f, 417.405f);
break;
}
}
@Override
public void onInstanceDestroy() {
if (failTask != null && !failTask.isCancelled())
failTask.cancel(true);
}
@Override
public boolean onReviveEvent(Player player) {
PlayerReviveService.revive(player, 25, 25, true, 0);
player.getGameStats().updateStatsAndSpeedVisually();
PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_REBIRTH_MASSAGE_ME());
WorldPosition p = Rnd.get(respawnLocations);
TeleportService.teleportTo(player, instance, p.getX(), p.getY(), p.getZ(), p.getHeading());
return true;
}
}