/* * Copyright (C) 2004-2015 L2J DataPack * * This file is part of L2J DataPack. * * L2J DataPack is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * L2J DataPack is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package ai.group_template; import java.util.logging.Level; import ai.npc.AbstractNpcAI; import com.l2jserver.gameserver.GeoData; import com.l2jserver.gameserver.model.L2Spawn; import com.l2jserver.gameserver.model.Location; import com.l2jserver.gameserver.model.actor.L2Npc; import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; import com.l2jserver.gameserver.model.interfaces.ILocational; import com.l2jserver.util.Rnd; /** * @author HorridoJoho, janiko, FinalDestination, lion */ public final class AltarsOfSacrifice extends AbstractNpcAI { private final class Altar { private final ILocational _middlePoint; private final int[] _bossNpcIds; private L2Npc _spawnedBoss; protected Altar(final ILocational middlePoint, final int... bossNpcIds) { _middlePoint = middlePoint; _bossNpcIds = bossNpcIds; _spawnedBoss = null; } protected void spawnBoss() throws Exception { if (!hasBosses() || (_spawnedBoss != null)) { throw new IllegalStateException(); } final L2Spawn spawn = new L2Spawn(_bossNpcIds[Rnd.get(_bossNpcIds.length)]); spawn.setAmount(1); spawn.setHeading(Rnd.get(65536)); int radius = Rnd.get(BOSS_MIN_SPAWN_RADIUS, BOSS_MAX_SPAWN_RADIUS); double angleRadians = Rnd.get() * 2 * Math.PI; int spawnX = (int) (radius * Math.cos(angleRadians)) + _middlePoint.getX(); int spawnY = (int) (radius * Math.sin(angleRadians)) + _middlePoint.getY(); spawn.setXYZ(spawnX, spawnY, GeoData.getInstance().getHeight(spawnX, spawnY, _middlePoint.getZ())); spawn.stopRespawn(); _spawnedBoss = spawn.spawnOne(false); } protected void despawnBoss() { if (_spawnedBoss != null) { _spawnedBoss.deleteMe(); _spawnedBoss = null; } } protected void unload() { despawnBoss(); } protected boolean hasBosses() { return _bossNpcIds.length > 0; } protected boolean isBossFighting() { return (_spawnedBoss != null) && _spawnedBoss.isInCombat(); } } private static final String EVT_SPAWN_BOSS_PRE = "spawnboss"; private static final String EVT_DESPAWN_BOSS_PRE = "despawnboss"; private static final int BOSS_MIN_SPAWN_RADIUS = 250; private static final int BOSS_MAX_SPAWN_RADIUS = 500; // every 240 minutes/4 hours, altars change private static final long ALTAR_STATE_CHANGE_DELAY = 240 * 60 * 1000; // disabling formatter here to make this easily readable // @formatter:off private final Altar[] _altars = new Altar[] { // TalkingIsland new Altar ( new Location(-92481, 244812, -3505) ), // Elven new Altar ( new Location(40241, 53974, -3262) ), // DarkElven new Altar ( new Location(1851, 21697, -3305), 25750 ), // Dwarven new Altar ( new Location(130133, -180968, -3271), 25800, 25782 ), // Orc new Altar ( new Location(-45329, -118327, -166), 25779 ), // Kamael new Altar ( new Location(-104031, 45059, -1417) ), // Oren new Altar ( new Location(80188, 47037, -3109), 25767, 25770 ), // Gludin new Altar ( new Location(-86620, 151536, -3018), 25735, 25738, 25741 ), // Gludio new Altar ( new Location(-14152, 120674, -2935), 25744, 25747 ), // Dion new Altar ( new Location(16715, 148320, -3210), 25753, 25754, 25757 ), // Heine new Altar ( new Location(120123, 219164, -3319), 25773, 25776 ), // Giran new Altar ( new Location(80712, 142538, -3487), 25760, 25763, 25766 ), // Aden new Altar ( new Location(152720, 24714, -2083), 25793, 25794, 25797 ), // Rune new Altar ( new Location(28010, -49175, -1278) ), // Goddard new Altar ( new Location(152274, -57706, -3383), 25787, 25790 ), // Schutgart new Altar ( new Location(82066, -139418, -2220), 25784 ), // Primeval new Altar ( new Location(10998, -24068, -3603) ), // Dragon Valley new Altar ( new Location(69592, 118694, -3417) ) }; // @formatter:on public static void main(String[] args) { new AltarsOfSacrifice(); } private AltarsOfSacrifice() { super("AltarsOfSacrifice", "ai/group_template"); for (int i = 0; i < _altars.length; ++i) { if (_altars[i].hasBosses()) { startQuestTimer(makeSpawnBossEvt(i), ALTAR_STATE_CHANGE_DELAY, null, null); } } } private String makeSpawnBossEvt(int altarIndex) { return EVT_SPAWN_BOSS_PRE + altarIndex; } private String makeDespawnBossEvt(int altarIndex) { return EVT_DESPAWN_BOSS_PRE + altarIndex; } private boolean isSpawnBossEvt(String event) { return event.startsWith(EVT_SPAWN_BOSS_PRE); } private boolean isDespawnBossEvt(String event) { return event.startsWith(EVT_DESPAWN_BOSS_PRE); } private int getSpawnBossIndex(String event) { return Integer.parseInt(event.substring(EVT_SPAWN_BOSS_PRE.length())); } private int getDespawnBossIndex(String event) { return Integer.parseInt(event.substring(EVT_DESPAWN_BOSS_PRE.length())); } @Override public boolean unload(boolean removeFromList) { _log.info(getClass().getSimpleName() + ": Unloading altars due to script unloading."); for (final Altar altar : _altars) { altar.unload(); } return super.unload(removeFromList); } @Override public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) { if (isSpawnBossEvt(event)) { final int altarIndex = getSpawnBossIndex(event); final Altar altar = _altars[altarIndex]; try { altar.spawnBoss(); startQuestTimer(makeDespawnBossEvt(altarIndex), ALTAR_STATE_CHANGE_DELAY, null, null); } catch (Exception e) { _log.log(Level.WARNING, getClass().getSimpleName() + ": Failed to spawn altar boss.", e); // let's try again to spawn it in 5 seconds startQuestTimer(event, 5000, null, null); } } else if (isDespawnBossEvt(event)) { final int altarIndex = getDespawnBossIndex(event); final Altar altar = _altars[altarIndex]; if (altar.isBossFighting()) { // periodically check if the altar boss is fighting, only despawn when not fighting anymore startQuestTimer(event, 5000, null, null); } else { altar.despawnBoss(); startQuestTimer(makeSpawnBossEvt(altarIndex), ALTAR_STATE_CHANGE_DELAY, null, null); } } return null; } }