Minigame.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. /*
  2. * Copyright (C) 2004-2015 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.npc.Minigame;
  20. import java.util.ArrayList;
  21. import java.util.List;
  22. import ai.npc.AbstractNpcAI;
  23. import com.l2jserver.gameserver.datatables.SpawnTable;
  24. import com.l2jserver.gameserver.model.L2Object;
  25. import com.l2jserver.gameserver.model.L2Spawn;
  26. import com.l2jserver.gameserver.model.Location;
  27. import com.l2jserver.gameserver.model.actor.L2Npc;
  28. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  29. import com.l2jserver.gameserver.model.events.EventType;
  30. import com.l2jserver.gameserver.model.events.impl.character.OnCreatureSkillUse;
  31. import com.l2jserver.gameserver.model.events.listeners.ConsumerEventListener;
  32. import com.l2jserver.gameserver.model.holders.SkillHolder;
  33. import com.l2jserver.gameserver.network.NpcStringId;
  34. import com.l2jserver.gameserver.network.clientpackets.Say2;
  35. import com.l2jserver.gameserver.util.Util;
  36. /**
  37. * Monastery Minigame AI.
  38. * @author nonom
  39. */
  40. public final class Minigame extends AbstractNpcAI
  41. {
  42. private static final int SUMIEL = 32758;
  43. private static final int BURNER = 18913;
  44. private static final int TREASURE_BOX = 18911;
  45. private static final int UNLIT_TORCHLIGHT = 15540;
  46. private static final int TORCHLIGHT = 15485;
  47. private static final int SKILL_TORCH_LIGHT = 9059;
  48. private static final SkillHolder TRIGGER_MIRAGE = new SkillHolder(5144, 1);
  49. private static final Location TELEPORT1 = new Location(113187, -85388, -3424, 0);
  50. private static final Location TELEPORT2 = new Location(118833, -80589, -2688, 0);
  51. private static final int TIMER_INTERVAL = 3;
  52. private static final int MAX_ATTEMPTS = 3;
  53. private final List<MinigameRoom> _rooms = new ArrayList<>(2);
  54. private Minigame()
  55. {
  56. super(Minigame.class.getSimpleName(), "ai/npc");
  57. addStartNpc(SUMIEL);
  58. addFirstTalkId(SUMIEL);
  59. addTalkId(SUMIEL);
  60. addSpawnId(SUMIEL, TREASURE_BOX);
  61. }
  62. @Override
  63. public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
  64. {
  65. final MinigameRoom room = getRoomByManager(npc);
  66. switch (event)
  67. {
  68. case "restart":
  69. {
  70. final boolean miniGameStarted = room.getStarted();
  71. if (!miniGameStarted && !hasQuestItems(player, UNLIT_TORCHLIGHT))
  72. {
  73. return "32758-05.html";
  74. }
  75. else if ((npc.getTarget() != null) && (npc.getTarget() != player))
  76. {
  77. return "32758-04.html";
  78. }
  79. takeItems(player, UNLIT_TORCHLIGHT, 1);
  80. giveItems(player, TORCHLIGHT, 1);
  81. broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.THE_FURNACE_WILL_GO_OUT_WATCH_AND_SEE);
  82. room.getManager().setTarget(player);
  83. room.setParticipant(player);
  84. room.setStarted(true);
  85. for (int i = 0; i < 9; i++)
  86. {
  87. room.getOrder()[i] = getRandom(8);
  88. }
  89. cancelQuestTimer("hurry_up", npc, null);
  90. cancelQuestTimer("hurry_up2", npc, null);
  91. cancelQuestTimer("expire", npc, null);
  92. startQuestTimer("hurry_up", 120000, npc, null);
  93. startQuestTimer("expire", 190000, npc, null);
  94. startQuestTimer("start", 1000, npc, null);
  95. return null;
  96. }
  97. case "off":
  98. {
  99. if (npc.getId() == BURNER)
  100. {
  101. npc.setDisplayEffect(2);
  102. npc.setIsRunning(false);
  103. }
  104. else
  105. {
  106. for (L2Npc burner : room.getBurners())
  107. {
  108. burner.setDisplayEffect(2);
  109. burner.setIsRunning(false);
  110. }
  111. }
  112. break;
  113. }
  114. case "teleport1":
  115. {
  116. player.teleToLocation(TELEPORT1, 0);
  117. break;
  118. }
  119. case "teleport2":
  120. {
  121. player.teleToLocation(TELEPORT2, 0);
  122. break;
  123. }
  124. case "start":
  125. {
  126. room.burnThemAll();
  127. startQuestTimer("off", 2000, npc, null); // It should be null to stop burnthemAll 2s after
  128. startQuestTimer("timer", 4000, npc, null);
  129. break;
  130. }
  131. case "timer":
  132. {
  133. if (room.getCurrentPot() < 9)
  134. {
  135. L2Npc b = room.getBurners()[room.getOrder()[room.getCurrentPot()]];
  136. b.setDisplayEffect(1);
  137. b.setIsRunning(false);
  138. startQuestTimer("off", 2000, b, null); // Stopping burning each pot 2s after
  139. startQuestTimer("timer", TIMER_INTERVAL * 1000, npc, null);
  140. room.setCurrentPot(room.getCurrentPot() + 1);
  141. }
  142. else
  143. {
  144. broadcastNpcSay(room.getManager(), Say2.NPC_ALL, NpcStringId.NOW_LIGHT_THE_FURNACES_FIRE);
  145. room.burnThemAll();
  146. startQuestTimer("off", 2000, npc, null);
  147. final ConsumerEventListener listener = new ConsumerEventListener(room.getParticipant(), EventType.ON_CREATURE_SKILL_USE, (OnCreatureSkillUse listenerEvent) -> onSkillUse(listenerEvent), room);
  148. room.getParticipant().addListener(listener);
  149. room.setCurrentPot(0);
  150. }
  151. break;
  152. }
  153. case "hurry_up":
  154. {
  155. broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.THERES_ABOUT_1_MINUTE_LEFT);
  156. startQuestTimer("hurry_up2", 60000, npc, null);
  157. break;
  158. }
  159. case "hurry_up2":
  160. {
  161. broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.THERES_JUST_10_SECONDS_LEFT);
  162. startQuestTimer("expire", 10000, npc, null);
  163. break;
  164. }
  165. case "expire":
  166. {
  167. broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.TIME_IS_UP_AND_YOU_HAVE_FAILED_ANY_MORE_WILL_BE_DIFFICULT);
  168. }
  169. case "end":
  170. {
  171. cancelQuestTimer("expire", npc, null);
  172. cancelQuestTimer("hurry_up", npc, null);
  173. cancelQuestTimer("hurry_up2", npc, null);
  174. room.getManager().setTarget(null);
  175. room.setParticipant(null);
  176. room.setStarted(false);
  177. room.setAttemptNumber(1);
  178. room.setCurrentPot(0);
  179. break;
  180. }
  181. case "afterthat":
  182. {
  183. npc.deleteMe();
  184. break;
  185. }
  186. }
  187. return event;
  188. }
  189. @Override
  190. public String onFirstTalk(L2Npc npc, L2PcInstance talker)
  191. {
  192. String htmltext = null;
  193. final MinigameRoom room = getRoomByManager(npc);
  194. final boolean miniGameStarted = room.getStarted();
  195. if (npc.getTarget() == null)
  196. {
  197. htmltext = (miniGameStarted ? "32758-08.html" : "32758.html");
  198. }
  199. else if (npc.getTarget() == talker)
  200. {
  201. if (miniGameStarted)
  202. {
  203. htmltext = "32758-07.html";
  204. }
  205. else
  206. {
  207. int attemptNumber = room.getAttemptNumber();
  208. if (attemptNumber == 2)
  209. {
  210. htmltext = "32758-02.html";
  211. }
  212. else if (attemptNumber == 3)
  213. {
  214. htmltext = "32758-03.html";
  215. }
  216. }
  217. }
  218. else
  219. {
  220. htmltext = "32758-04.html";
  221. }
  222. return htmltext;
  223. }
  224. @Override
  225. public String onSpawn(L2Npc npc)
  226. {
  227. switch (npc.getId())
  228. {
  229. case SUMIEL:
  230. {
  231. _rooms.add(initRoom(npc));
  232. break;
  233. }
  234. case TREASURE_BOX:
  235. {
  236. npc.disableCoreAI(true);
  237. startQuestTimer("afterthat", 180000, npc, null);
  238. break;
  239. }
  240. }
  241. return super.onSpawn(npc);
  242. }
  243. public void onSkillUse(OnCreatureSkillUse event)
  244. {
  245. final MinigameRoom room = getRoomByParticipant((L2PcInstance) event.getCaster());
  246. final boolean miniGameStarted = room.getStarted();
  247. if (miniGameStarted && (event.getSkill().getId() == SKILL_TORCH_LIGHT))
  248. {
  249. for (L2Object obj : event.getTargets())
  250. {
  251. if ((obj != null) && obj.isNpc())
  252. {
  253. L2Npc npc = (L2Npc) obj;
  254. if (npc.getId() == BURNER)
  255. {
  256. npc.doCast(TRIGGER_MIRAGE.getSkill());
  257. final int pos = room.getBurnerPos(npc);
  258. if (pos == room.getOrder()[room.getCurrentPot()])
  259. {
  260. if (room.getCurrentPot() < 8)
  261. {
  262. npc.setDisplayEffect(1);
  263. npc.setIsRunning(false);
  264. startQuestTimer("off", 2000, npc, null);
  265. room.setCurrentPot(room.getCurrentPot() + 1);
  266. }
  267. else
  268. {
  269. addSpawn(TREASURE_BOX, room.getParticipant().getLocation(), true, 0);
  270. broadcastNpcSay(room.getManager(), Say2.NPC_ALL, NpcStringId.OH_YOUVE_SUCCEEDED);
  271. room.setCurrentPot(0);
  272. room.burnThemAll();
  273. startQuestTimer("off", 2000, room.getManager(), null);
  274. startQuestTimer("end", 4000, room.getManager(), null);
  275. }
  276. }
  277. else
  278. {
  279. if (room.getAttemptNumber() == MAX_ATTEMPTS)
  280. {
  281. broadcastNpcSay(room.getManager(), Say2.NPC_ALL, NpcStringId.AH_IVE_FAILED_GOING_FURTHER_WILL_BE_DIFFICULT);
  282. room.burnThemAll();
  283. startQuestTimer("off", 2000, room.getManager(), null);
  284. room.getParticipant().removeListenerIf(EventType.ON_CREATURE_SKILL_USE, listener -> listener.getOwner() == room);
  285. startQuestTimer("end", 4000, room.getManager(), null);
  286. }
  287. else if (room.getAttemptNumber() < MAX_ATTEMPTS)
  288. {
  289. broadcastNpcSay(room.getManager(), Say2.NPC_ALL, NpcStringId.AH_IS_THIS_FAILURE_BUT_IT_LOOKS_LIKE_I_CAN_KEEP_GOING);
  290. room.burnThemAll();
  291. startQuestTimer("off", 2000, room.getManager(), null);
  292. room.setAttemptNumber(room.getAttemptNumber() + 1);
  293. }
  294. }
  295. break;
  296. }
  297. }
  298. }
  299. }
  300. }
  301. /**
  302. * Create and initialize a MinigameRoom<br>
  303. * It's loading the nearby pots around the game instructor NPC.<br>
  304. * TODO: Load the pot_number value from npc ai_params.
  305. * @param manager the NPC instructor
  306. * @return MinigameRoom
  307. */
  308. private MinigameRoom initRoom(L2Npc manager)
  309. {
  310. final L2Npc[] burners = new L2Npc[9];
  311. L2Npc lastSpawn;
  312. int potNumber = 0;
  313. for (L2Spawn spawn : SpawnTable.getInstance().getSpawns(BURNER))
  314. {
  315. lastSpawn = spawn.getLastSpawn();
  316. if ((potNumber <= 8) && Util.checkIfInRange(1000, manager, lastSpawn, false))
  317. {
  318. lastSpawn.setAutoAttackable(true);
  319. burners[potNumber++] = lastSpawn;
  320. }
  321. }
  322. return new MinigameRoom(burners, manager);
  323. }
  324. /**
  325. * Retrieve a MinigameRoom by game instructor
  326. * @param manager the NPC instructor
  327. * @return MinigameRoom
  328. */
  329. private MinigameRoom getRoomByManager(L2Npc manager)
  330. {
  331. for (MinigameRoom room : _rooms)
  332. {
  333. if (room.getManager() == manager)
  334. {
  335. return room;
  336. }
  337. }
  338. return null;
  339. }
  340. /**
  341. * Retrieve a MinigameRoom by participant
  342. * @param participant the L2PcInstance participating
  343. * @return MinigameRoom
  344. */
  345. private MinigameRoom getRoomByParticipant(L2PcInstance participant)
  346. {
  347. for (MinigameRoom room : _rooms)
  348. {
  349. if (room.getParticipant() == participant)
  350. {
  351. return room;
  352. }
  353. }
  354. return null;
  355. }
  356. /**
  357. * An object that holds the participant, manager, burning order<br>
  358. * and game status for each secret room into Monastery of Silence.
  359. */
  360. private class MinigameRoom
  361. {
  362. private final L2Npc[] _burners;
  363. private final L2Npc _manager;
  364. private L2PcInstance _participant;
  365. private boolean _started;
  366. private int _attemptNumber;
  367. private int _currentPot;
  368. private final int _order[];
  369. public MinigameRoom(L2Npc[] burners, L2Npc manager)
  370. {
  371. _burners = burners;
  372. _manager = manager;
  373. _participant = null;
  374. _started = false;
  375. _attemptNumber = 1;
  376. _currentPot = 0;
  377. _order = new int[9];
  378. }
  379. /**
  380. * Retrieve the burner position into the array
  381. * @param npc the L2Npc burner
  382. * @return the array index
  383. */
  384. public int getBurnerPos(L2Npc npc)
  385. {
  386. for (int i = 0; i < 9; i++)
  387. {
  388. if (npc.equals(_burners[i]))
  389. {
  390. return i;
  391. }
  392. }
  393. return 0;
  394. }
  395. /**
  396. * Burn all the pots into the room
  397. */
  398. public void burnThemAll()
  399. {
  400. for (L2Npc burner : _burners)
  401. {
  402. burner.setDisplayEffect(1);
  403. burner.setIsRunning(false);
  404. }
  405. }
  406. /**
  407. * Retrieve a list of burners
  408. * @return An array of L2Npcs
  409. */
  410. public L2Npc[] getBurners()
  411. {
  412. return _burners;
  413. }
  414. /**
  415. * Retrieve the current game manager
  416. * @return The L2Npc game instructor
  417. */
  418. public L2Npc getManager()
  419. {
  420. return _manager;
  421. }
  422. /**
  423. * Retrieve the current game participant
  424. * @return The L2PcInstance who is participating
  425. */
  426. public L2PcInstance getParticipant()
  427. {
  428. return _participant;
  429. }
  430. /**
  431. * Set the current participant
  432. * @param participant The L2PcInstance participating
  433. */
  434. public void setParticipant(L2PcInstance participant)
  435. {
  436. _participant = participant;
  437. }
  438. /**
  439. * Retrieves the MinigameRoom status
  440. * @return {@code true} if the game is started, {@code false} otherwise
  441. */
  442. public boolean getStarted()
  443. {
  444. return _started;
  445. }
  446. /**
  447. * Set the MinigameRoom status
  448. * @param started The game status {@code true} if the game is started, {@code false} otherwise
  449. */
  450. public void setStarted(boolean started)
  451. {
  452. _started = started;
  453. }
  454. /**
  455. * Retrieve the current burner position
  456. * @return The array index
  457. */
  458. public int getCurrentPot()
  459. {
  460. return _currentPot;
  461. }
  462. /**
  463. * Set the current burner position
  464. * @param pot The position
  465. */
  466. public void setCurrentPot(int pot)
  467. {
  468. _currentPot = pot;
  469. }
  470. /**
  471. * Retrieve the current attempt Number
  472. * @return The attempt number
  473. */
  474. public int getAttemptNumber()
  475. {
  476. return _attemptNumber;
  477. }
  478. /**
  479. * Set the attempt number
  480. * @param attempt attempt number
  481. */
  482. public void setAttemptNumber(int attempt)
  483. {
  484. _attemptNumber = attempt;
  485. }
  486. /**
  487. * Retrieve the burning order
  488. * @return an array of Ids
  489. */
  490. public int[] getOrder()
  491. {
  492. return _order;
  493. }
  494. }
  495. public static void main(String[] args)
  496. {
  497. new Minigame();
  498. }
  499. }