Venom.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. /*
  2. * Copyright (C) 2004-2014 L2J DataPack
  3. *
  4. * This file is part of L2J DataPack.
  5. *
  6. * L2J DataPack is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * L2J DataPack is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. package ai.individual.Venom;
  20. import java.util.ArrayList;
  21. import java.util.List;
  22. import ai.npc.AbstractNpcAI;
  23. import com.l2jserver.gameserver.ai.CtrlIntention;
  24. import com.l2jserver.gameserver.instancemanager.CastleManager;
  25. import com.l2jserver.gameserver.instancemanager.GlobalVariablesManager;
  26. import com.l2jserver.gameserver.model.Location;
  27. import com.l2jserver.gameserver.model.TeleportWhereType;
  28. import com.l2jserver.gameserver.model.actor.L2Attackable;
  29. import com.l2jserver.gameserver.model.actor.L2Npc;
  30. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  31. import com.l2jserver.gameserver.model.events.impl.sieges.castle.OnCastleSiegeFinish;
  32. import com.l2jserver.gameserver.model.events.impl.sieges.castle.OnCastleSiegeStart;
  33. import com.l2jserver.gameserver.model.holders.SkillHolder;
  34. import com.l2jserver.gameserver.model.skills.Skill;
  35. import com.l2jserver.gameserver.model.zone.ZoneId;
  36. import com.l2jserver.gameserver.network.NpcStringId;
  37. import com.l2jserver.gameserver.network.clientpackets.Say2;
  38. /**
  39. * Venom AI on Rune Castle.
  40. * @author nonom, MELERIX
  41. */
  42. public final class Venom extends AbstractNpcAI
  43. {
  44. private static final int CASTLE = 8; // Rune
  45. private static final int VENOM = 29054;
  46. private static final int TELEPORT_CUBE = 29055;
  47. private static final int DUNGEON_KEEPER = 35506;
  48. private static final byte ALIVE = 0;
  49. private static final byte DEAD = 1;
  50. private static final int HOURS_BEFORE = 24;
  51. private static final Location[] TARGET_TELEPORTS =
  52. {
  53. new Location(12860, -49158, 976),
  54. new Location(14878, -51339, 1024),
  55. new Location(15674, -49970, 864),
  56. new Location(15696, -48326, 864),
  57. new Location(14873, -46956, 1024),
  58. new Location(12157, -49135, -1088),
  59. new Location(12875, -46392, -288),
  60. new Location(14087, -46706, -288),
  61. new Location(14086, -51593, -288),
  62. new Location(12864, -51898, -288),
  63. new Location(15538, -49153, -1056),
  64. new Location(17001, -49149, -1064)
  65. };
  66. private static final Location TRHONE = new Location(11025, -49152, -537);
  67. private static final Location DUNGEON = new Location(11882, -49216, -3008);
  68. private static final Location TELEPORT = new Location(12589, -49044, -3008);
  69. private static final Location CUBE = new Location(12047, -49211, -3009);
  70. private static final SkillHolder VENOM_STRIKE = new SkillHolder(4993, 1);
  71. private static final SkillHolder SONIC_STORM = new SkillHolder(4994, 1);
  72. private static final SkillHolder VENOM_TELEPORT = new SkillHolder(4995, 1);
  73. private static final SkillHolder RANGE_TELEPORT = new SkillHolder(4996, 1);
  74. private L2Npc _venom;
  75. private L2Npc _massymore;
  76. private Location _loc;
  77. private boolean _aggroMode = false;
  78. private boolean _prisonIsOpen = false;
  79. // @formatter:off
  80. private static final int[] TARGET_TELEPORTS_OFFSET =
  81. {
  82. 650, 100, 100, 100, 100, 650, 200, 200, 200, 200, 200, 650
  83. };
  84. // @formatter:on
  85. private static List<L2PcInstance> _targets = new ArrayList<>();
  86. private Venom()
  87. {
  88. super(Venom.class.getSimpleName(), "ai/individual");
  89. addStartNpc(DUNGEON_KEEPER, TELEPORT_CUBE);
  90. addFirstTalkId(DUNGEON_KEEPER, TELEPORT_CUBE);
  91. addTalkId(DUNGEON_KEEPER, TELEPORT_CUBE);
  92. addSpawnId(VENOM, DUNGEON_KEEPER);
  93. addSpellFinishedId(VENOM);
  94. addAttackId(VENOM);
  95. addKillId(VENOM);
  96. addAggroRangeEnterId(VENOM);
  97. setCastleSiegeStartId(this::onSiegeStart, CASTLE);
  98. setCastleSiegeFinishId(this::onSiegeFinish, CASTLE);
  99. final long currentTime = System.currentTimeMillis();
  100. final long startSiegeDate = CastleManager.getInstance().getCastleById(CASTLE).getSiegeDate().getTimeInMillis();
  101. final long openingDungeonDate = startSiegeDate - (HOURS_BEFORE * 360000);
  102. if ((currentTime > openingDungeonDate) && (currentTime < startSiegeDate))
  103. {
  104. _prisonIsOpen = true;
  105. }
  106. }
  107. @Override
  108. public String onTalk(L2Npc npc, L2PcInstance talker)
  109. {
  110. switch (npc.getId())
  111. {
  112. case TELEPORT_CUBE:
  113. {
  114. talker.teleToLocation(TeleportWhereType.TOWN);
  115. break;
  116. }
  117. case DUNGEON_KEEPER:
  118. {
  119. if (_prisonIsOpen)
  120. {
  121. talker.teleToLocation(TELEPORT);
  122. }
  123. else
  124. {
  125. return "35506-02.html";
  126. }
  127. break;
  128. }
  129. }
  130. return super.onTalk(npc, talker);
  131. }
  132. @Override
  133. public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
  134. {
  135. switch (event)
  136. {
  137. case "tower_check":
  138. if (CastleManager.getInstance().getCastleById(CASTLE).getSiege().getControlTowerCount() <= 1)
  139. {
  140. changeLocation(MoveTo.THRONE);
  141. 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);
  142. cancelQuestTimer("tower_check", npc, null);
  143. startQuestTimer("raid_check", 10000, npc, null, true);
  144. }
  145. break;
  146. case "raid_check":
  147. if (!npc.isInsideZone(ZoneId.SIEGE) && !npc.isTeleporting())
  148. {
  149. npc.teleToLocation(_loc);
  150. }
  151. break;
  152. case "cube_despawn":
  153. if (npc != null)
  154. {
  155. npc.deleteMe();
  156. }
  157. break;
  158. }
  159. return event;
  160. }
  161. @Override
  162. public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isSummon)
  163. {
  164. if (isSummon)
  165. {
  166. return super.onAggroRangeEnter(npc, player, isSummon);
  167. }
  168. if (_aggroMode && (_targets.size() < 10) && (getRandom(3) < 1) && !player.isDead())
  169. {
  170. _targets.add(player);
  171. }
  172. return super.onAggroRangeEnter(npc, player, isSummon);
  173. }
  174. public void onSiegeStart(OnCastleSiegeStart event)
  175. {
  176. _aggroMode = true;
  177. _prisonIsOpen = false;
  178. if ((_venom != null) && !_venom.isDead())
  179. {
  180. _venom.setCurrentHp(_venom.getMaxHp());
  181. _venom.setCurrentMp(_venom.getMaxMp());
  182. _venom.enableSkill(VENOM_TELEPORT.getSkill());
  183. _venom.enableSkill(RANGE_TELEPORT.getSkill());
  184. startQuestTimer("tower_check", 30000, _venom, null, true);
  185. }
  186. }
  187. public void onSiegeFinish(OnCastleSiegeFinish event)
  188. {
  189. _aggroMode = false;
  190. if ((_venom != null) && !_venom.isDead())
  191. {
  192. changeLocation(MoveTo.PRISON);
  193. _venom.disableSkill(VENOM_TELEPORT.getSkill(), -1);
  194. _venom.disableSkill(RANGE_TELEPORT.getSkill(), -1);
  195. }
  196. updateStatus(ALIVE);
  197. cancelQuestTimer("tower_check", _venom, null);
  198. cancelQuestTimer("raid_check", _venom, null);
  199. }
  200. @Override
  201. public String onSpellFinished(L2Npc npc, L2PcInstance player, Skill skill)
  202. {
  203. switch (skill.getId())
  204. {
  205. case 4222:
  206. npc.teleToLocation(_loc);
  207. break;
  208. case 4995:
  209. teleportTarget(player);
  210. ((L2Attackable) npc).stopHating(player);
  211. break;
  212. case 4996:
  213. teleportTarget(player);
  214. ((L2Attackable) npc).stopHating(player);
  215. if ((_targets != null) && (_targets.size() > 0))
  216. {
  217. for (L2PcInstance target : _targets)
  218. {
  219. final long x = player.getX() - target.getX();
  220. final long y = player.getY() - target.getY();
  221. final long z = player.getZ() - target.getZ();
  222. final long range = 250;
  223. if (((x * x) + (y * y) + (z * z)) <= (range * range))
  224. {
  225. teleportTarget(target);
  226. ((L2Attackable) npc).stopHating(target);
  227. }
  228. }
  229. _targets.clear();
  230. }
  231. break;
  232. }
  233. return super.onSpellFinished(npc, player, skill);
  234. }
  235. @Override
  236. public final String onSpawn(L2Npc npc)
  237. {
  238. switch (npc.getId())
  239. {
  240. case DUNGEON_KEEPER:
  241. {
  242. _massymore = npc;
  243. break;
  244. }
  245. case VENOM:
  246. {
  247. _venom = npc;
  248. _loc = _venom.getLocation();
  249. _venom.disableSkill(VENOM_TELEPORT.getSkill(), -1);
  250. _venom.disableSkill(RANGE_TELEPORT.getSkill(), -1);
  251. _venom.doRevive();
  252. 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);
  253. ((L2Attackable) _venom).setCanReturnToSpawnPoint(false);
  254. if (checkStatus() == DEAD)
  255. {
  256. _venom.deleteMe();
  257. }
  258. break;
  259. }
  260. }
  261. if (checkStatus() == DEAD)
  262. {
  263. npc.deleteMe();
  264. }
  265. else
  266. {
  267. npc.doRevive();
  268. }
  269. return super.onSpawn(npc);
  270. }
  271. @Override
  272. public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
  273. {
  274. final double distance = npc.calculateDistance(attacker, false, false);
  275. if (_aggroMode && (getRandom(100) < 25))
  276. {
  277. npc.setTarget(attacker);
  278. npc.doCast(VENOM_TELEPORT.getSkill());
  279. }
  280. else if (_aggroMode && (npc.getCurrentHp() < (npc.getMaxHp() / 3)) && (getRandom(100) < 25) && !npc.isCastingNow())
  281. {
  282. npc.setTarget(attacker);
  283. npc.doCast(RANGE_TELEPORT.getSkill());
  284. }
  285. else if ((distance > 300) && (getRandom(100) < 10) && !npc.isCastingNow())
  286. {
  287. npc.setTarget(attacker);
  288. npc.doCast(VENOM_STRIKE.getSkill());
  289. }
  290. else if ((getRandom(100) < 10) && !npc.isCastingNow())
  291. {
  292. npc.setTarget(attacker);
  293. npc.doCast(SONIC_STORM.getSkill());
  294. }
  295. return super.onAttack(npc, attacker, damage, isSummon);
  296. }
  297. @Override
  298. public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
  299. {
  300. updateStatus(DEAD);
  301. broadcastNpcSay(npc, Say2.NPC_SHOUT, NpcStringId.ITS_NOT_OVER_YET_IT_WONT_BE_OVER_LIKE_THIS_NEVER);
  302. if (!CastleManager.getInstance().getCastleById(CASTLE).getSiege().isInProgress())
  303. {
  304. L2Npc cube = addSpawn(TELEPORT_CUBE, CUBE, false, 0);
  305. startQuestTimer("cube_despawn", 120000, cube, null);
  306. }
  307. cancelQuestTimer("raid_check", npc, null);
  308. return super.onKill(npc, killer, isSummon);
  309. }
  310. /**
  311. * Alters the Venom location
  312. * @param loc enum
  313. */
  314. private void changeLocation(MoveTo loc)
  315. {
  316. switch (loc)
  317. {
  318. case THRONE:
  319. _venom.teleToLocation(TRHONE, false);
  320. break;
  321. case PRISON:
  322. if ((_venom == null) || _venom.isDead() || _venom.isDecayed())
  323. {
  324. _venom = addSpawn(VENOM, DUNGEON, false, 0);
  325. }
  326. else
  327. {
  328. _venom.teleToLocation(DUNGEON, false);
  329. }
  330. cancelQuestTimer("raid_check", _venom, null);
  331. cancelQuestTimer("tower_check", _venom, null);
  332. break;
  333. }
  334. _loc.setLocation(_venom.getLocation());
  335. }
  336. private void teleportTarget(L2PcInstance player)
  337. {
  338. if ((player != null) && !player.isDead())
  339. {
  340. final int rnd = getRandom(11);
  341. player.teleToLocation(TARGET_TELEPORTS[rnd], TARGET_TELEPORTS_OFFSET[rnd]);
  342. player.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
  343. }
  344. }
  345. /**
  346. * Checks if Venom is Alive or Dead
  347. * @return status
  348. */
  349. private int checkStatus()
  350. {
  351. int checkStatus = ALIVE;
  352. if (GlobalVariablesManager.getInstance().hasVariable("VenomStatus"))
  353. {
  354. checkStatus = GlobalVariablesManager.getInstance().getInt("VenomStatus");
  355. }
  356. else
  357. {
  358. GlobalVariablesManager.getInstance().set("VenomStatus", 0);
  359. }
  360. return checkStatus;
  361. }
  362. /**
  363. * Update the Venom status
  364. * @param status the new status. 0 = ALIVE, 1 = DEAD.
  365. */
  366. private void updateStatus(int status)
  367. {
  368. GlobalVariablesManager.getInstance().set("VenomStatus", Integer.toString(status));
  369. }
  370. private enum MoveTo
  371. {
  372. THRONE,
  373. PRISON
  374. }
  375. public static void main(String[] args)
  376. {
  377. new Venom();
  378. }
  379. }