MercTicketManager.java 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. /*
  2. * This program is free software: you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation, either version 3 of the License, or (at your option) any later
  5. * version.
  6. *
  7. * This program is distributed in the hope that it will be useful, but WITHOUT
  8. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  10. * details.
  11. *
  12. * You should have received a copy of the GNU General Public License along with
  13. * this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. package com.l2jserver.gameserver.instancemanager;
  16. import java.sql.Connection;
  17. import java.sql.PreparedStatement;
  18. import java.sql.ResultSet;
  19. import java.util.Iterator;
  20. import java.util.List;
  21. import java.util.logging.Level;
  22. import java.util.logging.Logger;
  23. import javolution.util.FastList;
  24. import com.l2jserver.L2DatabaseFactory;
  25. import com.l2jserver.gameserver.datatables.NpcTable;
  26. import com.l2jserver.gameserver.idfactory.IdFactory;
  27. import com.l2jserver.gameserver.model.AutoChatHandler;
  28. import com.l2jserver.gameserver.model.L2World;
  29. import com.l2jserver.gameserver.model.actor.instance.L2DefenderInstance;
  30. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  31. import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
  32. import com.l2jserver.gameserver.model.entity.Castle;
  33. import com.l2jserver.gameserver.model.items.instance.L2ItemInstance;
  34. /**
  35. * @author yellowperil & Fulminus
  36. * This class is similar to the SiegeGuardManager, except it handles
  37. * the loading of the mercenary tickets that are dropped on castle floors
  38. * by the castle lords.
  39. * These tickets (aka badges) need to be readded after each server reboot
  40. * except when the server crashed in the middle of an ongoig siege.
  41. * In addition, this class keeps track of the added tickets, in order to
  42. * properly limit the number of mercenaries in each castle and the
  43. * number of mercenaries from each mercenary type.
  44. * Finally, we provide auxilary functions to identify the castle in
  45. * which each item (and its corresponding NPC) belong to, in order to
  46. * help avoid mixing them up.
  47. *
  48. */
  49. public class MercTicketManager
  50. {
  51. protected static final Logger _log = Logger.getLogger(MercTicketManager.class.getName());
  52. public static final MercTicketManager getInstance()
  53. {
  54. return SingletonHolder._instance;
  55. }
  56. // =========================================================
  57. // =========================================================
  58. // Data Field
  59. private List<L2ItemInstance> _droppedTickets; // to keep track of items on the ground
  60. //TODO move all these values into siege.properties
  61. // max tickets per merc type = 10 + (castleid * 2)?
  62. // max ticker per castle = 40 + (castleid * 20)?
  63. private static final int[] MAX_MERC_PER_TYPE = {
  64. 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
  65. 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
  66. 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
  67. 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
  68. 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
  69. 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
  70. 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
  71. 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
  72. 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
  73. };
  74. //TODO: not retail like: clan lvl 5 - 30 ticks max, lvl 7+ - 50 max
  75. protected static final int[] MERCS_MAX_PER_CASTLE = {
  76. 100, // Gludio
  77. 150, // Dion
  78. 200, // Giran
  79. 300, // Oren
  80. 400, // Aden
  81. 400, // Innadril
  82. 400, // Goddard
  83. 400, // Rune
  84. 400 // Schuttgart
  85. };
  86. private static final int[] ITEM_IDS = {
  87. 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
  88. 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
  89. 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
  90. 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
  91. 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
  92. 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
  93. 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
  94. 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
  95. 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
  96. };
  97. private static final int[] NPC_IDS = {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
  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, // Dion
  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, // Giran
  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, // Oren
  101. 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
  102. 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
  103. 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
  104. 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
  105. 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
  106. };
  107. private static final int GUARDIAN_TYPES_COUNT = 52;
  108. private MercTicketManager()
  109. {
  110. _log.info("Initializing MercTicketManager");
  111. load();
  112. }
  113. // returns the castleId for the passed ticket item id
  114. public int getTicketCastleId(int itemId)
  115. {
  116. for (int i = 0; i < 9; i++) //CastleID`s from 1 to 9 minus;
  117. {
  118. for (int i2 = 0; i2 < 50; i2 += 10)
  119. //Simplified if statement;
  120. if ((itemId >= ITEM_IDS[i2 + i * GUARDIAN_TYPES_COUNT] && itemId <= ITEM_IDS[i2 + 9 + i * GUARDIAN_TYPES_COUNT]))
  121. return i + 1;
  122. if (itemId >= ITEM_IDS[50] && itemId <= ITEM_IDS[51])
  123. return i + 1;
  124. }
  125. return -1;
  126. }
  127. public void reload()
  128. {
  129. getDroppedTickets().clear();
  130. load();
  131. }
  132. private final void load()
  133. {
  134. Connection con = null;
  135. // load merc tickets into the world
  136. try
  137. {
  138. con = L2DatabaseFactory.getInstance().getConnection();
  139. PreparedStatement statement = con.prepareStatement("SELECT * FROM castle_siege_guards Where isHired = 1");
  140. ResultSet rs = statement.executeQuery();
  141. int npcId;
  142. int itemId;
  143. int x, y, z;
  144. int mercPlaced[] = new int[20];
  145. // start index to begin the search for the itemId corresponding to this NPC
  146. // this will help with:
  147. // a) skip unnecessary iterations in the search loop
  148. // b) avoid finding the wrong itemId whenever tickets of different spawn the same npc!
  149. int startindex = 0;
  150. while (rs.next())
  151. {
  152. npcId = rs.getInt("npcId");
  153. x = rs.getInt("x");
  154. y = rs.getInt("y");
  155. z = rs.getInt("z");
  156. Castle castle = CastleManager.getInstance().getCastle(x, y, z);
  157. if (castle != null)
  158. {
  159. if (mercPlaced[castle.getCastleId() - 1] >= MERCS_MAX_PER_CASTLE[castle.getCastleId() - 1])
  160. continue;
  161. startindex = GUARDIAN_TYPES_COUNT * (castle.getCastleId() - 1);
  162. mercPlaced[castle.getCastleId() - 1] += 1;
  163. }
  164. // find the FIRST ticket itemId with spawns the saved NPC in the saved location
  165. for (int i = startindex; i < startindex + GUARDIAN_TYPES_COUNT; i++)
  166. if (NPC_IDS[i] == npcId) // Find the index of the item used
  167. {
  168. // only handle tickets if a siege is not ongoing in this npc's castle
  169. if ((castle != null) && !(castle.getSiege().getIsInProgress()))
  170. {
  171. itemId = ITEM_IDS[i];
  172. // create the ticket in the gameworld
  173. L2ItemInstance dropticket = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
  174. dropticket.setLocation(L2ItemInstance.ItemLocation.VOID);
  175. dropticket.dropMe(null, x, y, z);
  176. dropticket.setDropTime(0); //avoids it from beeing removed by the auto item destroyer
  177. L2World.getInstance().storeObject(dropticket);
  178. getDroppedTickets().add(dropticket);
  179. }
  180. break;
  181. }
  182. }
  183. rs.close();
  184. statement.close();
  185. _log.info("Loaded: " + getDroppedTickets().size() + " Mercenary Tickets");
  186. }
  187. catch (Exception e)
  188. {
  189. _log.log(Level.WARNING, "Exception: loadMercenaryData(): " + e.getMessage(), e);
  190. }
  191. finally
  192. {
  193. L2DatabaseFactory.close(con);
  194. }
  195. }
  196. /**
  197. * Checks if the passed item has reached the limit of number of dropped
  198. * tickets that this SPECIFIC item may have in its castle
  199. * @param itemId
  200. * @return
  201. */
  202. public boolean isAtTypeLimit(int itemId)
  203. {
  204. int limit = -1;
  205. // find the max value for this item
  206. for (int i = 0; i < ITEM_IDS.length; i++)
  207. if (ITEM_IDS[i] == itemId) // Find the index of the item used
  208. {
  209. limit = MAX_MERC_PER_TYPE[i];
  210. break;
  211. }
  212. if (limit <= 0)
  213. return true;
  214. int count = 0;
  215. for (L2ItemInstance ticket : getDroppedTickets())
  216. {
  217. if (ticket != null && ticket.getItemId() == itemId)
  218. count++;
  219. }
  220. if (count >= limit)
  221. return true;
  222. return false;
  223. }
  224. /**
  225. * Checks if the passed item belongs to a castle which has reached its limit
  226. * of number of dropped tickets.
  227. * @param itemId
  228. * @return
  229. */
  230. public boolean isAtCasleLimit(int itemId)
  231. {
  232. int castleId = getTicketCastleId(itemId);
  233. if (castleId <= 0)
  234. return true;
  235. int limit = MERCS_MAX_PER_CASTLE[castleId - 1];
  236. if (limit <= 0)
  237. return true;
  238. int count = 0;
  239. for (L2ItemInstance ticket : getDroppedTickets())
  240. {
  241. if ((ticket != null) && (getTicketCastleId(ticket.getItemId()) == castleId))
  242. count++;
  243. }
  244. if (count >= limit)
  245. return true;
  246. return false;
  247. }
  248. public int getMaxAllowedMerc(int castleId)
  249. {
  250. return MERCS_MAX_PER_CASTLE[castleId - 1];
  251. }
  252. public boolean isTooCloseToAnotherTicket(int x, int y, int z)
  253. {
  254. for (L2ItemInstance item : getDroppedTickets())
  255. {
  256. double dx = x - item.getX();
  257. double dy = y - item.getY();
  258. double dz = z - item.getZ();
  259. if ((dx * dx + dy * dy + dz * dz) < 25 * 25)
  260. return true;
  261. }
  262. return false;
  263. }
  264. /**
  265. * addTicket actions
  266. * 1) find the npc that needs to be saved in the mercenary spawns, given this item
  267. * 2) Use the passed character's location info to add the spawn
  268. * 3) create a copy of the item to drop in the world
  269. * returns the id of the mercenary npc that was added to the spawn
  270. * returns -1 if this fails.
  271. * @param itemId
  272. * @param activeChar
  273. * @param messages
  274. * @return
  275. */
  276. public int addTicket(int itemId, L2PcInstance activeChar, String[] messages)
  277. {
  278. int x = activeChar.getX();
  279. int y = activeChar.getY();
  280. int z = activeChar.getZ();
  281. int heading = activeChar.getHeading();
  282. Castle castle = CastleManager.getInstance().getCastle(activeChar);
  283. if (castle == null) //this should never happen at this point
  284. return -1;
  285. for (int i = 0; i < ITEM_IDS.length; i++)
  286. {
  287. if (ITEM_IDS[i] == itemId) // Find the index of the item used
  288. {
  289. spawnMercenary(NPC_IDS[i], x, y, z, 3000, messages, 0);
  290. // Hire merc for this castle. NpcId is at the same index as the item used.
  291. castle.getSiege().getSiegeGuardManager().hireMerc(x, y, z, heading, NPC_IDS[i]);
  292. // create the ticket in the gameworld
  293. L2ItemInstance dropticket = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
  294. dropticket.setLocation(L2ItemInstance.ItemLocation.VOID);
  295. dropticket.dropMe(null, x, y, z);
  296. dropticket.setDropTime(0); //avoids it from beeing removed by the auto item destroyer
  297. L2World.getInstance().storeObject(dropticket); //add to the world
  298. // and keep track of this ticket in the list
  299. _droppedTickets.add(dropticket);
  300. return NPC_IDS[i];
  301. }
  302. }
  303. return -1;
  304. }
  305. private void spawnMercenary(int npcId, int x, int y, int z, int despawnDelay, String[] messages, int chatDelay)
  306. {
  307. L2NpcTemplate template = NpcTable.getInstance().getTemplate(npcId);
  308. if (template != null)
  309. {
  310. final L2DefenderInstance npc = new L2DefenderInstance(IdFactory.getInstance().getNextId(), template);
  311. npc.setCurrentHpMp(npc.getMaxHp(), npc.getMaxMp());
  312. npc.setDecayed(false);
  313. npc.spawnMe(x, y, (z + 20));
  314. if (messages != null && messages.length > 0)
  315. AutoChatHandler.getInstance().registerChat(npc, messages, chatDelay);
  316. if (despawnDelay > 0)
  317. npc.scheduleDespawn(despawnDelay);
  318. }
  319. }
  320. /**
  321. * Delete all tickets from a castle;
  322. * remove the items from the world and remove references to them from this class
  323. * @param castleId
  324. */
  325. public void deleteTickets(int castleId)
  326. {
  327. Iterator<L2ItemInstance> it = getDroppedTickets().iterator();
  328. while (it.hasNext())
  329. {
  330. L2ItemInstance item = it.next();
  331. if ((item != null) && (getTicketCastleId(item.getItemId()) == castleId))
  332. {
  333. item.decayMe();
  334. L2World.getInstance().removeObject(item);
  335. it.remove();
  336. }
  337. }
  338. }
  339. /**
  340. * remove a single ticket and its associated spawn from the world
  341. * (used when the castle lord picks up a ticket, for example)
  342. * @param item
  343. */
  344. public void removeTicket(L2ItemInstance item)
  345. {
  346. int itemId = item.getItemId();
  347. int npcId = -1;
  348. // find the FIRST ticket itemId with spawns the saved NPC in the saved location
  349. for (int i = 0; i < ITEM_IDS.length; i++)
  350. if (ITEM_IDS[i] == itemId) // Find the index of the item used
  351. {
  352. npcId = NPC_IDS[i];
  353. break;
  354. }
  355. // find the castle where this item is
  356. Castle castle = CastleManager.getInstance().getCastleById(getTicketCastleId(itemId));
  357. if (npcId > 0 && castle != null)
  358. {
  359. (new SiegeGuardManager(castle)).removeMerc(npcId, item.getX(), item.getY(), item.getZ());
  360. }
  361. getDroppedTickets().remove(item);
  362. }
  363. public int[] getItemIds()
  364. {
  365. return ITEM_IDS;
  366. }
  367. public final List<L2ItemInstance> getDroppedTickets()
  368. {
  369. if (_droppedTickets == null)
  370. synchronized (this)
  371. {
  372. if (_droppedTickets == null)
  373. _droppedTickets = new FastList<L2ItemInstance>();
  374. }
  375. return _droppedTickets;
  376. }
  377. @SuppressWarnings("synthetic-access")
  378. private static class SingletonHolder
  379. {
  380. protected static final MercTicketManager _instance = new MercTicketManager();
  381. }
  382. }