AltarsOfSacrifice.java 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  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.group_template;
  20. import java.util.logging.Level;
  21. import ai.npc.AbstractNpcAI;
  22. import com.l2jserver.gameserver.GeoData;
  23. import com.l2jserver.gameserver.datatables.NpcData;
  24. import com.l2jserver.gameserver.model.L2Spawn;
  25. import com.l2jserver.gameserver.model.Location;
  26. import com.l2jserver.gameserver.model.actor.L2Npc;
  27. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  28. import com.l2jserver.gameserver.model.interfaces.ILocational;
  29. import com.l2jserver.util.Rnd;
  30. /**
  31. * @author HorridoJoho, janiko, FinalDestination, lion
  32. */
  33. public final class AltarsOfSacrifice extends AbstractNpcAI
  34. {
  35. private final class Altar
  36. {
  37. private final ILocational _middlePoint;
  38. private final int[] _bossNpcIds;
  39. private L2Npc _spawnedBoss;
  40. protected Altar(final ILocational middlePoint, final int... bossNpcIds)
  41. {
  42. _middlePoint = middlePoint;
  43. _bossNpcIds = bossNpcIds;
  44. _spawnedBoss = null;
  45. }
  46. protected void spawnBoss() throws Exception
  47. {
  48. if (!hasBosses() || (_spawnedBoss != null))
  49. {
  50. throw new IllegalStateException();
  51. }
  52. final L2Spawn spawn = new L2Spawn(NpcData.getInstance().getTemplate(_bossNpcIds[Rnd.get(_bossNpcIds.length)]));
  53. spawn.setAmount(1);
  54. spawn.setHeading(Rnd.get(65536));
  55. int radius = Rnd.get(BOSS_MIN_SPAWN_RADIUS, BOSS_MAX_SPAWN_RADIUS);
  56. double angleRadians = Rnd.get() * 2 * Math.PI;
  57. int spawnX = (int) (radius * Math.cos(angleRadians)) + _middlePoint.getX();
  58. int spawnY = (int) (radius * Math.sin(angleRadians)) + _middlePoint.getY();
  59. spawn.setXYZ(spawnX, spawnY, GeoData.getInstance().getHeight(spawnX, spawnY, _middlePoint.getZ()));
  60. spawn.stopRespawn();
  61. _spawnedBoss = spawn.spawnOne(false);
  62. }
  63. protected void despawnBoss()
  64. {
  65. if (_spawnedBoss != null)
  66. {
  67. _spawnedBoss.deleteMe();
  68. _spawnedBoss = null;
  69. }
  70. }
  71. protected void unload()
  72. {
  73. despawnBoss();
  74. }
  75. protected boolean hasBosses()
  76. {
  77. return _bossNpcIds.length > 0;
  78. }
  79. protected boolean isBossFighting()
  80. {
  81. return (_spawnedBoss != null) && _spawnedBoss.isInCombat();
  82. }
  83. }
  84. private static final String EVT_SPAWN_BOSS_PRE = "spawnboss";
  85. private static final String EVT_DESPAWN_BOSS_PRE = "despawnboss";
  86. private static final int BOSS_MIN_SPAWN_RADIUS = 250;
  87. private static final int BOSS_MAX_SPAWN_RADIUS = 500;
  88. // every 240 minutes/4 hours, altars change
  89. private static final long ALTAR_STATE_CHANGE_DELAY = 240 * 60 * 1000;
  90. // disabling formatter here to make this easily readable
  91. // @formatter:off
  92. private final Altar[] _altars = new Altar[]
  93. {
  94. // TalkingIsland
  95. new Altar
  96. (
  97. new Location(-92481, 244812, -3505)
  98. ),
  99. // Elven
  100. new Altar
  101. (
  102. new Location(40241, 53974, -3262)
  103. ),
  104. // DarkElven
  105. new Altar
  106. (
  107. new Location(1851, 21697, -3305),
  108. 25750
  109. ),
  110. // Dwarven
  111. new Altar
  112. (
  113. new Location(130133, -180968, -3271),
  114. 25800, 25782
  115. ),
  116. // Orc
  117. new Altar
  118. (
  119. new Location(-45329, -118327, -166),
  120. 25779
  121. ),
  122. // Kamael
  123. new Altar
  124. (
  125. new Location(-104031, 45059, -1417)
  126. ),
  127. // Oren
  128. new Altar
  129. (
  130. new Location(80188, 47037, -3109),
  131. 25767, 25770
  132. ),
  133. // Gludin
  134. new Altar
  135. (
  136. new Location(-86620, 151536, -3018),
  137. 25735, 25738, 25741
  138. ),
  139. // Gludio
  140. new Altar
  141. (
  142. new Location(-14152, 120674, -2935),
  143. 25744, 25747
  144. ),
  145. // Dion
  146. new Altar
  147. (
  148. new Location(16715, 148320, -3210),
  149. 25753, 25754, 25757
  150. ),
  151. // Heine
  152. new Altar
  153. (
  154. new Location(120123, 219164, -3319),
  155. 25773, 25776
  156. ),
  157. // Giran
  158. new Altar
  159. (
  160. new Location(80712, 142538, -3487),
  161. 25760, 25763, 25766
  162. ),
  163. // Aden
  164. new Altar
  165. (
  166. new Location(152720, 24714, -2083),
  167. 25793, 25794, 25797
  168. ),
  169. // Rune
  170. new Altar
  171. (
  172. new Location(28010, -49175, -1278)
  173. ),
  174. // Goddard
  175. new Altar
  176. (
  177. new Location(152274, -57706, -3383),
  178. 25787, 25790
  179. ),
  180. // Schutgart
  181. new Altar
  182. (
  183. new Location(82066, -139418, -2220),
  184. 25784
  185. ),
  186. // Primeval
  187. new Altar
  188. (
  189. new Location(10998, -24068, -3603)
  190. ),
  191. // Dragon Valley
  192. new Altar
  193. (
  194. new Location(69592, 118694, -3417)
  195. )
  196. };
  197. // @formatter:on
  198. public static void main(String[] args)
  199. {
  200. new AltarsOfSacrifice();
  201. }
  202. private AltarsOfSacrifice()
  203. {
  204. super("AltarsOfSacrifice", "ai/group_template");
  205. for (int i = 0; i < _altars.length; ++i)
  206. {
  207. if (_altars[i].hasBosses())
  208. {
  209. startQuestTimer(makeSpawnBossEvt(i), ALTAR_STATE_CHANGE_DELAY, null, null);
  210. }
  211. }
  212. }
  213. private String makeSpawnBossEvt(int altarIndex)
  214. {
  215. return EVT_SPAWN_BOSS_PRE + altarIndex;
  216. }
  217. private String makeDespawnBossEvt(int altarIndex)
  218. {
  219. return EVT_DESPAWN_BOSS_PRE + altarIndex;
  220. }
  221. private boolean isSpawnBossEvt(String event)
  222. {
  223. return event.startsWith(EVT_SPAWN_BOSS_PRE);
  224. }
  225. private boolean isDespawnBossEvt(String event)
  226. {
  227. return event.startsWith(EVT_DESPAWN_BOSS_PRE);
  228. }
  229. private int getSpawnBossIndex(String event)
  230. {
  231. return Integer.parseInt(event.substring(EVT_SPAWN_BOSS_PRE.length()));
  232. }
  233. private int getDespawnBossIndex(String event)
  234. {
  235. return Integer.parseInt(event.substring(EVT_DESPAWN_BOSS_PRE.length()));
  236. }
  237. @Override
  238. public boolean unload(boolean removeFromList)
  239. {
  240. _log.info(getClass().getSimpleName() + ": Unloading altars due to script unloading.");
  241. for (final Altar altar : _altars)
  242. {
  243. altar.unload();
  244. }
  245. return super.unload(removeFromList);
  246. }
  247. @Override
  248. public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
  249. {
  250. if (isSpawnBossEvt(event))
  251. {
  252. final int altarIndex = getSpawnBossIndex(event);
  253. final Altar altar = _altars[altarIndex];
  254. try
  255. {
  256. altar.spawnBoss();
  257. startQuestTimer(makeDespawnBossEvt(altarIndex), ALTAR_STATE_CHANGE_DELAY, null, null);
  258. }
  259. catch (Exception e)
  260. {
  261. _log.log(Level.WARNING, getClass().getSimpleName() + ": Failed to spawn altar boss.", e);
  262. // let's try again to spawn it in 5 seconds
  263. startQuestTimer(event, 5000, null, null);
  264. }
  265. }
  266. else if (isDespawnBossEvt(event))
  267. {
  268. final int altarIndex = getDespawnBossIndex(event);
  269. final Altar altar = _altars[altarIndex];
  270. if (altar.isBossFighting())
  271. {
  272. // periodically check if the altar boss is fighting, only despawn when not fighting anymore
  273. startQuestTimer(event, 5000, null, null);
  274. }
  275. else
  276. {
  277. altar.despawnBoss();
  278. startQuestTimer(makeSpawnBossEvt(altarIndex), ALTAR_STATE_CHANGE_DELAY, null, null);
  279. }
  280. }
  281. return null;
  282. }
  283. }