/* * 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 silentium.scripts.ai; import javolution.util.FastList; import silentium.commons.utils.Rnd; import silentium.gameserver.ai.CtrlIntention; import silentium.gameserver.ai.DefaultMonsterAI; import silentium.gameserver.configs.NPCConfig; import silentium.gameserver.instancemanager.GrandBossManager; import silentium.gameserver.model.actor.L2Attackable; import silentium.gameserver.model.actor.L2Npc; import silentium.gameserver.model.actor.instance.L2GrandBossInstance; import silentium.gameserver.model.actor.instance.L2MonsterInstance; import silentium.gameserver.model.actor.instance.L2PcInstance; import silentium.gameserver.model.zone.type.L2BossZone; import silentium.gameserver.network.serverpackets.PlaySound; import silentium.gameserver.network.serverpackets.SocialAction; import silentium.gameserver.scripting.ScriptFile; import silentium.gameserver.skills.SkillHolder; import silentium.gameserver.templates.StatsSet; import java.util.List; /** * Queen Ant AI * * @author Emperorc */ public class QueenAnt extends DefaultMonsterAI implements ScriptFile { private static final int QUEEN = 29001; private static final int LARVA = 29002; private static final int NURSE = 29003; private static final int GUARD = 29004; private static final int ROYAL = 29005; private static final int[] MOBS = { QUEEN, LARVA, NURSE, GUARD, ROYAL }; private static final int QUEEN_X = -21610; private static final int QUEEN_Y = 181594; private static final int QUEEN_Z = -5734; // Status Tracking private static final byte ALIVE = 0; // Queen Ant is spawned. private static final byte DEAD = 1; // Queen Ant has been killed. private static L2BossZone _zone; private static final SkillHolder HEAL1 = new SkillHolder(4020, 1); private static final SkillHolder HEAL2 = new SkillHolder(4024, 1); private L2MonsterInstance _queen = null; private L2MonsterInstance _larva = null; private final List<L2MonsterInstance> _nurses = new FastList<>(5); public static void onLoad() { new QueenAnt(-1, "QueenAnt", "QueenAnt", "ai"); } public QueenAnt(final int scriptId, final String name, final String dname, final String path) { super(scriptId, name, dname, path); registerMobs(MOBS, QuestEventType.ON_SPAWN, QuestEventType.ON_KILL); addFactionCallId(NURSE); _zone = GrandBossManager.getInstance().getZone(QUEEN_X, QUEEN_Y, QUEEN_Z); final StatsSet info = GrandBossManager.getInstance().getStatsSet(QUEEN); if (GrandBossManager.getInstance().getBossStatus(QUEEN) == DEAD) { // load the unlock date and time for queen ant from DB final long temp = info.getLong("respawn_time") - System.currentTimeMillis(); // the unlock time has not yet expired. if (temp > 0) startQuestTimer("queen_unlock", temp, null, null); // the time has already expired while the server was offline. Immediately spawn queen ant. else { final L2GrandBossInstance queen = (L2GrandBossInstance) addSpawn(QUEEN, QUEEN_X, QUEEN_Y, QUEEN_Z, 0, false, 0); GrandBossManager.getInstance().setBossStatus(QUEEN, ALIVE); spawnBoss(queen); } } else { int loc_x = info.getInteger("loc_x"); int loc_y = info.getInteger("loc_y"); int loc_z = info.getInteger("loc_z"); final int heading = info.getInteger("heading"); final int hp = info.getInteger("currentHP"); final int mp = info.getInteger("currentMP"); if (!_zone.isInsideZone(loc_x, loc_y, loc_z)) { loc_x = QUEEN_X; loc_y = QUEEN_Y; loc_z = QUEEN_Z; } final L2GrandBossInstance queen = (L2GrandBossInstance) addSpawn(QUEEN, loc_x, loc_y, loc_z, heading, false, 0); queen.setCurrentHpMp(hp, mp); spawnBoss(queen); } } private void spawnBoss(final L2GrandBossInstance npc) { if (Rnd.get(100) < 33) _zone.movePlayersTo(-19480, 187344, -5600); else if (Rnd.get(100) < 50) _zone.movePlayersTo(-17928, 180912, -5520); else _zone.movePlayersTo(-23808, 182368, -5600); GrandBossManager.getInstance().addBoss(npc); startQuestTimer("action", 10000, npc, null, true); startQuestTimer("heal", 1000, null, null, true); npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ())); _queen = npc; _larva = (L2MonsterInstance) addSpawn(LARVA, -21600, 179482, -5846, Rnd.get(360), false, 0); } @Override public String onAdvEvent(final String event, final L2Npc npc, final L2PcInstance player) { if ("heal".equalsIgnoreCase(event)) { boolean notCasting; final boolean larvaNeedHeal = _larva != null && _larva.getCurrentHp() < _larva.getMaxHp(); final boolean queenNeedHeal = _queen != null && _queen.getCurrentHp() < _queen.getMaxHp(); for (final L2MonsterInstance nurse : _nurses) { if (nurse == null || nurse.isDead() || nurse.isCastingNow()) continue; notCasting = nurse.getAI().getIntention() != CtrlIntention.AI_INTENTION_CAST; if (larvaNeedHeal) { if (nurse.getTarget() != _larva || notCasting) { nurse.setTarget(_larva); nurse.useMagic(Rnd.nextBoolean() ? HEAL1.getSkill() : HEAL2.getSkill()); } continue; } if (queenNeedHeal) { if (nurse.getLeader() == _larva) // skip larva's minions continue; if (nurse.getTarget() != _queen || notCasting) { nurse.setTarget(_queen); nurse.useMagic(HEAL1.getSkill()); } continue; } // if nurse not casting - remove target if (notCasting && nurse.getTarget() != null) nurse.setTarget(null); } } else if ("action".equalsIgnoreCase(event) && npc != null) { if (Rnd.get(3) == 0) { if (Rnd.get(2) == 0) npc.broadcastPacket(new SocialAction(npc, 3)); else npc.broadcastPacket(new SocialAction(npc, 4)); } } else if ("queen_unlock".equalsIgnoreCase(event)) { final L2GrandBossInstance queen = (L2GrandBossInstance) addSpawn(QUEEN, QUEEN_X, QUEEN_Y, QUEEN_Z, 0, false, 0); GrandBossManager.getInstance().setBossStatus(QUEEN, ALIVE); spawnBoss(queen); } return super.onAdvEvent(event, npc, player); } @Override public String onSpawn(final L2Npc npc) { final L2MonsterInstance mob = (L2MonsterInstance) npc; switch (npc.getNpcId()) { case LARVA: mob.setIsImmobilized(true); mob.setIsMortal(false); mob.setIsRaidMinion(true); break; case NURSE: mob.disableCoreAI(true); mob.setIsRaidMinion(true); _nurses.add(mob); break; case ROYAL: case GUARD: mob.setIsRaidMinion(true); break; } return super.onSpawn(npc); } @Override public String onFactionCall(final L2Npc npc, final L2Npc caller, final L2PcInstance attacker, final boolean isPet) { if (caller == null || npc == null) return super.onFactionCall(npc, caller, attacker, isPet); if (!npc.isCastingNow() && npc.getAI().getIntention() != CtrlIntention.AI_INTENTION_CAST) { if (caller.getCurrentHp() < caller.getMaxHp()) { npc.setTarget(caller); ((L2Attackable) npc).useMagic(HEAL1.getSkill()); } } return null; } @Override public String onKill(final L2Npc npc, final L2PcInstance killer, final boolean isPet) { // Acts only once. if (GrandBossManager.getInstance().getBossStatus(QUEEN) == ALIVE) { final int npcId = npc.getNpcId(); if (npcId == QUEEN) { npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ())); GrandBossManager.getInstance().setBossStatus(QUEEN, DEAD); // time is 36hour +/- 17hour final long respawnTime = (long) NPCConfig.SPAWN_INTERVAL_AQ + Rnd.get(NPCConfig.RANDOM_SPAWN_TIME_AQ); startQuestTimer("queen_unlock", respawnTime, null, null); cancelQuestTimer("action", npc, null); cancelQuestTimer("heal", null, null); // also save the respawn time so that the info is maintained past reboots final StatsSet info = GrandBossManager.getInstance().getStatsSet(QUEEN); info.set("respawn_time", System.currentTimeMillis() + respawnTime); GrandBossManager.getInstance().setStatsSet(QUEEN, info); _nurses.clear(); _larva.deleteMe(); _larva = null; _queen = null; } else { if (npcId == ROYAL) { final L2MonsterInstance mob = (L2MonsterInstance) npc; if (mob.getLeader() != null) mob.getLeader().getMinionList().onMinionDie(mob, (280 + Rnd.get(40)) * 1000); } else if (npcId == NURSE) { final L2MonsterInstance mob = (L2MonsterInstance) npc; _nurses.remove(mob); if (mob.getLeader() != null) mob.getLeader().getMinionList().onMinionDie(mob, 10000); } } } return super.onKill(npc, killer, isPet); } }