package instance;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import com.aionemu.commons.utils.Rnd;
import com.aionemu.gameserver.geoEngine.math.Vector3f;
import com.aionemu.gameserver.instance.handlers.GeneralInstanceHandler;
import com.aionemu.gameserver.instance.handlers.InstanceID;
import com.aionemu.gameserver.model.Race;
import com.aionemu.gameserver.model.gameobjects.Creature;
import com.aionemu.gameserver.model.gameobjects.Npc;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE;
import com.aionemu.gameserver.services.teleport.TeleportService;
import com.aionemu.gameserver.utils.PositionUtil;
import com.aionemu.gameserver.utils.ThreadPoolManager;
import com.aionemu.gameserver.world.WorldMapInstance;
import com.aionemu.gameserver.world.geo.GeoService;
import com.aionemu.gameserver.world.zone.ZoneInstance;
import com.aionemu.gameserver.world.zone.ZoneName;
/**
* @author Estrayl
* @since AION 4.8
*/
@InstanceID(300610000)
public class RaksangRuinsInstance extends GeneralInstanceHandler {
private final int way = Rnd.get(0, 2);
private final AtomicInteger spawns = new AtomicInteger();
private final AtomicBoolean isEventStarted = new AtomicBoolean();
private final AtomicInteger waveKillz = new AtomicInteger();
private volatile boolean isInstanceDestroyed;
private Future<?> spawnTask;
private boolean isDoorAccessible = false;
public RaksangRuinsInstance(WorldMapInstance instance) {
super(instance);
}
@Override
public float getExpMultiplier() {
return 1.8f;
}
@Override
public void onEnterInstance(Player player) {
spawn(206378 + way + (player.getRace() == Race.ASMODIANS ? 17 : 0), 818.103f, 931.0215f, 1207.4312f, (byte) 13);
}
@Override
public void onDie(Npc npc) {
switch (npc.getNpcId()) {
case 236010: // Trained Porgus
case 236011: // Trained Worg
case 236012: // Crumbling Skelesword
case 236013: // Withering Husk
case 236014: // Ragelich Adept
if (waveKillz.incrementAndGet() >= 31) {
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_TAMES_SOLO_A_END());
isDoorAccessible = true;
}
break;
case 236074:
case 236075:
case 236076:
switch (waveKillz.incrementAndGet()) {
case 15:
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_TAMES_SOLO_C_END());
instance.setDoorState(457, true);
break;
case 30:
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_TAMES_SOLO_C_END());
instance.setDoorState(64, true);
break;
}
break;
case 236020:
case 236021:
case 236096:
case 236097:
switch (waveKillz.incrementAndGet()) {
case 28:
spawnTask.cancel(false);
spawnTask = null;
spawns.set(0);
instance.setDoorState(107, true);
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_TAMES_SOLO_B_END());
break;
case 56:
spawn(236305, 331.107f, 787.326f, 147.798f, (byte) 47);
break;
}
break;
case 236084:
instance.setDoorState(307, true);
break;
case 217469:
instance.setDoorState(107, true);
break;
case 236303:
instance.setDoorState(294, true);
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_TAMES_SOLO_A_END());
break;
case 236304:
instance.setDoorState(118, true);
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_TAMES_SOLO_C_END());
break;
case 236305:
instance.setDoorState(324, true);
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_TAMES_SOLO_B_END());
break;
case 236306:
spawn(730445, 620.65f, 663.44f, 522.049f, (byte) 27); // Exit
break;
case 0:
spawn(730438, 628.132f, 187.505f, 924.86f, (byte) 0);
}
}
@Override
public void handleUseItemFinish(Player player, Npc npc) {
switch (npc.getNpcId()) {
case 702673: // Torment's Forge
case 702674:
case 702675:
case 702690:
case 702691:
case 702692:
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_TAMES_SOLO_A_START());
delaySpawn(player, 236074 + Rnd.nextInt(3), 2000);
delaySpawn(player, 236074 + Rnd.nextInt(3), 2000);
delaySpawn(player, 236074 + Rnd.nextInt(3), 8000);
delaySpawn(player, 236074 + Rnd.nextInt(3), 8000);
delaySpawn(player, 236074 + Rnd.nextInt(3), 12000);
npc.getController().delete();
break;
case 730438: // Terror' Vault
if (isDoorAccessible)
TeleportService.teleportTo(player, instance, 711.10895f, 312.82013f, 910.6781f);
else
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_TAMES_SOLO_A_DOOR_CONDITION());
break;
}
}
/**
* Used for way A (Terror's Vault & Cuttling Grounds).
*/
private void delaySpawn(int npcId, int delay) {
ThreadPoolManager.getInstance().schedule(() -> {
if (!isInstanceDestroyed)
spawn(npcId, 621.50f, 198.54f, 924.838f, (byte) 42);
}, delay);
}
private void delaySpawn(byte step, int delay) {
spawnTask = ThreadPoolManager.getInstance().scheduleAtFixedRate(() -> {
if (spawns.incrementAndGet() > 8 || isInstanceDestroyed) {
spawnTask.cancel(false);
return;
}
switch (step) {
case 1:
switch (spawns.get()) {
case 1:
case 3:
case 5:
case 7:
spawn(236020, 344.016f, 630.834f, 146.514f, (byte) 0);
spawn(236020, 325.803f, 645.552f, 146.514f, (byte) 0);
spawn(236020, 307.303f, 614.676f, 146.514f, (byte) 0);
spawn(236020, 329.768f, 608.466f, 146.514f, (byte) 0);
break;
case 2:
case 4:
case 6:
case 8:
spawn(236021, 312.577f, 605.469f, 146.514f, (byte) 0);
spawn(236021, 307.422f, 630.051f, 146.514f, (byte) 0);
spawn(236021, 337.200f, 639.658f, 146.514f, (byte) 0);
break;
}
break;
case 2:
switch (spawns.get()) {
case 1:
case 3:
case 5:
case 7:
spawn(236096, 303.755f, 772.090f, 148.988f, (byte) 0);
spawn(236096, 350.070f, 801.111f, 145.082f, (byte) 0);
spawn(236096, 332.003f, 767.004f, 147.394f, (byte) 0);
spawn(236096, 325.803f, 810.720f, 144.885f, (byte) 0);
break;
case 2:
case 4:
case 6:
case 8:
spawn(236097, 344.371f, 781.986f, 147.159f, (byte) 0);
spawn(236097, 339.273f, 813.446f, 145.390f, (byte) 0);
spawn(236097, 317.126f, 766.019f, 148.844f, (byte) 0);
break;
}
break;
case 3:
switch (spawns.get()) {
case 1:
delaySpawn(236010, 1000);
delaySpawn(236010, 4000);
delaySpawn(236010, 7000);
delaySpawn(236010, 10000);
delaySpawn(236010, 13000);
break;
case 2:
delaySpawn(236010, 1000);
delaySpawn(236010, 3000);
delaySpawn(236010, 6000);
delaySpawn(236011, 9000);
delaySpawn(236011, 9500);
break;
case 3:
delaySpawn(236011, 1000);
delaySpawn(236011, 1500);
delaySpawn(236011, 6000);
delaySpawn(236011, 6500);
delaySpawn(236011, 7000);
break;
case 4:
delaySpawn(236011, 1000);
delaySpawn(236011, 1500);
delaySpawn(236013, 2000);
break;
case 5:
delaySpawn(236010, 2000);
delaySpawn(236010, 5000);
delaySpawn(236010, 7000);
delaySpawn(236011, 11000);
delaySpawn(236011, 11500);
break;
case 6:
delaySpawn(236011, 1000);
delaySpawn(236011, 1500);
delaySpawn(236013, 2000);
delaySpawn(236011, 6000);
delaySpawn(236011, 6500);
break;
case 7:
delaySpawn(236012, 7000);
delaySpawn(236012, 7500);
delaySpawn(236014, 8000);
break;
}
break;
}
}, 0, delay);
}
/**
* Used for way C (Torment's Forge).
*/
private void delaySpawn(Player p, int npcId, int delay) {
ThreadPoolManager.getInstance().schedule(() -> rndSpawnInRange(p, npcId, 5), delay);
}
private void rndSpawnInRange(Player player, int npcId, int distance) {
double angleRadians = Math.toRadians(Rnd.nextFloat(360f));
float x = player.getX() + (float) (Math.cos(angleRadians) * distance);
float y = player.getY() + (float) (Math.sin(angleRadians) * distance);
Vector3f pos = GeoService.getInstance().getClosestCollision(player, x, y, player.getZ());
byte headingTowardsPlayer = PositionUtil.getHeadingTowards(pos.getX(), pos.getY(), player.getX(), player.getY());
spawn(npcId, pos.getX(), pos.getY(), pos.getZ(), headingTowardsPlayer);
}
@Override
public void onCreatureDetected(Npc detector, Creature detected) {
if (detected instanceof Player) {
switch (detector.getNpcId()) {
case 206197:
detector.getController().delete();
instance.setDoorState(219, true); // collapse pathway
break;
case 206198:
if (spawnTask == null && isEventStarted.compareAndSet(false, true)) {
detector.getController().delete();
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_TAMES_SOLO_B_START());
delaySpawn((byte) 1, 10000);
}
break;
case 206199:
if (spawnTask == null && isEventStarted.compareAndSet(true, false)) {
detector.getController().delete();
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_TAMES_SOLO_B_START());
delaySpawn((byte) 2, 10000);
}
break;
}
}
}
@Override
public void onEnterZone(Player player, ZoneInstance zone) {
if (zone.getZoneTemplate().getName() == ZoneName.get("IDRAKSHA_SOLO_WAVE_01_206399_1_300610000")) {
if (spawnTask == null && isEventStarted.compareAndSet(false, true)) {
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_TAMES_SOLO_A_START());
delaySpawn((byte) 3, 20000);
}
}
}
@Override
public void onInstanceDestroy() {
isInstanceDestroyed = true;
if (spawnTask != null)
spawnTask.cancel(true);
}
}