2
0

MercTicketManager.java 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. /*
  2. * Copyright (C) 2004-2014 L2J Server
  3. *
  4. * This file is part of L2J Server.
  5. *
  6. * L2J Server 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 Server 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 com.l2jserver.gameserver.instancemanager;
  20. import java.sql.Connection;
  21. import java.sql.ResultSet;
  22. import java.sql.Statement;
  23. import java.util.Iterator;
  24. import java.util.List;
  25. import java.util.logging.Level;
  26. import java.util.logging.Logger;
  27. import javolution.util.FastList;
  28. import com.l2jserver.L2DatabaseFactory;
  29. import com.l2jserver.gameserver.datatables.NpcData;
  30. import com.l2jserver.gameserver.enums.ItemLocation;
  31. import com.l2jserver.gameserver.idfactory.IdFactory;
  32. import com.l2jserver.gameserver.model.L2World;
  33. import com.l2jserver.gameserver.model.actor.instance.L2DefenderInstance;
  34. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  35. import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
  36. import com.l2jserver.gameserver.model.entity.Castle;
  37. import com.l2jserver.gameserver.model.items.instance.L2ItemInstance;
  38. /**
  39. * This class is similar to the SiegeGuardManager, except it handles the loading of the mercenary tickets that are dropped on castle floors by the castle lords.<br>
  40. * These tickets (a.k.a. badges) need to be read after each server reboot except when the server crashed in the middle of an ongoing siege.<br>
  41. * In addition, this class keeps track of the added tickets, in order to properly limit the number of mercenaries in each castle and the number of mercenaries from each mercenary type.<br>
  42. * Finally, we provide auxiliary functions to identify the castle in which each item (and its corresponding NPC) belong to, in order to help avoid mixing them up.
  43. * @author yellowperil, Fulminus
  44. */
  45. public final class MercTicketManager
  46. {
  47. private static final Logger _log = Logger.getLogger(MercTicketManager.class.getName());
  48. private static final FastList<L2ItemInstance> _droppedTickets = new FastList<>();
  49. // TODO: move all these values into siege.properties
  50. // max tickets per merc type = 10 + (castleid * 2)?
  51. // max ticker per castle = 40 + (castleid * 20)?
  52. // @formatter:off
  53. private static final int[] MAX_MERC_PER_TYPE =
  54. {
  55. 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, // Gludio
  56. 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, // Dion
  57. 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, // Giran
  58. 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, // Oren
  59. 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // Aden
  60. 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // Innadril
  61. 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // Goddard
  62. 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // Rune
  63. 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 // Schuttgart
  64. };
  65. //TODO: not retail like: clan lvl 5 - 30 ticks max, lvl 7+ - 50 max
  66. protected static final int[] MERCS_MAX_PER_CASTLE =
  67. {
  68. 100, // Gludio
  69. 150, // Dion
  70. 200, // Giran
  71. 300, // Oren
  72. 400, // Aden
  73. 400, // Innadril
  74. 400, // Goddard
  75. 400, // Rune
  76. 400 // Schuttgart
  77. };
  78. private static final int[] ITEM_IDS =
  79. {
  80. 3960, 3961, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 6115, 6116, 6117, 6118, 6119, 6120, 6121, 6122, 6123, 6124, 6038, 6039, 6040, 6041, 6042, 6043, 6044, 6045, 6046, 6047, 6175, 6176, 6177, 6178, 6179, 6180, 6181, 6182, 6183, 6184, 6235, 6236, 6237, 6238, 6239, 6240, 6241, 6242, 6243, 6244, 6295, 6296, // Gludio
  81. 3973, 3974, 3975, 3976, 3977, 3978, 3979, 3980, 3981, 3982, 6125, 6126, 6127, 6128, 6129, 6130, 6131, 6132, 6133, 6134, 6051, 6052, 6053, 6054, 6055, 6056, 6057, 6058, 6059, 6060, 6185, 6186, 6187, 6188, 6189, 6190, 6191, 6192, 6193, 6194, 6245, 6246, 6247, 6248, 6249, 6250, 6251, 6252, 6253, 6254, 6297, 6298, // Dion
  82. 3986, 3987, 3988, 3989, 3990, 3991, 3992, 3993, 3994, 3995, 6135, 6136, 6137, 6138, 6139, 6140, 6141, 6142, 6143, 6144, 6064, 6065, 6066, 6067, 6068, 6069, 6070, 6071, 6072, 6073, 6195, 6196, 6197, 6198, 6199, 6200, 6201, 6202, 6203, 6204, 6255, 6256, 6257, 6258, 6259, 6260, 6261, 6262, 6263, 6264, 6299, 6300, // Giran
  83. 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 6145, 6146, 6147, 6148, 6149, 6150, 6151, 6152, 6153, 6154, 6077, 6078, 6079, 6080, 6081, 6082, 6083, 6084, 6085, 6086, 6205, 6206, 6207, 6208, 6209, 6210, 6211, 6212, 6213, 6214, 6265, 6266, 6267, 6268, 6269, 6270, 6271, 6272, 6273, 6274, 6301, 6302, // Oren
  84. 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 6155, 6156, 6157, 6158, 6159, 6160, 6161, 6162, 6163, 6164, 6090, 6091, 6092, 6093, 6094, 6095, 6096, 6097, 6098, 6099, 6215, 6216, 6217, 6218, 6219, 6220, 6221, 6222, 6223, 6224, 6275, 6276, 6277, 6278, 6279, 6280, 6281, 6282, 6283, 6284, 6303, 6304, // Aden
  85. 5205, 5206, 5207, 5208, 5209, 5210, 5211, 5212, 5213, 5214, 6165, 6166, 6167, 6168, 6169, 6170, 6171, 6172, 6173, 6174, 6105, 6106, 6107, 6108, 6109, 6110, 6111, 6112, 6113, 6114, 6225, 6226, 6227, 6228, 6229, 6230, 6231, 6232, 6233, 6234, 6285, 6286, 6287, 6288, 6289, 6290, 6291, 6292, 6293, 6294, 6305, 6306, // Innadril
  86. 6779, 6780, 6781, 6782, 6783, 6784, 6785, 6786, 6787, 6788, 6802, 6803, 6804, 6805, 6806, 6807, 6808, 6809, 6810, 6811, 6792, 6793, 6794, 6795, 6796, 6797, 6798, 6799, 6800, 6801, 6812, 6813, 6814, 6815, 6816, 6817, 6818, 6819, 6820, 6821, 6822, 6823, 6824, 6825, 6826, 6827, 6828, 6829, 6830, 6831, 6832, 6833, // Goddard
  87. 7973, 7974, 7975, 7976, 7977, 7978, 7979, 7980, 7981, 7982, 7998, 7999, 8000, 8001, 8002, 8003, 8004, 8005, 8006, 8007, 7988, 7989, 7990, 7991, 7992, 7993, 7994, 7995, 7996, 7997, 8008, 8009, 8010, 8011, 8012, 8013, 8014, 8015, 8016, 8017, 8018, 8019, 8020, 8021, 8022, 8023, 8024, 8025, 8026, 8027, 8028, 8029, // Rune
  88. 7918, 7919, 7920, 7921, 7922, 7923, 7924, 7925, 7926, 7927, 7941, 7942, 7943, 7944, 7945, 7946, 7947, 7948, 7949, 7950, 7931, 7932, 7933, 7934, 7935, 7936, 7937, 7938, 7939, 7940, 7951, 7952, 7953, 7954, 7955, 7956, 7957, 7958, 7959, 7960, 7961, 7962, 7963, 7964, 7965, 7966, 7967, 7968, 7969, 7970, 7971, 7972 // Schuttgart
  89. };
  90. private static final int[] NPC_IDS =
  91. {
  92. 35010, 35011, 35012, 35013, 35014, 35015, 35016, 35017, 35018, 35019, 35020, 35021, 35022, 35023, 35024, 35025, 35026, 35027, 35028, 35029, 35030,35031,35032,35033,35034,35035,35036,35037,35038,35039, 35040, 35041, 35042, 35043, 35044, 35045, 35046, 35047, 35048, 35049, 35050, 35051, 35052, 35053, 35054, 35055, 35056, 35057, 35058, 35059, 35060, 35061, // Gludio
  93. 35010, 35011, 35012, 35013, 35014, 35015, 35016, 35017, 35018, 35019, 35020, 35021, 35022, 35023, 35024, 35025, 35026, 35027, 35028, 35029, 35030,35031,35032,35033,35034,35035,35036,35037,35038,35039, 35040, 35041, 35042, 35043, 35044, 35045, 35046, 35047, 35048, 35049, 35050, 35051, 35052, 35053, 35054, 35055, 35056, 35057, 35058, 35059, 35060, 35061, // Dion
  94. 35010, 35011, 35012, 35013, 35014, 35015, 35016, 35017, 35018, 35019, 35020, 35021, 35022, 35023, 35024, 35025, 35026, 35027, 35028, 35029, 35030,35031,35032,35033,35034,35035,35036,35037,35038,35039, 35040, 35041, 35042, 35043, 35044, 35045, 35046, 35047, 35048, 35049, 35050, 35051, 35052, 35053, 35054, 35055, 35056, 35057, 35058, 35059, 35060, 35061, // Giran
  95. 35010, 35011, 35012, 35013, 35014, 35015, 35016, 35017, 35018, 35019, 35020, 35021, 35022, 35023, 35024, 35025, 35026, 35027, 35028, 35029, 35030,35031,35032,35033,35034,35035,35036,35037,35038,35039, 35040, 35041, 35042, 35043, 35044, 35045, 35046, 35047, 35048, 35049, 35050, 35051, 35052, 35053, 35054, 35055, 35056, 35057, 35058, 35059, 35060, 35061, // Oren
  96. 35010, 35011, 35012, 35013, 35014, 35015, 35016, 35017, 35018, 35019, 35020, 35021, 35022, 35023, 35024, 35025, 35026, 35027, 35028, 35029, 35030,35031,35032,35033,35034,35035,35036,35037,35038,35039, 35040, 35041, 35042, 35043, 35044, 35045, 35046, 35047, 35048, 35049, 35050, 35051, 35052, 35053, 35054, 35055, 35056, 35057, 35058, 35059, 35060, 35061, // Aden
  97. 35010, 35011, 35012, 35013, 35014, 35015, 35016, 35017, 35018, 35019, 35020, 35021, 35022, 35023, 35024, 35025, 35026, 35027, 35028, 35029, 35030,35031,35032,35033,35034,35035,35036,35037,35038,35039, 35040, 35041, 35042, 35043, 35044, 35045, 35046, 35047, 35048, 35049, 35050, 35051, 35052, 35053, 35054, 35055, 35056, 35057, 35058, 35059, 35060, 35061, // Innadril
  98. 35010, 35011, 35012, 35013, 35014, 35015, 35016, 35017, 35018, 35019, 35020, 35021, 35022, 35023, 35024, 35025, 35026, 35027, 35028, 35029, 35030,35031,35032,35033,35034,35035,35036,35037,35038,35039, 35040, 35041, 35042, 35043, 35044, 35045, 35046, 35047, 35048, 35049, 35050, 35051, 35052, 35053, 35054, 35055, 35056, 35057, 35058, 35059, 35060, 35061, // Goddard
  99. 35010, 35011, 35012, 35013, 35014, 35015, 35016, 35017, 35018, 35019, 35020, 35021, 35022, 35023, 35024, 35025, 35026, 35027, 35028, 35029, 35030,35031,35032,35033,35034,35035,35036,35037,35038,35039, 35040, 35041, 35042, 35043, 35044, 35045, 35046, 35047, 35048, 35049, 35050, 35051, 35052, 35053, 35054, 35055, 35056, 35057, 35058, 35059, 35060, 35061, // Rune
  100. 35010, 35011, 35012, 35013, 35014, 35015, 35016, 35017, 35018, 35019, 35020, 35021, 35022, 35023, 35024, 35025, 35026, 35027, 35028, 35029, 35030,35031,35032,35033,35034,35035,35036,35037,35038,35039, 35040, 35041, 35042, 35043, 35044, 35045, 35046, 35047, 35048, 35049, 35050, 35051, 35052, 35053, 35054, 35055, 35056, 35057, 35058, 35059, 35060, 35061, // Schuttgart
  101. };
  102. // @formatter:on
  103. private static final int GUARDIAN_TYPES_COUNT = 52;
  104. protected MercTicketManager()
  105. {
  106. _droppedTickets.shared();
  107. load();
  108. }
  109. // returns the castleId for the passed ticket item id
  110. public int getTicketCastleId(int itemId)
  111. {
  112. for (int i = 0; i < 9; i++) // CastleID`s from 1 to 9 minus;
  113. {
  114. for (int i2 = 0; i2 < 50; i2 += 10)
  115. {
  116. // Simplified if statement;
  117. if (((itemId >= ITEM_IDS[i2 + (i * GUARDIAN_TYPES_COUNT)]) && (itemId <= ITEM_IDS[i2 + 9 + (i * GUARDIAN_TYPES_COUNT)])))
  118. {
  119. return i + 1;
  120. }
  121. }
  122. if ((itemId >= ITEM_IDS[50]) && (itemId <= ITEM_IDS[51]))
  123. {
  124. return i + 1;
  125. }
  126. }
  127. return -1;
  128. }
  129. public void reload()
  130. {
  131. _droppedTickets.clear();
  132. load();
  133. }
  134. /**
  135. * Load merc tickets into the world.
  136. */
  137. private final void load()
  138. {
  139. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  140. Statement s = con.createStatement();
  141. ResultSet rs = s.executeQuery("SELECT * FROM castle_siege_guards Where isHired = 1"))
  142. {
  143. int npcId;
  144. int itemId;
  145. int x, y, z;
  146. int mercPlaced[] = new int[20];
  147. // start index to begin the search for the itemId corresponding to this NPC
  148. // this will help with:
  149. // a) skip unnecessary iterations in the search loop
  150. // b) avoid finding the wrong itemId whenever tickets of different spawn the same npc!
  151. int startindex = 0;
  152. while (rs.next())
  153. {
  154. npcId = rs.getInt("npcId");
  155. x = rs.getInt("x");
  156. y = rs.getInt("y");
  157. z = rs.getInt("z");
  158. Castle castle = CastleManager.getInstance().getCastle(x, y, z);
  159. if (castle != null)
  160. {
  161. if (mercPlaced[castle.getResidenceId() - 1] >= MERCS_MAX_PER_CASTLE[castle.getResidenceId() - 1])
  162. {
  163. continue;
  164. }
  165. startindex = GUARDIAN_TYPES_COUNT * (castle.getResidenceId() - 1);
  166. mercPlaced[castle.getResidenceId() - 1] += 1;
  167. }
  168. // find the FIRST ticket itemId with spawns the saved NPC in the saved location
  169. for (int i = startindex; i < (startindex + GUARDIAN_TYPES_COUNT); i++)
  170. {
  171. if (NPC_IDS[i] == npcId) // Find the index of the item used
  172. {
  173. // only handle tickets if a siege is not ongoing in this npc's castle
  174. if ((castle != null) && !(castle.getSiege().getIsInProgress()))
  175. {
  176. itemId = ITEM_IDS[i];
  177. // create the ticket in the gameworld
  178. L2ItemInstance dropticket = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
  179. dropticket.setItemLocation(ItemLocation.VOID);
  180. dropticket.dropMe(null, x, y, z);
  181. dropticket.setDropTime(0); // avoids it from being removed by the auto item destroyer
  182. L2World.getInstance().storeObject(dropticket);
  183. _droppedTickets.add(dropticket);
  184. }
  185. break;
  186. }
  187. }
  188. }
  189. rs.close();
  190. s.close();
  191. _log.info(getClass().getSimpleName() + ": Loaded: " + _droppedTickets.size() + " Mercenary Tickets");
  192. }
  193. catch (Exception e)
  194. {
  195. _log.log(Level.WARNING, "Exception: loadMercenaryData(): " + e.getMessage(), e);
  196. }
  197. }
  198. /**
  199. * Checks if the passed item has reached the limit of number of dropped tickets that this SPECIFIC item may have in its castle
  200. * @param itemId
  201. * @return
  202. */
  203. public boolean isAtTypeLimit(int itemId)
  204. {
  205. int limit = -1;
  206. // find the max value for this item
  207. for (int i = 0; i < ITEM_IDS.length; i++)
  208. {
  209. if (ITEM_IDS[i] == itemId) // Find the index of the item used
  210. {
  211. limit = MAX_MERC_PER_TYPE[i];
  212. break;
  213. }
  214. }
  215. if (limit <= 0)
  216. {
  217. return true;
  218. }
  219. int count = 0;
  220. for (L2ItemInstance ticket : _droppedTickets)
  221. {
  222. if ((ticket != null) && (ticket.getId() == itemId))
  223. {
  224. count++;
  225. }
  226. }
  227. if (count >= limit)
  228. {
  229. return true;
  230. }
  231. return false;
  232. }
  233. /**
  234. * Checks if the passed item belongs to a castle which has reached its limit of number of dropped tickets.
  235. * @param itemId
  236. * @return
  237. */
  238. public boolean isAtCasleLimit(int itemId)
  239. {
  240. int castleId = getTicketCastleId(itemId);
  241. if (castleId <= 0)
  242. {
  243. return true;
  244. }
  245. int limit = MERCS_MAX_PER_CASTLE[castleId - 1];
  246. if (limit <= 0)
  247. {
  248. return true;
  249. }
  250. int count = 0;
  251. for (L2ItemInstance ticket : _droppedTickets)
  252. {
  253. if ((ticket != null) && (getTicketCastleId(ticket.getId()) == castleId))
  254. {
  255. count++;
  256. }
  257. }
  258. if (count >= limit)
  259. {
  260. return true;
  261. }
  262. return false;
  263. }
  264. public int getMaxAllowedMerc(int castleId)
  265. {
  266. return MERCS_MAX_PER_CASTLE[castleId - 1];
  267. }
  268. public boolean isTooCloseToAnotherTicket(int x, int y, int z)
  269. {
  270. for (L2ItemInstance item : _droppedTickets)
  271. {
  272. double dx = x - item.getX();
  273. double dy = y - item.getY();
  274. double dz = z - item.getZ();
  275. if (((dx * dx) + (dy * dy) + (dz * dz)) < (25 * 25))
  276. {
  277. return true;
  278. }
  279. }
  280. return false;
  281. }
  282. /**
  283. * addTicket actions 1) find the npc that needs to be saved in the mercenary spawns, given this item 2) Use the passed character's location info to add the spawn 3) create a copy of the item to drop in the world returns the id of the mercenary npc that was added to the spawn returns -1 if this
  284. * fails.
  285. * @param itemId
  286. * @param activeChar
  287. * @return
  288. */
  289. public int addTicket(int itemId, L2PcInstance activeChar)
  290. {
  291. int x = activeChar.getX();
  292. int y = activeChar.getY();
  293. int z = activeChar.getZ();
  294. int heading = activeChar.getHeading();
  295. Castle castle = CastleManager.getInstance().getCastle(activeChar);
  296. if (castle == null)
  297. {
  298. return -1;
  299. }
  300. for (int i = 0; i < ITEM_IDS.length; i++)
  301. {
  302. if (ITEM_IDS[i] == itemId) // Find the index of the item used
  303. {
  304. spawnMercenary(NPC_IDS[i], x, y, z, 3000);
  305. // Hire merc for this castle. NpcId is at the same index as the item used.
  306. castle.getSiege().getSiegeGuardManager().hireMerc(x, y, z, heading, NPC_IDS[i]);
  307. // create the ticket in the gameworld
  308. L2ItemInstance dropticket = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
  309. dropticket.setItemLocation(ItemLocation.VOID);
  310. dropticket.dropMe(null, x, y, z);
  311. dropticket.setDropTime(0); // avoids it from beeing removed by the auto item destroyer
  312. L2World.getInstance().storeObject(dropticket); // add to the world
  313. // and keep track of this ticket in the list
  314. _droppedTickets.add(dropticket);
  315. return NPC_IDS[i];
  316. }
  317. }
  318. return -1;
  319. }
  320. private void spawnMercenary(int npcId, int x, int y, int z, int despawnDelay)
  321. {
  322. L2NpcTemplate template = NpcData.getInstance().getTemplate(npcId);
  323. if (template != null)
  324. {
  325. final L2DefenderInstance npc = new L2DefenderInstance(IdFactory.getInstance().getNextId(), template);
  326. npc.setCurrentHpMp(npc.getMaxHp(), npc.getMaxMp());
  327. npc.setDecayed(false);
  328. npc.spawnMe(x, y, (z + 20));
  329. if (despawnDelay > 0)
  330. {
  331. npc.scheduleDespawn(despawnDelay);
  332. }
  333. }
  334. }
  335. /**
  336. * Delete all tickets from a castle; remove the items from the world and remove references to them from this class
  337. * @param castleId
  338. */
  339. public void deleteTickets(int castleId)
  340. {
  341. Iterator<L2ItemInstance> it = _droppedTickets.iterator();
  342. while (it.hasNext())
  343. {
  344. L2ItemInstance item = it.next();
  345. if ((item != null) && (getTicketCastleId(item.getId()) == castleId))
  346. {
  347. item.decayMe();
  348. L2World.getInstance().removeObject(item);
  349. it.remove();
  350. }
  351. }
  352. }
  353. /**
  354. * remove a single ticket and its associated spawn from the world (used when the castle lord picks up a ticket, for example)
  355. * @param item
  356. */
  357. public void removeTicket(L2ItemInstance item)
  358. {
  359. int itemId = item.getId();
  360. int npcId = -1;
  361. // find the FIRST ticket itemId with spawns the saved NPC in the saved location
  362. for (int i = 0; i < ITEM_IDS.length; i++)
  363. {
  364. if (ITEM_IDS[i] == itemId) // Find the index of the item used
  365. {
  366. npcId = NPC_IDS[i];
  367. break;
  368. }
  369. }
  370. // find the castle where this item is
  371. Castle castle = CastleManager.getInstance().getCastleById(getTicketCastleId(itemId));
  372. if ((npcId > 0) && (castle != null))
  373. {
  374. (new SiegeGuardManager(castle)).removeMerc(npcId, item.getX(), item.getY(), item.getZ());
  375. }
  376. _droppedTickets.remove(item);
  377. }
  378. public int[] getItemIds()
  379. {
  380. return ITEM_IDS;
  381. }
  382. public final List<L2ItemInstance> getDroppedTickets()
  383. {
  384. return _droppedTickets;
  385. }
  386. /**
  387. * Gets the single instance of {@code MercTicketManager}.
  388. * @return single instance of {@code MercTicketManager}
  389. */
  390. public static final MercTicketManager getInstance()
  391. {
  392. return SingletonHolder._instance;
  393. }
  394. private static class SingletonHolder
  395. {
  396. protected static final MercTicketManager _instance = new MercTicketManager();
  397. }
  398. }