/* * Copyright (C) 2004-2014 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.individual.Venom; import java.util.ArrayList; import java.util.List; import ai.npc.AbstractNpcAI; import com.l2jserver.gameserver.ai.CtrlIntention; import com.l2jserver.gameserver.instancemanager.CastleManager; import com.l2jserver.gameserver.instancemanager.GlobalVariablesManager; import com.l2jserver.gameserver.model.Location; import com.l2jserver.gameserver.model.TeleportWhereType; import com.l2jserver.gameserver.model.actor.L2Attackable; import com.l2jserver.gameserver.model.actor.L2Npc; import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; import com.l2jserver.gameserver.model.events.impl.sieges.castle.OnCastleSiegeFinish; import com.l2jserver.gameserver.model.events.impl.sieges.castle.OnCastleSiegeStart; import com.l2jserver.gameserver.model.holders.SkillHolder; import com.l2jserver.gameserver.model.skills.Skill; import com.l2jserver.gameserver.model.zone.ZoneId; import com.l2jserver.gameserver.network.NpcStringId; import com.l2jserver.gameserver.network.clientpackets.Say2; /** * Venom AI on Rune Castle. * @author nonom, MELERIX */ public final class Venom extends AbstractNpcAI { private static final int CASTLE = 8; // Rune private static final int VENOM = 29054; private static final int TELEPORT_CUBE = 29055; private static final int DUNGEON_KEEPER = 35506; private static final byte ALIVE = 0; private static final byte DEAD = 1; private static final int HOURS_BEFORE = 24; private static final Location[] TARGET_TELEPORTS = { new Location(12860, -49158, 976), new Location(14878, -51339, 1024), new Location(15674, -49970, 864), new Location(15696, -48326, 864), new Location(14873, -46956, 1024), new Location(12157, -49135, -1088), new Location(12875, -46392, -288), new Location(14087, -46706, -288), new Location(14086, -51593, -288), new Location(12864, -51898, -288), new Location(15538, -49153, -1056), new Location(17001, -49149, -1064) }; private static final Location TRHONE = new Location(11025, -49152, -537); private static final Location DUNGEON = new Location(11882, -49216, -3008); private static final Location TELEPORT = new Location(12589, -49044, -3008); private static final Location CUBE = new Location(12047, -49211, -3009); private static final SkillHolder VENOM_STRIKE = new SkillHolder(4993, 1); private static final SkillHolder SONIC_STORM = new SkillHolder(4994, 1); private static final SkillHolder VENOM_TELEPORT = new SkillHolder(4995, 1); private static final SkillHolder RANGE_TELEPORT = new SkillHolder(4996, 1); private L2Npc _venom; private L2Npc _massymore; private Location _loc; private boolean _aggroMode = false; private boolean _prisonIsOpen = false; // @formatter:off private static final int[] TARGET_TELEPORTS_OFFSET = { 650, 100, 100, 100, 100, 650, 200, 200, 200, 200, 200, 650 }; // @formatter:on private static List _targets = new ArrayList<>(); private Venom() { super(Venom.class.getSimpleName(), "ai/individual"); addStartNpc(DUNGEON_KEEPER, TELEPORT_CUBE); addFirstTalkId(DUNGEON_KEEPER, TELEPORT_CUBE); addTalkId(DUNGEON_KEEPER, TELEPORT_CUBE); addSpawnId(VENOM, DUNGEON_KEEPER); addSpellFinishedId(VENOM); addAttackId(VENOM); addKillId(VENOM); addAggroRangeEnterId(VENOM); setCastleSiegeStartId(this::onSiegeStart, CASTLE); setCastleSiegeFinishId(this::onSiegeFinish, CASTLE); final long currentTime = System.currentTimeMillis(); final long startSiegeDate = CastleManager.getInstance().getCastleById(CASTLE).getSiegeDate().getTimeInMillis(); final long openingDungeonDate = startSiegeDate - (HOURS_BEFORE * 360000); if ((currentTime > openingDungeonDate) && (currentTime < startSiegeDate)) { _prisonIsOpen = true; } } @Override public String onTalk(L2Npc npc, L2PcInstance talker) { switch (npc.getId()) { case TELEPORT_CUBE: { talker.teleToLocation(TeleportWhereType.TOWN); break; } case DUNGEON_KEEPER: { if (_prisonIsOpen) { talker.teleToLocation(TELEPORT); } else { return "35506-02.html"; } break; } } return super.onTalk(npc, talker); } @Override public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) { switch (event) { case "tower_check": if (CastleManager.getInstance().getCastleById(CASTLE).getSiege().getControlTowerCount() <= 1) { changeLocation(MoveTo.THRONE); broadcastNpcSay(_massymore, Say2.NPC_SHOUT, NpcStringId.OH_NO_THE_DEFENSES_HAVE_FAILED_IT_IS_TOO_DANGEROUS_TO_REMAIN_INSIDE_THE_CASTLE_FLEE_EVERY_MAN_FOR_HIMSELF); cancelQuestTimer("tower_check", npc, null); startQuestTimer("raid_check", 10000, npc, null, true); } break; case "raid_check": if (!npc.isInsideZone(ZoneId.SIEGE) && !npc.isTeleporting()) { npc.teleToLocation(_loc); } break; case "cube_despawn": if (npc != null) { npc.deleteMe(); } break; } return event; } @Override public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isSummon) { if (isSummon) { return super.onAggroRangeEnter(npc, player, isSummon); } if (_aggroMode && (_targets.size() < 10) && (getRandom(3) < 1) && !player.isDead()) { _targets.add(player); } return super.onAggroRangeEnter(npc, player, isSummon); } public void onSiegeStart(OnCastleSiegeStart event) { _aggroMode = true; _prisonIsOpen = false; if ((_venom != null) && !_venom.isDead()) { _venom.setCurrentHp(_venom.getMaxHp()); _venom.setCurrentMp(_venom.getMaxMp()); _venom.enableSkill(VENOM_TELEPORT.getSkill()); _venom.enableSkill(RANGE_TELEPORT.getSkill()); startQuestTimer("tower_check", 30000, _venom, null, true); } } public void onSiegeFinish(OnCastleSiegeFinish event) { _aggroMode = false; if ((_venom != null) && !_venom.isDead()) { changeLocation(MoveTo.PRISON); _venom.disableSkill(VENOM_TELEPORT.getSkill(), -1); _venom.disableSkill(RANGE_TELEPORT.getSkill(), -1); } updateStatus(ALIVE); cancelQuestTimer("tower_check", _venom, null); cancelQuestTimer("raid_check", _venom, null); } @Override public String onSpellFinished(L2Npc npc, L2PcInstance player, Skill skill) { switch (skill.getId()) { case 4222: npc.teleToLocation(_loc); break; case 4995: teleportTarget(player); ((L2Attackable) npc).stopHating(player); break; case 4996: teleportTarget(player); ((L2Attackable) npc).stopHating(player); if ((_targets != null) && (_targets.size() > 0)) { for (L2PcInstance target : _targets) { final long x = player.getX() - target.getX(); final long y = player.getY() - target.getY(); final long z = player.getZ() - target.getZ(); final long range = 250; if (((x * x) + (y * y) + (z * z)) <= (range * range)) { teleportTarget(target); ((L2Attackable) npc).stopHating(target); } } _targets.clear(); } break; } return super.onSpellFinished(npc, player, skill); } @Override public final String onSpawn(L2Npc npc) { switch (npc.getId()) { case DUNGEON_KEEPER: { _massymore = npc; break; } case VENOM: { _venom = npc; _loc = _venom.getLocation(); _venom.disableSkill(VENOM_TELEPORT.getSkill(), -1); _venom.disableSkill(RANGE_TELEPORT.getSkill(), -1); _venom.doRevive(); broadcastNpcSay(npc, Say2.NPC_SHOUT, NpcStringId.WHO_DARES_TO_COVET_THE_THRONE_OF_OUR_CASTLE_LEAVE_IMMEDIATELY_OR_YOU_WILL_PAY_THE_PRICE_OF_YOUR_AUDACITY_WITH_YOUR_VERY_OWN_BLOOD); ((L2Attackable) _venom).setCanReturnToSpawnPoint(false); if (checkStatus() == DEAD) { _venom.deleteMe(); } break; } } if (checkStatus() == DEAD) { npc.deleteMe(); } else { npc.doRevive(); } return super.onSpawn(npc); } @Override public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon) { final double distance = npc.calculateDistance(attacker, false, false); if (_aggroMode && (getRandom(100) < 25)) { npc.setTarget(attacker); npc.doCast(VENOM_TELEPORT.getSkill()); } else if (_aggroMode && (npc.getCurrentHp() < (npc.getMaxHp() / 3)) && (getRandom(100) < 25) && !npc.isCastingNow()) { npc.setTarget(attacker); npc.doCast(RANGE_TELEPORT.getSkill()); } else if ((distance > 300) && (getRandom(100) < 10) && !npc.isCastingNow()) { npc.setTarget(attacker); npc.doCast(VENOM_STRIKE.getSkill()); } else if ((getRandom(100) < 10) && !npc.isCastingNow()) { npc.setTarget(attacker); npc.doCast(SONIC_STORM.getSkill()); } return super.onAttack(npc, attacker, damage, isSummon); } @Override public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon) { updateStatus(DEAD); broadcastNpcSay(npc, Say2.NPC_SHOUT, NpcStringId.ITS_NOT_OVER_YET_IT_WONT_BE_OVER_LIKE_THIS_NEVER); if (!CastleManager.getInstance().getCastleById(CASTLE).getSiege().isInProgress()) { L2Npc cube = addSpawn(TELEPORT_CUBE, CUBE, false, 0); startQuestTimer("cube_despawn", 120000, cube, null); } cancelQuestTimer("raid_check", npc, null); return super.onKill(npc, killer, isSummon); } /** * Alters the Venom location * @param loc enum */ private void changeLocation(MoveTo loc) { switch (loc) { case THRONE: _venom.teleToLocation(TRHONE, false); break; case PRISON: if ((_venom == null) || _venom.isDead() || _venom.isDecayed()) { _venom = addSpawn(VENOM, DUNGEON, false, 0); } else { _venom.teleToLocation(DUNGEON, false); } cancelQuestTimer("raid_check", _venom, null); cancelQuestTimer("tower_check", _venom, null); break; } _loc.setLocation(_venom.getLocation()); } private void teleportTarget(L2PcInstance player) { if ((player != null) && !player.isDead()) { final int rnd = getRandom(11); player.teleToLocation(TARGET_TELEPORTS[rnd], TARGET_TELEPORTS_OFFSET[rnd]); player.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); } } /** * Checks if Venom is Alive or Dead * @return status */ private int checkStatus() { int checkStatus = ALIVE; if (GlobalVariablesManager.getInstance().hasVariable("VenomStatus")) { checkStatus = GlobalVariablesManager.getInstance().getInt("VenomStatus"); } else { GlobalVariablesManager.getInstance().set("VenomStatus", 0); } return checkStatus; } /** * Update the Venom status * @param status the new status. 0 = ALIVE, 1 = DEAD. */ private void updateStatus(int status) { GlobalVariablesManager.getInstance().set("VenomStatus", Integer.toString(status)); } private enum MoveTo { THRONE, PRISON } public static void main(String[] args) { new Venom(); } }