SevenSignsFestival.java 74 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454
  1. /*
  2. * Copyright (C) 2004-2015 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;
  20. import java.sql.Connection;
  21. import java.sql.PreparedStatement;
  22. import java.sql.ResultSet;
  23. import java.sql.SQLException;
  24. import java.sql.Statement;
  25. import java.util.ArrayList;
  26. import java.util.HashMap;
  27. import java.util.List;
  28. import java.util.Map;
  29. import java.util.concurrent.ConcurrentHashMap;
  30. import java.util.concurrent.ScheduledFuture;
  31. import java.util.logging.Level;
  32. import java.util.logging.Logger;
  33. import com.l2jserver.Config;
  34. import com.l2jserver.commons.database.pool.impl.ConnectionFactory;
  35. import com.l2jserver.gameserver.ai.CtrlIntention;
  36. import com.l2jserver.gameserver.data.sql.impl.CharNameTable;
  37. import com.l2jserver.gameserver.data.sql.impl.ClanTable;
  38. import com.l2jserver.gameserver.data.xml.impl.ExperienceData;
  39. import com.l2jserver.gameserver.datatables.SpawnTable;
  40. import com.l2jserver.gameserver.model.L2Clan;
  41. import com.l2jserver.gameserver.model.L2Party;
  42. import com.l2jserver.gameserver.model.L2Party.messageType;
  43. import com.l2jserver.gameserver.model.L2Spawn;
  44. import com.l2jserver.gameserver.model.L2World;
  45. import com.l2jserver.gameserver.model.Location;
  46. import com.l2jserver.gameserver.model.SpawnListener;
  47. import com.l2jserver.gameserver.model.StatsSet;
  48. import com.l2jserver.gameserver.model.TeleportWhereType;
  49. import com.l2jserver.gameserver.model.actor.L2Npc;
  50. import com.l2jserver.gameserver.model.actor.instance.L2FestivalMonsterInstance;
  51. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  52. import com.l2jserver.gameserver.model.items.instance.L2ItemInstance;
  53. import com.l2jserver.gameserver.network.NpcStringId;
  54. import com.l2jserver.gameserver.network.SystemMessageId;
  55. import com.l2jserver.gameserver.network.clientpackets.Say2;
  56. import com.l2jserver.gameserver.network.serverpackets.CreatureSay;
  57. import com.l2jserver.gameserver.network.serverpackets.MagicSkillUse;
  58. import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
  59. import com.l2jserver.gameserver.util.Util;
  60. import com.l2jserver.util.Rnd;
  61. /**
  62. * Seven Signs Festival of Darkness Engine.<br>
  63. * TODO:<br>
  64. * <ul>
  65. * <li>Archer mobs should target healer characters over other party members.</li>
  66. * <li>Added 29 Sep: Players that leave a party during the Seven Signs Festival will now take damage and cannot be healed.</li>
  67. * </ul>
  68. * @author Tempy
  69. */
  70. public class SevenSignsFestival implements SpawnListener
  71. {
  72. protected static final Logger _log = Logger.getLogger(SevenSignsFestival.class.getName());
  73. private static final String GET_CLAN_NAME = "SELECT clan_name FROM clan_data WHERE clan_id = (SELECT clanid FROM characters WHERE char_name = ?)";
  74. /**
  75. * These length settings are important! :)<br>
  76. * All times are relative to the ELAPSED time (in ms) since a festival begins.<br>
  77. * Festival manager start is the time after the server starts to begin the first festival cycle.<br>
  78. * The cycle length should ideally be at least 2x longer than the festival length.<br>
  79. * This allows ample time for players to sign-up to participate in the festival.<br>
  80. * The intermission is the time between the festival participants being moved to the "arenas" and the spawning of the first set of mobs.<br>
  81. * The monster swarm time is the time before the monsters swarm to the center of the arena, after they are spawned.<br>
  82. * The chest spawn time is for when the bonus festival chests spawn, usually towards the end of the festival.
  83. */
  84. public static final long FESTIVAL_SIGNUP_TIME = Config.ALT_FESTIVAL_CYCLE_LENGTH - Config.ALT_FESTIVAL_LENGTH - 60000;
  85. // Key Constants \\
  86. private static final int FESTIVAL_MAX_OFFSET_X = 230;
  87. private static final int FESTIVAL_MAX_OFFSET_Y = 230;
  88. private static final int FESTIVAL_DEFAULT_RESPAWN = 60; // Specify in seconds!
  89. public static final int FESTIVAL_COUNT = 5; // do not change without correcting db and SevenSigns itself !
  90. public static final int FESTIVAL_LEVEL_MAX_31 = 0;
  91. public static final int FESTIVAL_LEVEL_MAX_42 = 1;
  92. public static final int FESTIVAL_LEVEL_MAX_53 = 2;
  93. public static final int FESTIVAL_LEVEL_MAX_64 = 3;
  94. public static final int FESTIVAL_LEVEL_MAX_NONE = 4;
  95. // 500 maximum possible score
  96. public static final int[] FESTIVAL_LEVEL_SCORES =
  97. {
  98. 60,
  99. 70,
  100. 100,
  101. 120,
  102. 150
  103. };
  104. public static final int FESTIVAL_OFFERING_ID = 5901;
  105. public static final int FESTIVAL_OFFERING_VALUE = 5;
  106. /**
  107. * The following contains all the necessary spawn data for:<br>
  108. * <ul>
  109. * <li>Player Start Locations
  110. * <li>
  111. * <li>Witches
  112. * <li>
  113. * <li>Monsters
  114. * <li>
  115. * <li>Chests</li>
  116. * </ul>
  117. * All data is given by: X, Y, Z (coords), Heading, NPC ID (if necessary).<br>
  118. * This may be moved externally in time, but the data should not change.<br>
  119. */
  120. // @formatter:off
  121. public static final int[][] FESTIVAL_DAWN_PLAYER_SPAWNS =
  122. {
  123. { -79187, 113186, -4895, 0 }, // 31 and below
  124. { -75918, 110137, -4895, 0 }, // 42 and below
  125. { -73835, 111969, -4895, 0 }, // 53 and below
  126. { -76170, 113804, -4895, 0 }, // 64 and below
  127. { -78927, 109528, -4895, 0 } // No level limit
  128. };
  129. public static final int[][] FESTIVAL_DUSK_PLAYER_SPAWNS =
  130. {
  131. { -77200, 88966, -5151, 0 }, // 31 and below
  132. { -76941, 85307, -5151, 0 }, // 42 and below
  133. { -74855, 87135, -5151, 0 }, // 53 and below
  134. { -80208, 88222, -5151, 0 }, // 64 and below
  135. { -79954, 84697, -5151, 0 } // No level limit
  136. };
  137. protected static final int[][] FESTIVAL_DAWN_WITCH_SPAWNS =
  138. {
  139. { -79183, 113052, -4891, 0, 31132 }, // 31 and below
  140. { -75916, 110270, -4891, 0, 31133 }, // 42 and below
  141. { -73979, 111970, -4891, 0, 31134 }, // 53 and below
  142. { -76174, 113663, -4891, 0, 31135 }, // 64 and below
  143. { -78930, 109664, -4891, 0, 31136 } // No level limit
  144. };
  145. protected static final int[][] FESTIVAL_DUSK_WITCH_SPAWNS =
  146. {
  147. { -77199, 88830, -5147, 0, 31142 }, // 31 and below
  148. { -76942, 85438, -5147, 0, 31143 }, // 42 and below
  149. { -74990, 87135, -5147, 0, 31144 }, // 53 and below
  150. { -80207, 88222, -5147, 0, 31145 }, // 64 and below
  151. { -79952, 84833, -5147, 0, 31146 } // No level limit
  152. };
  153. protected static final int[][][] FESTIVAL_DAWN_PRIMARY_SPAWNS =
  154. {
  155. {
  156. /* Level 31 and Below - Offering of the Branded */
  157. { -78537, 113839, -4895, -1, 18009 },
  158. { -78466, 113852, -4895, -1, 18010 },
  159. { -78509, 113899, -4895, -1, 18010 },
  160. { -78481, 112557, -4895, -1, 18009 },
  161. { -78559, 112504, -4895, -1, 18010 },
  162. { -78489, 112494, -4895, -1, 18010 },
  163. { -79803, 112543, -4895, -1, 18012 },
  164. { -79854, 112492, -4895, -1, 18013 },
  165. { -79886, 112557, -4895, -1, 18014 },
  166. { -79821, 113811, -4895, -1, 18015 },
  167. { -79857, 113896, -4895, -1, 18017 },
  168. { -79878, 113816, -4895, -1, 18018 },
  169. // Archers and Marksmen \\
  170. { -79190, 113660, -4895, -1, 18011 },
  171. { -78710, 113188, -4895, -1, 18011 },
  172. { -79190, 112730, -4895, -1, 18016 },
  173. { -79656, 113188, -4895, -1, 18016 }
  174. },
  175. {
  176. /* Level 42 and Below - Apostate Offering */
  177. { -76558, 110784, -4895, -1, 18019 },
  178. { -76607, 110815, -4895, -1, 18020 }, // South West
  179. { -76559, 110820, -4895, -1, 18020 },
  180. { -75277, 110792, -4895, -1, 18019 },
  181. { -75225, 110801, -4895, -1, 18020 }, // South East
  182. { -75262, 110832, -4895, -1, 18020 },
  183. { -75249, 109441, -4895, -1, 18022 },
  184. { -75278, 109495, -4895, -1, 18023 }, // North East
  185. { -75223, 109489, -4895, -1, 18024 },
  186. { -76556, 109490, -4895, -1, 18025 },
  187. { -76607, 109469, -4895, -1, 18027 }, // North West
  188. { -76561, 109450, -4895, -1, 18028 },
  189. // Archers and Marksmen \\
  190. { -76399, 110144, -4895, -1, 18021 },
  191. { -75912, 110606, -4895, -1, 18021 },
  192. { -75444, 110144, -4895, -1, 18026 },
  193. { -75930, 109665, -4895, -1, 18026 }
  194. },
  195. {
  196. /* Level 53 and Below - Witch's Offering */
  197. { -73184, 111319, -4895, -1, 18029 },
  198. { -73135, 111294, -4895, -1, 18030 }, // South West
  199. { -73185, 111281, -4895, -1, 18030 },
  200. { -74477, 111321, -4895, -1, 18029 },
  201. { -74523, 111293, -4895, -1, 18030 }, // South East
  202. { -74481, 111280, -4895, -1, 18030 },
  203. { -74489, 112604, -4895, -1, 18032 },
  204. { -74491, 112660, -4895, -1, 18033 }, // North East
  205. { -74527, 112629, -4895, -1, 18034 },
  206. { -73197, 112621, -4895, -1, 18035 },
  207. { -73142, 112631, -4895, -1, 18037 }, // North West
  208. { -73182, 112656, -4895, -1, 18038 },
  209. // Archers and Marksmen \\
  210. { -73834, 112430, -4895, -1, 18031 },
  211. { -74299, 111959, -4895, -1, 18031 },
  212. { -73841, 111491, -4895, -1, 18036 },
  213. { -73363, 111959, -4895, -1, 18036 }
  214. },
  215. {
  216. /* Level 64 and Below - Dark Omen Offering */
  217. { -75543, 114461, -4895, -1, 18039 },
  218. { -75514, 114493, -4895, -1, 18040 }, // South West
  219. { -75488, 114456, -4895, -1, 18040 },
  220. { -75521, 113158, -4895, -1, 18039 },
  221. { -75504, 113110, -4895, -1, 18040 }, // South East
  222. { -75489, 113142, -4895, -1, 18040 },
  223. { -76809, 113143, -4895, -1, 18042 },
  224. { -76860, 113138, -4895, -1, 18043 }, // North East
  225. { -76831, 113112, -4895, -1, 18044 },
  226. { -76831, 114441, -4895, -1, 18045 },
  227. { -76840, 114490, -4895, -1, 18047 }, // North West
  228. { -76864, 114455, -4895, -1, 18048 },
  229. // Archers and Marksmen \\
  230. { -75703, 113797, -4895, -1, 18041 },
  231. { -76180, 114263, -4895, -1, 18041 },
  232. { -76639, 113797, -4895, -1, 18046 },
  233. { -76180, 113337, -4895, -1, 18046 }
  234. },
  235. {
  236. /* No Level Limit - Offering of Forbidden Path */
  237. { -79576, 108881, -4895, -1, 18049 },
  238. { -79592, 108835, -4895, -1, 18050 }, // South West
  239. { -79614, 108871, -4895, -1, 18050 },
  240. { -79586, 110171, -4895, -1, 18049 },
  241. { -79589, 110216, -4895, -1, 18050 }, // South East
  242. { -79620, 110177, -4895, -1, 18050 },
  243. { -78825, 110182, -4895, -1, 18052 },
  244. { -78238, 110182, -4895, -1, 18053 }, // North East
  245. { -78266, 110218, -4895, -1, 18054 },
  246. { -78275, 108883, -4895, -1, 18055 },
  247. { -78267, 108839, -4895, -1, 18057 }, // North West
  248. { -78241, 108871, -4895, -1, 18058 },
  249. // Archers and Marksmen \\
  250. { -79394, 109538, -4895, -1, 18051 },
  251. { -78929, 109992, -4895, -1, 18051 },
  252. { -78454, 109538, -4895, -1, 18056 },
  253. { -78929, 109053, -4895, -1, 18056 }
  254. }
  255. };
  256. protected static final int[][][] FESTIVAL_DUSK_PRIMARY_SPAWNS =
  257. {
  258. {
  259. /* Level 31 and Below - Offering of the Branded */
  260. { -76542, 89653, -5151, -1, 18009 },
  261. { -76509, 89637, -5151, -1, 18010 },
  262. { -76548, 89614, -5151, -1, 18010 },
  263. { -76539, 88326, -5151, -1, 18009 },
  264. { -76512, 88289, -5151, -1, 18010 },
  265. { -76546, 88287, -5151, -1, 18010 },
  266. { -77879, 88308, -5151, -1, 18012 },
  267. { -77886, 88310, -5151, -1, 18013 },
  268. { -77879, 88278, -5151, -1, 18014 },
  269. { -77857, 89605, -5151, -1, 18015 },
  270. { -77858, 89658, -5151, -1, 18017 },
  271. { -77891, 89633, -5151, -1, 18018 },
  272. // Archers and Marksmen \\
  273. { -76728, 88962, -5151, -1, 18011 },
  274. { -77194, 88494, -5151, -1, 18011 },
  275. { -77660, 88896, -5151, -1, 18016 },
  276. { -77195, 89438, -5151, -1, 18016 }
  277. },
  278. {
  279. /* Level 42 and Below - Apostate's Offering */
  280. { -77585, 84650, -5151, -1, 18019 },
  281. { -77628, 84643, -5151, -1, 18020 },
  282. { -77607, 84613, -5151, -1, 18020 },
  283. { -76603, 85946, -5151, -1, 18019 },
  284. { -77606, 85994, -5151, -1, 18020 },
  285. { -77638, 85959, -5151, -1, 18020 },
  286. { -76301, 85960, -5151, -1, 18022 },
  287. { -76257, 85972, -5151, -1, 18023 },
  288. { -76286, 85992, -5151, -1, 18024 },
  289. { -76281, 84667, -5151, -1, 18025 },
  290. { -76291, 84611, -5151, -1, 18027 },
  291. { -76257, 84616, -5151, -1, 18028 },
  292. // Archers and Marksmen \\
  293. { -77419, 85307, -5151, -1, 18021 },
  294. { -76952, 85768, -5151, -1, 18021 },
  295. { -76477, 85312, -5151, -1, 18026 },
  296. { -76942, 84832, -5151, -1, 18026 }
  297. },
  298. {
  299. /* Level 53 and Below - Witch's Offering */
  300. { -74211, 86494, -5151, -1, 18029 },
  301. { -74200, 86449, -5151, -1, 18030 },
  302. { -74167, 86464, -5151, -1, 18030 },
  303. { -75495, 86482, -5151, -1, 18029 },
  304. { -75540, 86473, -5151, -1, 18030 },
  305. { -75509, 86445, -5151, -1, 18030 },
  306. { -75509, 87775, -5151, -1, 18032 },
  307. { -75518, 87826, -5151, -1, 18033 },
  308. { -75542, 87780, -5151, -1, 18034 },
  309. { -74214, 87789, -5151, -1, 18035 },
  310. { -74169, 87801, -5151, -1, 18037 },
  311. { -74198, 87827, -5151, -1, 18038 },
  312. // Archers and Marksmen \\
  313. { -75324, 87135, -5151, -1, 18031 },
  314. { -74852, 87606, -5151, -1, 18031 },
  315. { -74388, 87146, -5151, -1, 18036 },
  316. { -74856, 86663, -5151, -1, 18036 }
  317. },
  318. {
  319. /* Level 64 and Below - Dark Omen Offering */
  320. { -79560, 89007, -5151, -1, 18039 },
  321. { -79521, 89016, -5151, -1, 18040 },
  322. { -79544, 89047, -5151, -1, 18040 },
  323. { -79552, 87717, -5151, -1, 18039 },
  324. { -79552, 87673, -5151, -1, 18040 },
  325. { -79510, 87702, -5151, -1, 18040 },
  326. { -80866, 87719, -5151, -1, 18042 },
  327. { -80897, 87689, -5151, -1, 18043 },
  328. { -80850, 87685, -5151, -1, 18044 },
  329. { -80848, 89013, -5151, -1, 18045 },
  330. { -80887, 89051, -5151, -1, 18047 },
  331. { -80891, 89004, -5151, -1, 18048 },
  332. // Archers and Marksmen \\
  333. { -80205, 87895, -5151, -1, 18041 },
  334. { -80674, 88350, -5151, -1, 18041 },
  335. { -80209, 88833, -5151, -1, 18046 },
  336. { -79743, 88364, -5151, -1, 18046 }
  337. },
  338. {
  339. /* No Level Limit - Offering of Forbidden Path */
  340. { -80624, 84060, -5151, -1, 18049 },
  341. { -80621, 84007, -5151, -1, 18050 },
  342. { -80590, 84039, -5151, -1, 18050 },
  343. { -80605, 85349, -5151, -1, 18049 },
  344. { -80639, 85363, -5151, -1, 18050 },
  345. { -80611, 85385, -5151, -1, 18050 },
  346. { -79311, 85353, -5151, -1, 18052 },
  347. { -79277, 85384, -5151, -1, 18053 },
  348. { -79273, 85539, -5151, -1, 18054 },
  349. { -79297, 84054, -5151, -1, 18055 },
  350. { -79285, 84006, -5151, -1, 18057 },
  351. { -79260, 84040, -5151, -1, 18058 },
  352. // Archers and Marksmen \\
  353. { -79945, 85171, -5151, -1, 18051 },
  354. { -79489, 84707, -5151, -1, 18051 },
  355. { -79952, 84222, -5151, -1, 18056 },
  356. { -80423, 84703, -5151, -1, 18056 }
  357. }
  358. };
  359. protected static final int[][][] FESTIVAL_DAWN_SECONDARY_SPAWNS =
  360. {
  361. {
  362. /* 31 and Below */
  363. { -78757, 112834, -4895, -1, 18016 },
  364. { -78581, 112834, -4895, -1, 18016 },
  365. { -78822, 112526, -4895, -1, 18011 },
  366. { -78822, 113702, -4895, -1, 18011 },
  367. { -78822, 113874, -4895, -1, 18011 },
  368. { -79524, 113546, -4895, -1, 18011 },
  369. { -79693, 113546, -4895, -1, 18011 },
  370. { -79858, 113546, -4895, -1, 18011 },
  371. { -79545, 112757, -4895, -1, 18016 },
  372. { -79545, 112586, -4895, -1, 18016 },
  373. },
  374. {
  375. /* 42 and Below */
  376. { -75565, 110580, -4895, -1, 18026 },
  377. { -75565, 110740, -4895, -1, 18026 },
  378. { -75577, 109776, -4895, -1, 18021 },
  379. { -75413, 109776, -4895, -1, 18021 },
  380. { -75237, 109776, -4895, -1, 18021 },
  381. { -76274, 109468, -4895, -1, 18021 },
  382. { -76274, 109635, -4895, -1, 18021 },
  383. { -76274, 109795, -4895, -1, 18021 },
  384. { -76351, 110500, -4895, -1, 18056 },
  385. { -76528, 110500, -4895, -1, 18056 },
  386. },
  387. {
  388. /* 53 and Below */
  389. { -74191, 111527, -4895, -1, 18036 },
  390. { -74191, 111362, -4895, -1, 18036 },
  391. { -73495, 111611, -4895, -1, 18031 },
  392. { -73327, 111611, -4895, -1, 18031 },
  393. { -73154, 111611, -4895, -1, 18031 },
  394. { -73473, 112301, -4895, -1, 18031 },
  395. { -73473, 112475, -4895, -1, 18031 },
  396. { -73473, 112649, -4895, -1, 18031 },
  397. { -74270, 112326, -4895, -1, 18036 },
  398. { -74443, 112326, -4895, -1, 18036 },
  399. },
  400. {
  401. /* 64 and Below */
  402. { -75738, 113439, -4895, -1, 18046 },
  403. { -75571, 113439, -4895, -1, 18046 },
  404. { -75824, 114141, -4895, -1, 18041 },
  405. { -75824, 114309, -4895, -1, 18041 },
  406. { -75824, 114477, -4895, -1, 18041 },
  407. { -76513, 114158, -4895, -1, 18041 },
  408. { -76683, 114158, -4895, -1, 18041 },
  409. { -76857, 114158, -4895, -1, 18041 },
  410. { -76535, 113357, -4895, -1, 18056 },
  411. { -76535, 113190, -4895, -1, 18056 },
  412. },
  413. {
  414. /* No Level Limit */
  415. { -79350, 109894, -4895, -1, 18056 },
  416. { -79534, 109894, -4895, -1, 18056 },
  417. { -79285, 109187, -4895, -1, 18051 },
  418. { -79285, 109019, -4895, -1, 18051 },
  419. { -79285, 108860, -4895, -1, 18051 },
  420. { -78587, 109172, -4895, -1, 18051 },
  421. { -78415, 109172, -4895, -1, 18051 },
  422. { -78249, 109172, -4895, -1, 18051 },
  423. { -78575, 109961, -4895, -1, 18056 },
  424. { -78575, 110130, -4895, -1, 18056 },
  425. }
  426. };
  427. protected static final int[][][] FESTIVAL_DUSK_SECONDARY_SPAWNS =
  428. {
  429. {
  430. /* 31 and Below */
  431. { -76844, 89304, -5151, -1, 18011 },
  432. { -76844, 89479, -5151, -1, 18011 },
  433. { -76844, 89649, -5151, -1, 18011 },
  434. { -77544, 89326, -5151, -1, 18011 },
  435. { -77716, 89326, -5151, -1, 18011 },
  436. { -77881, 89326, -5151, -1, 18011 },
  437. { -77561, 88530, -5151, -1, 18016 },
  438. { -77561, 88364, -5151, -1, 18016 },
  439. { -76762, 88615, -5151, -1, 18016 },
  440. { -76594, 88615, -5151, -1, 18016 },
  441. },
  442. {
  443. /* 42 and Below */
  444. { -77307, 84969, -5151, -1, 18021 },
  445. { -77307, 84795, -5151, -1, 18021 },
  446. { -77307, 84623, -5151, -1, 18021 },
  447. { -76614, 84944, -5151, -1, 18021 },
  448. { -76433, 84944, -5151, -1, 18021 },
  449. { -76251, 84944, -5151, -1, 18021 },
  450. { -76594, 85745, -5151, -1, 18026 },
  451. { -76594, 85910, -5151, -1, 18026 },
  452. { -77384, 85660, -5151, -1, 18026 },
  453. { -77555, 85660, -5151, -1, 18026 },
  454. },
  455. {
  456. /* 53 and Below */
  457. { -74517, 86782, -5151, -1, 18031 },
  458. { -74344, 86782, -5151, -1, 18031 },
  459. { -74185, 86782, -5151, -1, 18031 },
  460. { -74496, 87464, -5151, -1, 18031 },
  461. { -74496, 87636, -5151, -1, 18031 },
  462. { -74496, 87815, -5151, -1, 18031 },
  463. { -75298, 87497, -5151, -1, 18036 },
  464. { -75460, 87497, -5151, -1, 18036 },
  465. { -75219, 86712, -5151, -1, 18036 },
  466. { -75219, 86531, -5151, -1, 18036 },
  467. },
  468. {
  469. /* 64 and Below */
  470. { -79851, 88703, -5151, -1, 18041 },
  471. { -79851, 88868, -5151, -1, 18041 },
  472. { -79851, 89040, -5151, -1, 18041 },
  473. { -80548, 88722, -5151, -1, 18041 },
  474. { -80711, 88722, -5151, -1, 18041 },
  475. { -80883, 88722, -5151, -1, 18041 },
  476. { -80565, 87916, -5151, -1, 18046 },
  477. { -80565, 87752, -5151, -1, 18046 },
  478. { -79779, 87996, -5151, -1, 18046 },
  479. { -79613, 87996, -5151, -1, 18046 },
  480. },
  481. {
  482. /* No Level Limit */
  483. { -79271, 84330, -5151, -1, 18051 },
  484. { -79448, 84330, -5151, -1, 18051 },
  485. { -79601, 84330, -5151, -1, 18051 },
  486. { -80311, 84367, -5151, -1, 18051 },
  487. { -80311, 84196, -5151, -1, 18051 },
  488. { -80311, 84015, -5151, -1, 18051 },
  489. { -80556, 85049, -5151, -1, 18056 },
  490. { -80384, 85049, -5151, -1, 18056 },
  491. { -79598, 85127, -5151, -1, 18056 },
  492. { -79598, 85303, -5151, -1, 18056 },
  493. }
  494. };
  495. protected static final int[][][] FESTIVAL_DAWN_CHEST_SPAWNS =
  496. {
  497. {
  498. /* Level 31 and Below */
  499. { -78999, 112957, -4927, -1, 18109 },
  500. { -79153, 112873, -4927, -1, 18109 },
  501. { -79256, 112873, -4927, -1, 18109 },
  502. { -79368, 112957, -4927, -1, 18109 },
  503. { -79481, 113124, -4927, -1, 18109 },
  504. { -79481, 113275, -4927, -1, 18109 },
  505. { -79364, 113398, -4927, -1, 18109 },
  506. { -79213, 113500, -4927, -1, 18109 },
  507. { -79099, 113500, -4927, -1, 18109 },
  508. { -78960, 113398, -4927, -1, 18109 },
  509. { -78882, 113235, -4927, -1, 18109 },
  510. { -78882, 113099, -4927, -1, 18109 },
  511. },
  512. {
  513. /* Level 42 and Below */
  514. { -76119, 110383, -4927, -1, 18110 },
  515. { -75980, 110442, -4927, -1, 18110 },
  516. { -75848, 110442, -4927, -1, 18110 },
  517. { -75720, 110383, -4927, -1, 18110 },
  518. { -75625, 110195, -4927, -1, 18110 },
  519. { -75625, 110063, -4927, -1, 18110 },
  520. { -75722, 109908, -4927, -1, 18110 },
  521. { -75863, 109832, -4927, -1, 18110 },
  522. { -75989, 109832, -4927, -1, 18110 },
  523. { -76130, 109908, -4927, -1, 18110 },
  524. { -76230, 110079, -4927, -1, 18110 },
  525. { -76230, 110215, -4927, -1, 18110 },
  526. },
  527. {
  528. /* Level 53 and Below */
  529. { -74055, 111781, -4927, -1, 18111 },
  530. { -74144, 111938, -4927, -1, 18111 },
  531. { -74144, 112075, -4927, -1, 18111 },
  532. { -74055, 112173, -4927, -1, 18111 },
  533. { -73885, 112289, -4927, -1, 18111 },
  534. { -73756, 112289, -4927, -1, 18111 },
  535. { -73574, 112141, -4927, -1, 18111 },
  536. { -73511, 112040, -4927, -1, 18111 },
  537. { -73511, 111912, -4927, -1, 18111 },
  538. { -73574, 111772, -4927, -1, 18111 },
  539. { -73767, 111669, -4927, -1, 18111 },
  540. { -73899, 111669, -4927, -1, 18111 },
  541. },
  542. {
  543. /* Level 64 and Below */
  544. { -76008, 113566, -4927, -1, 18112 },
  545. { -76159, 113485, -4927, -1, 18112 },
  546. { -76267, 113485, -4927, -1, 18112 },
  547. { -76386, 113566, -4927, -1, 18112 },
  548. { -76482, 113748, -4927, -1, 18112 },
  549. { -76482, 113885, -4927, -1, 18112 },
  550. { -76371, 114029, -4927, -1, 18112 },
  551. { -76220, 114118, -4927, -1, 18112 },
  552. { -76092, 114118, -4927, -1, 18112 },
  553. { -75975, 114029, -4927, -1, 18112 },
  554. { -75861, 113851, -4927, -1, 18112 },
  555. { -75861, 113713, -4927, -1, 18112 },
  556. },
  557. {
  558. /* No Level Limit */
  559. { -79100, 109782, -4927, -1, 18113 },
  560. { -78962, 109853, -4927, -1, 18113 },
  561. { -78851, 109853, -4927, -1, 18113 },
  562. { -78721, 109782, -4927, -1, 18113 },
  563. { -78615, 109596, -4927, -1, 18113 },
  564. { -78615, 109453, -4927, -1, 18113 },
  565. { -78746, 109300, -4927, -1, 18113 },
  566. { -78881, 109203, -4927, -1, 18113 },
  567. { -79027, 109203, -4927, -1, 18113 },
  568. { -79159, 109300, -4927, -1, 18113 },
  569. { -79240, 109480, -4927, -1, 18113 },
  570. { -79240, 109615, -4927, -1, 18113 },
  571. }
  572. };
  573. protected static final int[][][] FESTIVAL_DUSK_CHEST_SPAWNS =
  574. {
  575. {
  576. /* Level 31 and Below */
  577. { -77016, 88726, -5183, -1, 18114 },
  578. { -77136, 88646, -5183, -1, 18114 },
  579. { -77247, 88646, -5183, -1, 18114 },
  580. { -77380, 88726, -5183, -1, 18114 },
  581. { -77512, 88883, -5183, -1, 18114 },
  582. { -77512, 89053, -5183, -1, 18114 },
  583. { -77378, 89287, -5183, -1, 18114 },
  584. { -77254, 89238, -5183, -1, 18114 },
  585. { -77095, 89238, -5183, -1, 18114 },
  586. { -76996, 89287, -5183, -1, 18114 },
  587. { -76901, 89025, -5183, -1, 18114 },
  588. { -76901, 88891, -5183, -1, 18114 },
  589. },
  590. {
  591. /* Level 42 and Below */
  592. { -77128, 85553, -5183, -1, 18115 },
  593. { -77036, 85594, -5183, -1, 18115 },
  594. { -76919, 85594, -5183, -1, 18115 },
  595. { -76755, 85553, -5183, -1, 18115 },
  596. { -76635, 85392, -5183, -1, 18115 },
  597. { -76635, 85216, -5183, -1, 18115 },
  598. { -76761, 85025, -5183, -1, 18115 },
  599. { -76908, 85004, -5183, -1, 18115 },
  600. { -77041, 85004, -5183, -1, 18115 },
  601. { -77138, 85025, -5183, -1, 18115 },
  602. { -77268, 85219, -5183, -1, 18115 },
  603. { -77268, 85410, -5183, -1, 18115 },
  604. },
  605. {
  606. /* Level 53 and Below */
  607. { -75150, 87303, -5183, -1, 18116 },
  608. { -75150, 87175, -5183, -1, 18116 },
  609. { -75150, 87175, -5183, -1, 18116 },
  610. { -75150, 87303, -5183, -1, 18116 },
  611. { -74943, 87433, -5183, -1, 18116 },
  612. { -74767, 87433, -5183, -1, 18116 },
  613. { -74556, 87306, -5183, -1, 18116 },
  614. { -74556, 87184, -5183, -1, 18116 },
  615. { -74556, 87184, -5183, -1, 18116 },
  616. { -74556, 87306, -5183, -1, 18116 },
  617. { -74757, 86830, -5183, -1, 18116 },
  618. { -74927, 86830, -5183, -1, 18116 },
  619. },
  620. {
  621. /* Level 64 and Below */
  622. { -80010, 88128, -5183, -1, 18117 },
  623. { -80113, 88066, -5183, -1, 18117 },
  624. { -80220, 88066, -5183, -1, 18117 },
  625. { -80359, 88128, -5183, -1, 18117 },
  626. { -80467, 88267, -5183, -1, 18117 },
  627. { -80467, 88436, -5183, -1, 18117 },
  628. { -80381, 88639, -5183, -1, 18117 },
  629. { -80278, 88577, -5183, -1, 18117 },
  630. { -80142, 88577, -5183, -1, 18117 },
  631. { -80028, 88639, -5183, -1, 18117 },
  632. { -79915, 88466, -5183, -1, 18117 },
  633. { -79915, 88322, -5183, -1, 18117 },
  634. },
  635. {
  636. /* No Level Limit */
  637. { -80153, 84947, -5183, -1, 18118 },
  638. { -80003, 84962, -5183, -1, 18118 },
  639. { -79848, 84962, -5183, -1, 18118 },
  640. { -79742, 84947, -5183, -1, 18118 },
  641. { -79668, 84772, -5183, -1, 18118 },
  642. { -79668, 84619, -5183, -1, 18118 },
  643. { -79772, 84471, -5183, -1, 18118 },
  644. { -79888, 84414, -5183, -1, 18118 },
  645. { -80023, 84414, -5183, -1, 18118 },
  646. { -80166, 84471, -5183, -1, 18118 },
  647. { -80253, 84600, -5183, -1, 18118 },
  648. { -80253, 84780, -5183, -1, 18118 },
  649. }
  650. };
  651. // @formatter:on
  652. private FestivalManager _managerInstance;
  653. protected ScheduledFuture<?> _managerScheduledTask;
  654. protected int _signsCycle = SevenSigns.getInstance().getCurrentCycle();
  655. protected int _festivalCycle;
  656. protected long _nextFestivalCycleStart;
  657. protected long _nextFestivalStart;
  658. protected boolean _festivalInitialized;
  659. protected boolean _festivalInProgress;
  660. protected List<Integer> _accumulatedBonuses = new ArrayList<>(); // The total bonus available (in Ancient Adena)
  661. boolean _noPartyRegister;
  662. private L2Npc _dawnChatGuide;
  663. private L2Npc _duskChatGuide;
  664. protected Map<Integer, List<Integer>> _dawnFestivalParticipants = new HashMap<>();
  665. protected Map<Integer, List<Integer>> _duskFestivalParticipants = new HashMap<>();
  666. protected Map<Integer, List<Integer>> _dawnPreviousParticipants = new HashMap<>();
  667. protected Map<Integer, List<Integer>> _duskPreviousParticipants = new HashMap<>();
  668. private final Map<Integer, Long> _dawnFestivalScores = new HashMap<>();
  669. private final Map<Integer, Long> _duskFestivalScores = new HashMap<>();
  670. /**
  671. * _festivalData is essentially an instance of the seven_signs_festival table and should be treated as such. Data is initially accessed by the related Seven Signs cycle, with _signsCycle representing data for the current round of Festivals. The actual table data is stored as a series of StatsSet
  672. * constructs. These are accessed by the use of an offset based on the number of festivals, thus: offset = FESTIVAL_COUNT + festivalId (Data for Dawn is always accessed by offset > FESTIVAL_COUNT)
  673. */
  674. private final Map<Integer, Map<Integer, StatsSet>> _festivalData = new HashMap<>();
  675. protected SevenSignsFestival()
  676. {
  677. restoreFestivalData();
  678. if (SevenSigns.getInstance().isSealValidationPeriod())
  679. {
  680. _log.info("SevenSignsFestival: Initialization bypassed due to Seal Validation in effect.");
  681. return;
  682. }
  683. L2Spawn.addSpawnListener(this);
  684. startFestivalManager();
  685. }
  686. public static SevenSignsFestival getInstance()
  687. {
  688. return SingletonHolder._instance;
  689. }
  690. /**
  691. * Returns the associated name (level range) to a given festival ID.
  692. * @param festivalID
  693. * @return String festivalName
  694. */
  695. public static final String getFestivalName(int festivalID)
  696. {
  697. String festivalName;
  698. switch (festivalID)
  699. {
  700. case FESTIVAL_LEVEL_MAX_31:
  701. festivalName = "Level 31 or lower";
  702. break;
  703. case FESTIVAL_LEVEL_MAX_42:
  704. festivalName = "Level 42 or lower";
  705. break;
  706. case FESTIVAL_LEVEL_MAX_53:
  707. festivalName = "Level 53 or lower";
  708. break;
  709. case FESTIVAL_LEVEL_MAX_64:
  710. festivalName = "Level 64 or lower";
  711. break;
  712. default:
  713. festivalName = "No Level Limit";
  714. break;
  715. }
  716. return festivalName;
  717. }
  718. /**
  719. * Returns the maximum allowed player level for the given festival type.
  720. * @param festivalId
  721. * @return int maxLevel
  722. */
  723. public static final int getMaxLevelForFestival(int festivalId)
  724. {
  725. int maxLevel = (ExperienceData.getInstance().getMaxLevel() - 1);
  726. switch (festivalId)
  727. {
  728. case SevenSignsFestival.FESTIVAL_LEVEL_MAX_31:
  729. maxLevel = 31;
  730. break;
  731. case SevenSignsFestival.FESTIVAL_LEVEL_MAX_42:
  732. maxLevel = 42;
  733. break;
  734. case SevenSignsFestival.FESTIVAL_LEVEL_MAX_53:
  735. maxLevel = 53;
  736. break;
  737. case SevenSignsFestival.FESTIVAL_LEVEL_MAX_64:
  738. maxLevel = 64;
  739. break;
  740. }
  741. return maxLevel;
  742. }
  743. /**
  744. * Returns true if the monster ID given is of an archer/marksman type.
  745. * @param npcId
  746. * @return boolean isArcher
  747. */
  748. protected static final boolean isFestivalArcher(int npcId)
  749. {
  750. if ((npcId < 18009) || (npcId > 18108))
  751. {
  752. return false;
  753. }
  754. int identifier = npcId % 10;
  755. return ((identifier == 4) || (identifier == 9));
  756. }
  757. /**
  758. * Returns true if the monster ID given is a festival chest.
  759. * @param npcId
  760. * @return boolean isChest
  761. */
  762. protected static final boolean isFestivalChest(int npcId)
  763. {
  764. return ((npcId < 18109) || (npcId > 18118));
  765. }
  766. /**
  767. * Primarily used to terminate the Festival Manager, when the Seven Signs period changes.
  768. * @return ScheduledFuture festManagerScheduler
  769. */
  770. protected final ScheduledFuture<?> getFestivalManagerSchedule()
  771. {
  772. if (_managerScheduledTask == null)
  773. {
  774. startFestivalManager();
  775. }
  776. return _managerScheduledTask;
  777. }
  778. /**
  779. * Used to start the Festival Manager, if the current period is not Seal Validation.
  780. */
  781. protected void startFestivalManager()
  782. {
  783. // Start the Festival Manager for the first time after the server has started
  784. // at the specified time, then invoke it automatically after every cycle.
  785. _managerInstance = new FestivalManager();
  786. setNextFestivalStart(Config.ALT_FESTIVAL_MANAGER_START + FESTIVAL_SIGNUP_TIME);
  787. _managerScheduledTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(_managerInstance, Config.ALT_FESTIVAL_MANAGER_START, Config.ALT_FESTIVAL_CYCLE_LENGTH);
  788. _log.info("SevenSignsFestival: The first Festival of Darkness cycle begins in " + (Config.ALT_FESTIVAL_MANAGER_START / 60000) + " minute(s).");
  789. }
  790. /**
  791. * Restores saved festival data, basic settings from the properties file and past high score data from the database.
  792. */
  793. protected void restoreFestivalData()
  794. {
  795. try (Connection con = ConnectionFactory.getInstance().getConnection();
  796. Statement s = con.createStatement();
  797. ResultSet rs = s.executeQuery("SELECT festivalId, cabal, cycle, date, score, members " + "FROM seven_signs_festival"))
  798. {
  799. while (rs.next())
  800. {
  801. int festivalCycle = rs.getInt("cycle");
  802. int festivalId = rs.getInt("festivalId");
  803. String cabal = rs.getString("cabal");
  804. StatsSet festivalDat = new StatsSet();
  805. festivalDat.set("festivalId", festivalId);
  806. festivalDat.set("cabal", cabal);
  807. festivalDat.set("cycle", festivalCycle);
  808. festivalDat.set("date", rs.getString("date"));
  809. festivalDat.set("score", rs.getInt("score"));
  810. festivalDat.set("members", rs.getString("members"));
  811. if (cabal.equals("dawn"))
  812. {
  813. festivalId += FESTIVAL_COUNT;
  814. }
  815. final Map<Integer, StatsSet> tempData = _festivalData.getOrDefault(festivalCycle, new HashMap<>());
  816. tempData.put(festivalId, festivalDat);
  817. _festivalData.put(festivalCycle, tempData);
  818. }
  819. }
  820. catch (SQLException e)
  821. {
  822. _log.log(Level.SEVERE, "SevenSignsFestival: Failed to load configuration: " + e.getMessage(), e);
  823. }
  824. StringBuilder query = new StringBuilder();
  825. query.append("SELECT festival_cycle, ");
  826. for (int i = 0; i < (FESTIVAL_COUNT - 1); i++)
  827. {
  828. query.append("accumulated_bonus");
  829. query.append(String.valueOf(i));
  830. query.append(", ");
  831. }
  832. query.append("accumulated_bonus");
  833. query.append(String.valueOf(FESTIVAL_COUNT - 1));
  834. query.append(' ');
  835. query.append("FROM seven_signs_status WHERE id=0");
  836. try (Connection con = ConnectionFactory.getInstance().getConnection();
  837. Statement s = con.createStatement();
  838. ResultSet rs = s.executeQuery(query.toString()))
  839. {
  840. while (rs.next())
  841. {
  842. _festivalCycle = rs.getInt("festival_cycle");
  843. for (int i = 0; i < FESTIVAL_COUNT; i++)
  844. {
  845. _accumulatedBonuses.add(i, rs.getInt("accumulated_bonus" + String.valueOf(i)));
  846. }
  847. }
  848. }
  849. catch (SQLException e)
  850. {
  851. _log.log(Level.SEVERE, "SevenSignsFestival: Failed to load configuration: " + e.getMessage(), e);
  852. }
  853. }
  854. /**
  855. * Stores current festival data, basic settings to the properties file and past high score data to the database. If updateSettings = true, then all Seven Signs data is updated in the database.
  856. * @param updateSettings
  857. */
  858. public void saveFestivalData(boolean updateSettings)
  859. {
  860. try (Connection con = ConnectionFactory.getInstance().getConnection();
  861. PreparedStatement psUpdate = con.prepareStatement("UPDATE seven_signs_festival SET date=?, score=?, members=? WHERE cycle=? AND cabal=? AND festivalId=?");
  862. PreparedStatement psInsert = con.prepareStatement("INSERT INTO seven_signs_festival (festivalId, cabal, cycle, date, score, members) VALUES (?,?,?,?,?,?)"))
  863. {
  864. for (Map<Integer, StatsSet> currCycleData : _festivalData.values())
  865. {
  866. for (StatsSet festivalDat : currCycleData.values())
  867. {
  868. int festivalCycle = festivalDat.getInt("cycle");
  869. int festivalId = festivalDat.getInt("festivalId");
  870. String cabal = festivalDat.getString("cabal");
  871. // Try to update an existing record.
  872. psUpdate.setLong(1, Long.valueOf(festivalDat.getString("date")));
  873. psUpdate.setInt(2, festivalDat.getInt("score"));
  874. psUpdate.setString(3, festivalDat.getString("members"));
  875. psUpdate.setInt(4, festivalCycle);
  876. psUpdate.setString(5, cabal);
  877. psUpdate.setInt(6, festivalId);
  878. // If there was no record to update, assume it doesn't exist and add a new one,
  879. // otherwise continue with the next record to store.
  880. if (psUpdate.executeUpdate() > 0)
  881. {
  882. continue;
  883. }
  884. psInsert.setInt(1, festivalId);
  885. psInsert.setString(2, cabal);
  886. psInsert.setInt(3, festivalCycle);
  887. psInsert.setLong(4, Long.valueOf(festivalDat.getString("date")));
  888. psInsert.setInt(5, festivalDat.getInt("score"));
  889. psInsert.setString(6, festivalDat.getString("members"));
  890. psInsert.execute();
  891. psInsert.clearParameters();
  892. }
  893. }
  894. }
  895. catch (SQLException e)
  896. {
  897. _log.log(Level.SEVERE, "SevenSignsFestival: Failed to save configuration: " + e.getMessage(), e);
  898. }
  899. // Updates Seven Signs DB data also, so call only if really necessary.
  900. if (updateSettings)
  901. {
  902. SevenSigns.getInstance().saveSevenSignsStatus();
  903. }
  904. }
  905. /**
  906. * If a clan member is a member of the highest-ranked party in the Festival of Darkness, 100 points are added per member
  907. */
  908. protected void rewardHighestRanked()
  909. {
  910. String[] partyMembers;
  911. StatsSet overallData = getOverallHighestScoreData(FESTIVAL_LEVEL_MAX_31);
  912. if (overallData != null)
  913. {
  914. partyMembers = overallData.getString("members").split(",");
  915. for (String partyMemberName : partyMembers)
  916. {
  917. addReputationPointsForPartyMemberClan(partyMemberName);
  918. }
  919. }
  920. overallData = getOverallHighestScoreData(FESTIVAL_LEVEL_MAX_42);
  921. if (overallData != null)
  922. {
  923. partyMembers = overallData.getString("members").split(",");
  924. for (String partyMemberName : partyMembers)
  925. {
  926. addReputationPointsForPartyMemberClan(partyMemberName);
  927. }
  928. }
  929. overallData = getOverallHighestScoreData(FESTIVAL_LEVEL_MAX_53);
  930. if (overallData != null)
  931. {
  932. partyMembers = overallData.getString("members").split(",");
  933. for (String partyMemberName : partyMembers)
  934. {
  935. addReputationPointsForPartyMemberClan(partyMemberName);
  936. }
  937. }
  938. overallData = getOverallHighestScoreData(FESTIVAL_LEVEL_MAX_64);
  939. if (overallData != null)
  940. {
  941. partyMembers = overallData.getString("members").split(",");
  942. for (String partyMemberName : partyMembers)
  943. {
  944. addReputationPointsForPartyMemberClan(partyMemberName);
  945. }
  946. }
  947. overallData = getOverallHighestScoreData(FESTIVAL_LEVEL_MAX_NONE);
  948. if (overallData != null)
  949. {
  950. partyMembers = overallData.getString("members").split(",");
  951. for (String partyMemberName : partyMembers)
  952. {
  953. addReputationPointsForPartyMemberClan(partyMemberName);
  954. }
  955. }
  956. }
  957. private void addReputationPointsForPartyMemberClan(String partyMemberName)
  958. {
  959. L2PcInstance player = L2World.getInstance().getPlayer(partyMemberName);
  960. if (player != null)
  961. {
  962. if (player.getClan() != null)
  963. {
  964. player.getClan().addReputationScore(Config.FESTIVAL_WIN_POINTS, true);
  965. SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.CLAN_MEMBER_C1_WAS_IN_HIGHEST_RANKED_PARTY_IN_FESTIVAL_OF_DARKNESS_AND_GAINED_S2_REPUTATION);
  966. sm.addString(partyMemberName);
  967. sm.addInt(Config.FESTIVAL_WIN_POINTS);
  968. player.getClan().broadcastToOnlineMembers(sm);
  969. }
  970. }
  971. else
  972. {
  973. try (Connection con = ConnectionFactory.getInstance().getConnection();
  974. PreparedStatement ps = con.prepareStatement(GET_CLAN_NAME))
  975. {
  976. ps.setString(1, partyMemberName);
  977. try (ResultSet rs = ps.executeQuery())
  978. {
  979. if (rs.next())
  980. {
  981. String clanName = rs.getString("clan_name");
  982. if (clanName != null)
  983. {
  984. L2Clan clan = ClanTable.getInstance().getClanByName(clanName);
  985. if (clan != null)
  986. {
  987. clan.addReputationScore(Config.FESTIVAL_WIN_POINTS, true);
  988. SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.CLAN_MEMBER_C1_WAS_IN_HIGHEST_RANKED_PARTY_IN_FESTIVAL_OF_DARKNESS_AND_GAINED_S2_REPUTATION);
  989. sm.addString(partyMemberName);
  990. sm.addInt(Config.FESTIVAL_WIN_POINTS);
  991. clan.broadcastToOnlineMembers(sm);
  992. }
  993. }
  994. }
  995. }
  996. }
  997. catch (Exception e)
  998. {
  999. _log.log(Level.WARNING, "Could not get clan name of " + partyMemberName + ": " + e.getMessage(), e);
  1000. }
  1001. }
  1002. }
  1003. /**
  1004. * Used to reset all festival data at the beginning of a new quest event period.
  1005. * @param updateSettings
  1006. */
  1007. protected void resetFestivalData(boolean updateSettings)
  1008. {
  1009. _festivalCycle = 0;
  1010. _signsCycle = SevenSigns.getInstance().getCurrentCycle();
  1011. // Set all accumulated bonuses back to 0.
  1012. for (int i = 0; i < FESTIVAL_COUNT; i++)
  1013. {
  1014. _accumulatedBonuses.set(i, 0);
  1015. }
  1016. _dawnFestivalParticipants.clear();
  1017. _dawnPreviousParticipants.clear();
  1018. _dawnFestivalScores.clear();
  1019. _duskFestivalParticipants.clear();
  1020. _duskPreviousParticipants.clear();
  1021. _duskFestivalScores.clear();
  1022. // Set up a new data set for the current cycle of festivals
  1023. Map<Integer, StatsSet> newData = new HashMap<>();
  1024. for (int i = 0; i < (FESTIVAL_COUNT * 2); i++)
  1025. {
  1026. int festivalId = i;
  1027. if (i >= FESTIVAL_COUNT)
  1028. {
  1029. festivalId -= FESTIVAL_COUNT;
  1030. }
  1031. // Create a new StatsSet with "default" data for Dusk
  1032. StatsSet tempStats = new StatsSet();
  1033. tempStats.set("festivalId", festivalId);
  1034. tempStats.set("cycle", _signsCycle);
  1035. tempStats.set("date", "0");
  1036. tempStats.set("score", 0);
  1037. tempStats.set("members", "");
  1038. if (i >= FESTIVAL_COUNT)
  1039. {
  1040. tempStats.set("cabal", SevenSigns.getCabalShortName(SevenSigns.CABAL_DAWN));
  1041. }
  1042. else
  1043. {
  1044. tempStats.set("cabal", SevenSigns.getCabalShortName(SevenSigns.CABAL_DUSK));
  1045. }
  1046. newData.put(i, tempStats);
  1047. }
  1048. // Add the newly created cycle data to the existing festival data, and
  1049. // subsequently save it to the database.
  1050. _festivalData.put(_signsCycle, newData);
  1051. saveFestivalData(updateSettings);
  1052. // Remove any unused blood offerings from online players.
  1053. for (L2PcInstance player : L2World.getInstance().getPlayers())
  1054. {
  1055. final L2ItemInstance bloodOfferings = player.getInventory().getItemByItemId(FESTIVAL_OFFERING_ID);
  1056. if (bloodOfferings != null)
  1057. {
  1058. player.destroyItem("SevenSigns", bloodOfferings, null, false);
  1059. }
  1060. }
  1061. _log.info("SevenSignsFestival: Reinitialized engine for next competition period.");
  1062. }
  1063. public final int getCurrentFestivalCycle()
  1064. {
  1065. return _festivalCycle;
  1066. }
  1067. public final boolean isFestivalInitialized()
  1068. {
  1069. return _festivalInitialized;
  1070. }
  1071. public final boolean isFestivalInProgress()
  1072. {
  1073. return _festivalInProgress;
  1074. }
  1075. public void setNextCycleStart()
  1076. {
  1077. _nextFestivalCycleStart = System.currentTimeMillis() + Config.ALT_FESTIVAL_CYCLE_LENGTH;
  1078. }
  1079. public void setNextFestivalStart(long milliFromNow)
  1080. {
  1081. _nextFestivalStart = System.currentTimeMillis() + milliFromNow;
  1082. }
  1083. public final long getMinsToNextCycle()
  1084. {
  1085. if (SevenSigns.getInstance().isSealValidationPeriod())
  1086. {
  1087. return -1;
  1088. }
  1089. return (_nextFestivalCycleStart - System.currentTimeMillis()) / 60000;
  1090. }
  1091. public final int getMinsToNextFestival()
  1092. {
  1093. if (SevenSigns.getInstance().isSealValidationPeriod())
  1094. {
  1095. return -1;
  1096. }
  1097. return (int) (((_nextFestivalStart - System.currentTimeMillis()) / 60000) + 1);
  1098. }
  1099. public final String getTimeToNextFestivalStr()
  1100. {
  1101. if (SevenSigns.getInstance().isSealValidationPeriod())
  1102. {
  1103. return "<font color=\"FF0000\">This is the Seal Validation period. Festivals will resume next week.</font>";
  1104. }
  1105. return "<font color=\"FF0000\">The next festival will begin in " + getMinsToNextFestival() + " minute(s).</font>";
  1106. }
  1107. /**
  1108. * Returns the current festival ID and oracle ID that the specified player is in, but will return the default of {-1, -1} if the player is not found as a participant.
  1109. * @param player
  1110. * @return int[] playerFestivalInfo
  1111. */
  1112. public final int[] getFestivalForPlayer(L2PcInstance player)
  1113. {
  1114. int[] playerFestivalInfo =
  1115. {
  1116. -1,
  1117. -1
  1118. };
  1119. int festivalId = 0;
  1120. while (festivalId < FESTIVAL_COUNT)
  1121. {
  1122. List<Integer> participants = _dawnFestivalParticipants.get(festivalId);
  1123. // If there are no participants in this festival, move on to the next.
  1124. if ((participants != null) && participants.contains(player.getObjectId()))
  1125. {
  1126. playerFestivalInfo[0] = SevenSigns.CABAL_DAWN;
  1127. playerFestivalInfo[1] = festivalId;
  1128. return playerFestivalInfo;
  1129. }
  1130. participants = _duskFestivalParticipants.get(++festivalId);
  1131. if ((participants != null) && participants.contains(player.getObjectId()))
  1132. {
  1133. playerFestivalInfo[0] = SevenSigns.CABAL_DUSK;
  1134. playerFestivalInfo[1] = festivalId;
  1135. return playerFestivalInfo;
  1136. }
  1137. festivalId++;
  1138. }
  1139. // Return default data if the player is not found as a participant.
  1140. return playerFestivalInfo;
  1141. }
  1142. public final boolean isParticipant(L2PcInstance player)
  1143. {
  1144. if (SevenSigns.getInstance().isSealValidationPeriod())
  1145. {
  1146. return false;
  1147. }
  1148. if (_managerInstance == null)
  1149. {
  1150. return false;
  1151. }
  1152. for (List<Integer> participants : _dawnFestivalParticipants.values())
  1153. {
  1154. if ((participants != null) && participants.contains(player.getObjectId()))
  1155. {
  1156. return true;
  1157. }
  1158. }
  1159. for (List<Integer> participants : _duskFestivalParticipants.values())
  1160. {
  1161. if ((participants != null) && participants.contains(player.getObjectId()))
  1162. {
  1163. return true;
  1164. }
  1165. }
  1166. return false;
  1167. }
  1168. public final List<Integer> getParticipants(int oracle, int festivalId)
  1169. {
  1170. if (oracle == SevenSigns.CABAL_DAWN)
  1171. {
  1172. return _dawnFestivalParticipants.get(festivalId);
  1173. }
  1174. return _duskFestivalParticipants.get(festivalId);
  1175. }
  1176. public final List<Integer> getPreviousParticipants(int oracle, int festivalId)
  1177. {
  1178. if (oracle == SevenSigns.CABAL_DAWN)
  1179. {
  1180. return _dawnPreviousParticipants.get(festivalId);
  1181. }
  1182. return _duskPreviousParticipants.get(festivalId);
  1183. }
  1184. public void setParticipants(int oracle, int festivalId, L2Party festivalParty)
  1185. {
  1186. List<Integer> participants = null;
  1187. if (festivalParty != null)
  1188. {
  1189. participants = new ArrayList<>(festivalParty.getMemberCount());
  1190. for (L2PcInstance player : festivalParty.getMembers())
  1191. {
  1192. if (player == null)
  1193. {
  1194. continue;
  1195. }
  1196. participants.add(player.getObjectId());
  1197. }
  1198. }
  1199. if (oracle == SevenSigns.CABAL_DAWN)
  1200. {
  1201. _dawnFestivalParticipants.put(festivalId, participants);
  1202. }
  1203. else
  1204. {
  1205. _duskFestivalParticipants.put(festivalId, participants);
  1206. }
  1207. }
  1208. public void updateParticipants(L2PcInstance player, L2Party festivalParty)
  1209. {
  1210. if (!isParticipant(player))
  1211. {
  1212. return;
  1213. }
  1214. final int[] playerFestInfo = getFestivalForPlayer(player);
  1215. final int oracle = playerFestInfo[0];
  1216. final int festivalId = playerFestInfo[1];
  1217. if (festivalId > -1)
  1218. {
  1219. if (_festivalInitialized)
  1220. {
  1221. L2DarknessFestival festivalInst = _managerInstance.getFestivalInstance(oracle, festivalId);
  1222. if (festivalParty == null)
  1223. {
  1224. for (int partyMemberObjId : getParticipants(oracle, festivalId))
  1225. {
  1226. L2PcInstance partyMember = L2World.getInstance().getPlayer(partyMemberObjId);
  1227. if (partyMember == null)
  1228. {
  1229. continue;
  1230. }
  1231. festivalInst.relocatePlayer(partyMember, true);
  1232. }
  1233. }
  1234. else
  1235. {
  1236. festivalInst.relocatePlayer(player, true);
  1237. }
  1238. }
  1239. setParticipants(oracle, festivalId, festivalParty);
  1240. // Check on disconnect if min player in party
  1241. if ((festivalParty != null) && (festivalParty.getMemberCount() < Config.ALT_FESTIVAL_MIN_PLAYER))
  1242. {
  1243. updateParticipants(player, null); // under minimum count
  1244. festivalParty.removePartyMember(player, messageType.Expelled);
  1245. }
  1246. }
  1247. }
  1248. public final long getFinalScore(int oracle, int festivalId)
  1249. {
  1250. if (oracle == SevenSigns.CABAL_DAWN)
  1251. {
  1252. return _dawnFestivalScores.get(festivalId);
  1253. }
  1254. return _duskFestivalScores.get(festivalId);
  1255. }
  1256. public final int getHighestScore(int oracle, int festivalId)
  1257. {
  1258. return getHighestScoreData(oracle, festivalId).getInt("score");
  1259. }
  1260. /**
  1261. * Returns a stats set containing the highest score <b>this cycle</b> for the the specified cabal and associated festival ID.
  1262. * @param oracle
  1263. * @param festivalId
  1264. * @return StatsSet festivalDat
  1265. */
  1266. public final StatsSet getHighestScoreData(int oracle, int festivalId)
  1267. {
  1268. int offsetId = festivalId;
  1269. if (oracle == SevenSigns.CABAL_DAWN)
  1270. {
  1271. offsetId += 5;
  1272. }
  1273. // Attempt to retrieve existing score data (if found), otherwise create a
  1274. // new blank data set and display a console warning.
  1275. StatsSet currData = null;
  1276. try
  1277. {
  1278. currData = _festivalData.get(_signsCycle).get(offsetId);
  1279. }
  1280. catch (Exception e)
  1281. {
  1282. currData = new StatsSet();
  1283. currData.set("score", 0);
  1284. currData.set("members", "");
  1285. }
  1286. return currData;
  1287. }
  1288. /**
  1289. * Returns a stats set containing the highest ever recorded score data for the specified festival.
  1290. * @param festivalId
  1291. * @return StatsSet result
  1292. */
  1293. public final StatsSet getOverallHighestScoreData(int festivalId)
  1294. {
  1295. StatsSet result = null;
  1296. int highestScore = 0;
  1297. for (Map<Integer, StatsSet> currCycleData : _festivalData.values())
  1298. {
  1299. for (StatsSet currFestData : currCycleData.values())
  1300. {
  1301. int currFestID = currFestData.getInt("festivalId");
  1302. int festivalScore = currFestData.getInt("score");
  1303. if (currFestID != festivalId)
  1304. {
  1305. continue;
  1306. }
  1307. if (festivalScore > highestScore)
  1308. {
  1309. highestScore = festivalScore;
  1310. result = currFestData;
  1311. }
  1312. }
  1313. }
  1314. return result;
  1315. }
  1316. /**
  1317. * Set the final score details for the last participants of the specified festival data. Returns <b>true</b> if the score is higher than that previously recorded <b>this cycle</b>.
  1318. * @param player
  1319. * @param oracle
  1320. * @param festivalId
  1321. * @param offeringScore
  1322. * @return boolean isHighestScore
  1323. */
  1324. public boolean setFinalScore(L2PcInstance player, int oracle, int festivalId, long offeringScore)
  1325. {
  1326. List<String> partyMembers;
  1327. int currDawnHighScore = getHighestScore(SevenSigns.CABAL_DAWN, festivalId);
  1328. int currDuskHighScore = getHighestScore(SevenSigns.CABAL_DUSK, festivalId);
  1329. int thisCabalHighScore = 0;
  1330. int otherCabalHighScore = 0;
  1331. if (oracle == SevenSigns.CABAL_DAWN)
  1332. {
  1333. thisCabalHighScore = currDawnHighScore;
  1334. otherCabalHighScore = currDuskHighScore;
  1335. _dawnFestivalScores.put(festivalId, offeringScore);
  1336. }
  1337. else
  1338. {
  1339. thisCabalHighScore = currDuskHighScore;
  1340. otherCabalHighScore = currDawnHighScore;
  1341. _duskFestivalScores.put(festivalId, offeringScore);
  1342. }
  1343. StatsSet currFestData = getHighestScoreData(oracle, festivalId);
  1344. // Check if this is the highest score for this level range so far for the player's cabal.
  1345. if (offeringScore > thisCabalHighScore)
  1346. {
  1347. // If the current score is greater than that for the other cabal,
  1348. // then they already have the points from this festival.
  1349. if (thisCabalHighScore > otherCabalHighScore)
  1350. {
  1351. return false;
  1352. }
  1353. List<Integer> prevParticipants = getPreviousParticipants(oracle, festivalId);
  1354. partyMembers = new ArrayList<>(prevParticipants.size());
  1355. // Record a string list of the party members involved.
  1356. for (Integer partyMember : prevParticipants)
  1357. {
  1358. partyMembers.add(CharNameTable.getInstance().getNameById(partyMember));
  1359. }
  1360. // Update the highest scores and party list.
  1361. currFestData.set("date", String.valueOf(System.currentTimeMillis()));
  1362. currFestData.set("score", offeringScore);
  1363. currFestData.set("members", Util.implodeString(partyMembers, ","));
  1364. // Only add the score to the cabal's overall if it's higher than the other cabal's score.
  1365. if (offeringScore > otherCabalHighScore)
  1366. {
  1367. int contribPoints = FESTIVAL_LEVEL_SCORES[festivalId];
  1368. // Give this cabal the festival points, while deducting them from the other.
  1369. SevenSigns.getInstance().addFestivalScore(oracle, contribPoints);
  1370. }
  1371. saveFestivalData(true);
  1372. return true;
  1373. }
  1374. return false;
  1375. }
  1376. public final int getAccumulatedBonus(int festivalId)
  1377. {
  1378. return _accumulatedBonuses.get(festivalId);
  1379. }
  1380. public final int getTotalAccumulatedBonus()
  1381. {
  1382. int totalAccumBonus = 0;
  1383. for (int accumBonus : _accumulatedBonuses)
  1384. {
  1385. totalAccumBonus += accumBonus;
  1386. }
  1387. return totalAccumBonus;
  1388. }
  1389. public void addAccumulatedBonus(int festivalId, int stoneType, int stoneAmount)
  1390. {
  1391. int eachStoneBonus = 0;
  1392. switch (stoneType)
  1393. {
  1394. case SevenSigns.SEAL_STONE_BLUE_ID:
  1395. eachStoneBonus = SevenSigns.SEAL_STONE_BLUE_VALUE;
  1396. break;
  1397. case SevenSigns.SEAL_STONE_GREEN_ID:
  1398. eachStoneBonus = SevenSigns.SEAL_STONE_GREEN_VALUE;
  1399. break;
  1400. case SevenSigns.SEAL_STONE_RED_ID:
  1401. eachStoneBonus = SevenSigns.SEAL_STONE_RED_VALUE;
  1402. break;
  1403. }
  1404. int newTotalBonus = _accumulatedBonuses.get(festivalId) + (stoneAmount * eachStoneBonus);
  1405. _accumulatedBonuses.set(festivalId, newTotalBonus);
  1406. }
  1407. /**
  1408. * Calculate and return the proportion of the accumulated bonus for the festival where the player was in the winning party, if the winning party's cabal won the event. The accumulated bonus is then updated, with the player's share deducted.
  1409. * @param player
  1410. * @return playerBonus (the share of the bonus for the party)
  1411. */
  1412. public final int distribAccumulatedBonus(L2PcInstance player)
  1413. {
  1414. int playerBonus = 0;
  1415. String playerName = player.getName();
  1416. int playerCabal = SevenSigns.getInstance().getPlayerCabal(player.getObjectId());
  1417. if (playerCabal != SevenSigns.getInstance().getCabalHighestScore())
  1418. {
  1419. return 0;
  1420. }
  1421. final Map<Integer, StatsSet> festivalDataMap = _festivalData.get(_signsCycle);
  1422. if (festivalDataMap != null)
  1423. {
  1424. for (StatsSet festivalData : festivalDataMap.values())
  1425. {
  1426. if (festivalData.getString("members").indexOf(playerName) > -1)
  1427. {
  1428. int festivalId = festivalData.getInt("festivalId");
  1429. int numPartyMembers = festivalData.getString("members").split(",").length;
  1430. int totalAccumBonus = _accumulatedBonuses.get(festivalId);
  1431. playerBonus = totalAccumBonus / numPartyMembers;
  1432. _accumulatedBonuses.set(festivalId, totalAccumBonus - playerBonus);
  1433. break;
  1434. }
  1435. }
  1436. }
  1437. return playerBonus;
  1438. }
  1439. /**
  1440. * Used to send a "shout" message to all players currently present in an Oracle.<br>
  1441. * Primarily used for Festival Guide and Witch related speech.
  1442. * @param senderName
  1443. * @param npcString
  1444. */
  1445. public void sendMessageToAll(String senderName, NpcStringId npcString)
  1446. {
  1447. if ((_dawnChatGuide == null) || (_duskChatGuide == null))
  1448. {
  1449. return;
  1450. }
  1451. sendMessageToAll(senderName, npcString, _dawnChatGuide);
  1452. sendMessageToAll(senderName, npcString, _duskChatGuide);
  1453. }
  1454. /**
  1455. * @param senderName
  1456. * @param npcString
  1457. * @param npc
  1458. */
  1459. public void sendMessageToAll(String senderName, NpcStringId npcString, L2Npc npc)
  1460. {
  1461. CreatureSay cs = new CreatureSay(npc.getObjectId(), Say2.NPC_SHOUT, senderName, npcString);
  1462. if (npcString.getParamCount() == 1)
  1463. {
  1464. cs.addStringParameter(String.valueOf(getMinsToNextFestival()));
  1465. }
  1466. npc.broadcastPacket(cs);
  1467. }
  1468. /**
  1469. * Basically a wrapper-call to signal to increase the challenge of the specified festival.
  1470. * @param oracle
  1471. * @param festivalId
  1472. * @return boolean isChalIncreased
  1473. */
  1474. public final boolean increaseChallenge(int oracle, int festivalId)
  1475. {
  1476. L2DarknessFestival festivalInst = _managerInstance.getFestivalInstance(oracle, festivalId);
  1477. return festivalInst.increaseChallenge();
  1478. }
  1479. /**
  1480. * Used with the SpawnListener, to update the required "chat guide" instances, for use with announcements in the oracles.
  1481. * @param npc
  1482. */
  1483. @Override
  1484. public void npcSpawned(L2Npc npc)
  1485. {
  1486. if (npc == null)
  1487. {
  1488. return;
  1489. }
  1490. int npcId = npc.getId();
  1491. // If the spawned NPC ID matches the ones we need, assign their instances.
  1492. if (npcId == 31127)
  1493. {
  1494. _dawnChatGuide = npc;
  1495. }
  1496. if (npcId == 31137)
  1497. {
  1498. _duskChatGuide = npc;
  1499. }
  1500. }
  1501. /**
  1502. * The FestivalManager class is the main runner of all the festivals. It is used for easier integration and management of all running festivals.
  1503. * @author Tempy
  1504. */
  1505. private class FestivalManager implements Runnable
  1506. {
  1507. protected Map<Integer, L2DarknessFestival> _festivalInstances;
  1508. public FestivalManager()
  1509. {
  1510. _festivalInstances = new HashMap<>();
  1511. // Increment the cycle counter.
  1512. _festivalCycle++;
  1513. // Set the next start timers.
  1514. setNextCycleStart();
  1515. setNextFestivalStart(Config.ALT_FESTIVAL_CYCLE_LENGTH - FESTIVAL_SIGNUP_TIME);
  1516. }
  1517. @Override
  1518. public synchronized void run()
  1519. {
  1520. try
  1521. {
  1522. // The manager shouldn't be running if Seal Validation is in effect.
  1523. if (SevenSigns.getInstance().isSealValidationPeriod())
  1524. {
  1525. return;
  1526. }
  1527. // If the next period is due to start before the end of this
  1528. // festival cycle, then don't run it.
  1529. if (SevenSigns.getInstance().getMilliToPeriodChange() < Config.ALT_FESTIVAL_CYCLE_LENGTH)
  1530. {
  1531. return;
  1532. }
  1533. else if (getMinsToNextFestival() == 2)
  1534. {
  1535. sendMessageToAll("Festival Guide", NpcStringId.THE_MAIN_EVENT_WILL_START_IN_2_MINUTES_PLEASE_REGISTER_NOW);
  1536. }
  1537. // Stand by until the allowed signup period has elapsed.
  1538. try
  1539. {
  1540. wait(FESTIVAL_SIGNUP_TIME);
  1541. }
  1542. catch (InterruptedException e)
  1543. {
  1544. }
  1545. // Clear past participants, they can no longer register their score if not done so already.
  1546. _dawnPreviousParticipants.clear();
  1547. _duskPreviousParticipants.clear();
  1548. // Get rid of random monsters that avoided deletion after last festival
  1549. for (L2DarknessFestival festivalInst : _festivalInstances.values())
  1550. {
  1551. festivalInst.unspawnMobs();
  1552. }
  1553. // Start only if participants signed up
  1554. _noPartyRegister = true;
  1555. while (_noPartyRegister)
  1556. {
  1557. if ((_duskFestivalParticipants.isEmpty() && _dawnFestivalParticipants.isEmpty()))
  1558. {
  1559. try
  1560. {
  1561. setNextCycleStart();
  1562. setNextFestivalStart(Config.ALT_FESTIVAL_CYCLE_LENGTH - FESTIVAL_SIGNUP_TIME);
  1563. wait(Config.ALT_FESTIVAL_CYCLE_LENGTH - FESTIVAL_SIGNUP_TIME);
  1564. for (L2DarknessFestival festivalInst : _festivalInstances.values())
  1565. {
  1566. if (!festivalInst._npcInsts.isEmpty())
  1567. {
  1568. festivalInst.unspawnMobs();
  1569. }
  1570. }
  1571. }
  1572. catch (InterruptedException e)
  1573. {
  1574. }
  1575. }
  1576. else
  1577. {
  1578. _noPartyRegister = false;
  1579. }
  1580. }
  1581. /* INITIATION */
  1582. // Set the festival timer to 0, as it is just beginning.
  1583. long elapsedTime = 0;
  1584. // Create the instances for the festivals in both Oracles,
  1585. // but only if they have participants signed up for them.
  1586. for (int i = 0; i < FESTIVAL_COUNT; i++)
  1587. {
  1588. if (_duskFestivalParticipants.get(i) != null)
  1589. {
  1590. _festivalInstances.put(10 + i, new L2DarknessFestival(SevenSigns.CABAL_DUSK, i));
  1591. }
  1592. if (_dawnFestivalParticipants.get(i) != null)
  1593. {
  1594. _festivalInstances.put(20 + i, new L2DarknessFestival(SevenSigns.CABAL_DAWN, i));
  1595. }
  1596. }
  1597. // Prevent future signups while festival is in progress.
  1598. _festivalInitialized = true;
  1599. setNextFestivalStart(Config.ALT_FESTIVAL_CYCLE_LENGTH);
  1600. sendMessageToAll("Festival Guide", NpcStringId.THE_MAIN_EVENT_IS_NOW_STARTING);
  1601. // Stand by for a short length of time before starting the festival.
  1602. try
  1603. {
  1604. wait(Config.ALT_FESTIVAL_FIRST_SPAWN);
  1605. }
  1606. catch (InterruptedException e)
  1607. {
  1608. }
  1609. elapsedTime = Config.ALT_FESTIVAL_FIRST_SPAWN;
  1610. // Participants can now opt to increase the challenge, if desired.
  1611. _festivalInProgress = true;
  1612. /* PROPOGATION */
  1613. // Sequentially set all festivals to begin, spawn the Festival Witch and notify participants.
  1614. for (L2DarknessFestival festivalInst : _festivalInstances.values())
  1615. {
  1616. festivalInst.festivalStart();
  1617. festivalInst.sendMessageToParticipants(NpcStringId.THE_MAIN_EVENT_IS_NOW_STARTING);
  1618. }
  1619. // After a short time period, move all idle spawns to the center of the arena.
  1620. try
  1621. {
  1622. wait(Config.ALT_FESTIVAL_FIRST_SWARM - Config.ALT_FESTIVAL_FIRST_SPAWN);
  1623. }
  1624. catch (InterruptedException e)
  1625. {
  1626. }
  1627. elapsedTime += Config.ALT_FESTIVAL_FIRST_SWARM - Config.ALT_FESTIVAL_FIRST_SPAWN;
  1628. for (L2DarknessFestival festivalInst : _festivalInstances.values())
  1629. {
  1630. festivalInst.moveMonstersToCenter();
  1631. }
  1632. // Stand by until the time comes for the second spawn.
  1633. try
  1634. {
  1635. wait(Config.ALT_FESTIVAL_SECOND_SPAWN - Config.ALT_FESTIVAL_FIRST_SWARM);
  1636. }
  1637. catch (InterruptedException e)
  1638. {
  1639. }
  1640. // Spawn an extra set of monsters (archers) on the free platforms with
  1641. // a faster respawn when killed.
  1642. for (L2DarknessFestival festivalInst : _festivalInstances.values())
  1643. {
  1644. festivalInst.spawnFestivalMonsters(FESTIVAL_DEFAULT_RESPAWN / 2, 2);
  1645. long end = (Config.ALT_FESTIVAL_LENGTH - Config.ALT_FESTIVAL_SECOND_SPAWN) / 60000;
  1646. if (end == 2)
  1647. {
  1648. festivalInst.sendMessageToParticipants(NpcStringId.THE_FESTIVAL_OF_DARKNESS_WILL_END_IN_TWO_MINUTES);
  1649. }
  1650. else
  1651. {
  1652. festivalInst.sendMessageToParticipants("The Festival of Darkness will end in " + end + " minute(s).");
  1653. }
  1654. }
  1655. elapsedTime += Config.ALT_FESTIVAL_SECOND_SPAWN - Config.ALT_FESTIVAL_FIRST_SWARM;
  1656. // After another short time period, again move all idle spawns to the center of the arena.
  1657. try
  1658. {
  1659. wait(Config.ALT_FESTIVAL_SECOND_SWARM - Config.ALT_FESTIVAL_SECOND_SPAWN);
  1660. }
  1661. catch (InterruptedException e)
  1662. {
  1663. }
  1664. for (L2DarknessFestival festivalInst : _festivalInstances.values())
  1665. {
  1666. festivalInst.moveMonstersToCenter();
  1667. }
  1668. elapsedTime += Config.ALT_FESTIVAL_SECOND_SWARM - Config.ALT_FESTIVAL_SECOND_SPAWN;
  1669. // Stand by until the time comes for the chests to be spawned.
  1670. try
  1671. {
  1672. wait(Config.ALT_FESTIVAL_CHEST_SPAWN - Config.ALT_FESTIVAL_SECOND_SWARM);
  1673. }
  1674. catch (InterruptedException e)
  1675. {
  1676. }
  1677. // Spawn the festival chests, which enable the team to gain greater rewards
  1678. // for each chest they kill.
  1679. for (L2DarknessFestival festivalInst : _festivalInstances.values())
  1680. {
  1681. festivalInst.spawnFestivalMonsters(FESTIVAL_DEFAULT_RESPAWN, 3);
  1682. festivalInst.sendMessageToParticipants("The chests have spawned! Be quick, the festival will end soon."); // FIXME What is the correct npcString?
  1683. }
  1684. elapsedTime += Config.ALT_FESTIVAL_CHEST_SPAWN - Config.ALT_FESTIVAL_SECOND_SWARM;
  1685. // Stand by and wait until it's time to end the festival.
  1686. try
  1687. {
  1688. wait(Config.ALT_FESTIVAL_LENGTH - elapsedTime);
  1689. }
  1690. catch (InterruptedException e)
  1691. {
  1692. }
  1693. // Participants can no longer opt to increase the challenge, as the festival will soon close.
  1694. _festivalInProgress = false;
  1695. /* TERMINATION */
  1696. // Sequentially begin the ending sequence for all running festivals.
  1697. for (L2DarknessFestival festivalInst : _festivalInstances.values())
  1698. {
  1699. festivalInst.festivalEnd();
  1700. }
  1701. // Clear the participants list for the next round of signups.
  1702. _dawnFestivalParticipants.clear();
  1703. _duskFestivalParticipants.clear();
  1704. // Allow signups for the next festival cycle.
  1705. _festivalInitialized = false;
  1706. sendMessageToAll("Festival Witch", NpcStringId.THAT_WILL_DO_ILL_MOVE_YOU_TO_THE_OUTSIDE_SOON);
  1707. }
  1708. catch (Exception e)
  1709. {
  1710. _log.warning(e.getMessage());
  1711. }
  1712. }
  1713. /**
  1714. * Returns the running instance of a festival for the given Oracle and festivalID. <BR>
  1715. * A <B>null</B> value is returned if there are no participants in that festival.
  1716. * @param oracle
  1717. * @param festivalId
  1718. * @return L2DarknessFestival festivalInst
  1719. */
  1720. public final L2DarknessFestival getFestivalInstance(int oracle, int festivalId)
  1721. {
  1722. if (!isFestivalInitialized())
  1723. {
  1724. return null;
  1725. }
  1726. /*
  1727. * Compute the offset if a Dusk instance is required. ID: 0 1 2 3 4 Dusk 1:1011121314 Dawn 2:2021222324
  1728. */
  1729. festivalId += (oracle == SevenSigns.CABAL_DUSK) ? 10 : 20;
  1730. return _festivalInstances.get(festivalId);
  1731. }
  1732. }
  1733. /**
  1734. * Each running festival is represented by an L2DarknessFestival class. It contains all the spawn information and data for the running festival. All festivals are managed by the FestivalManager class, which must be initialized first.
  1735. * @author Tempy
  1736. */
  1737. private class L2DarknessFestival
  1738. {
  1739. protected final int _cabal;
  1740. protected final int _levelRange;
  1741. protected boolean _challengeIncreased;
  1742. private FestivalSpawn _startLocation;
  1743. private FestivalSpawn _witchSpawn;
  1744. private L2Npc _witchInst;
  1745. List<L2FestivalMonsterInstance> _npcInsts = new ArrayList<>();
  1746. private List<Integer> _participants;
  1747. private final Map<Integer, FestivalSpawn> _originalLocations = new ConcurrentHashMap<>();
  1748. protected L2DarknessFestival(int cabal, int levelRange)
  1749. {
  1750. _cabal = cabal;
  1751. _levelRange = levelRange;
  1752. if (cabal == SevenSigns.CABAL_DAWN)
  1753. {
  1754. _participants = _dawnFestivalParticipants.get(levelRange);
  1755. _witchSpawn = new FestivalSpawn(FESTIVAL_DAWN_WITCH_SPAWNS[levelRange]);
  1756. _startLocation = new FestivalSpawn(FESTIVAL_DAWN_PLAYER_SPAWNS[levelRange]);
  1757. }
  1758. else
  1759. {
  1760. _participants = _duskFestivalParticipants.get(levelRange);
  1761. _witchSpawn = new FestivalSpawn(FESTIVAL_DUSK_WITCH_SPAWNS[levelRange]);
  1762. _startLocation = new FestivalSpawn(FESTIVAL_DUSK_PLAYER_SPAWNS[levelRange]);
  1763. }
  1764. // FOR TESTING!
  1765. if (_participants == null)
  1766. {
  1767. _participants = new ArrayList<>();
  1768. }
  1769. festivalInit();
  1770. }
  1771. protected void festivalInit()
  1772. {
  1773. boolean isPositive;
  1774. // Teleport all players to arena and notify them.
  1775. if ((_participants != null) && !_participants.isEmpty())
  1776. {
  1777. try
  1778. {
  1779. for (int participantObjId : _participants)
  1780. {
  1781. L2PcInstance participant = L2World.getInstance().getPlayer(participantObjId);
  1782. if (participant == null)
  1783. {
  1784. continue;
  1785. }
  1786. _originalLocations.put(participantObjId, new FestivalSpawn(participant.getX(), participant.getY(), participant.getZ(), participant.getHeading()));
  1787. // Randomize the spawn point around the specific centerpoint for each player.
  1788. int x = _startLocation._x;
  1789. int y = _startLocation._y;
  1790. isPositive = (Rnd.nextInt(2) == 1);
  1791. if (isPositive)
  1792. {
  1793. x += Rnd.nextInt(FESTIVAL_MAX_OFFSET_X);
  1794. y += Rnd.nextInt(FESTIVAL_MAX_OFFSET_Y);
  1795. }
  1796. else
  1797. {
  1798. x -= Rnd.nextInt(FESTIVAL_MAX_OFFSET_X);
  1799. y -= Rnd.nextInt(FESTIVAL_MAX_OFFSET_Y);
  1800. }
  1801. participant.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
  1802. participant.teleToLocation(new Location(x, y, _startLocation._z), true);
  1803. // Remove all buffs from all participants on entry. Works like the skill Cancel.
  1804. participant.stopAllEffectsExceptThoseThatLastThroughDeath();
  1805. // Remove any stray blood offerings in inventory
  1806. L2ItemInstance bloodOfferings = participant.getInventory().getItemByItemId(FESTIVAL_OFFERING_ID);
  1807. if (bloodOfferings != null)
  1808. {
  1809. participant.destroyItem("SevenSigns", bloodOfferings, null, true);
  1810. }
  1811. }
  1812. }
  1813. catch (NullPointerException e)
  1814. {
  1815. // deleteMe handling should teleport party out in case of disconnect
  1816. }
  1817. }
  1818. // Spawn the festival witch for this arena
  1819. try
  1820. {
  1821. L2Spawn npcSpawn = new L2Spawn(_witchSpawn._npcId);
  1822. npcSpawn.setX(_witchSpawn._x);
  1823. npcSpawn.setY(_witchSpawn._y);
  1824. npcSpawn.setZ(_witchSpawn._z);
  1825. npcSpawn.setHeading(_witchSpawn._heading);
  1826. npcSpawn.setAmount(1);
  1827. npcSpawn.setRespawnDelay(1);
  1828. // Needed as doSpawn() is required to be called also for the NpcInstance it returns.
  1829. npcSpawn.startRespawn();
  1830. SpawnTable.getInstance().addNewSpawn(npcSpawn, false);
  1831. _witchInst = npcSpawn.doSpawn();
  1832. }
  1833. catch (Exception e)
  1834. {
  1835. _log.log(Level.WARNING, "SevenSignsFestival: Error while spawning Festival Witch ID " + _witchSpawn._npcId + ": " + e.getMessage(), e);
  1836. }
  1837. // Make it appear as though the Witch has apparated there.
  1838. MagicSkillUse msu = new MagicSkillUse(_witchInst, _witchInst, 2003, 1, 1, 0);
  1839. _witchInst.broadcastPacket(msu);
  1840. // And another one...:D
  1841. msu = new MagicSkillUse(_witchInst, _witchInst, 2133, 1, 1, 0);
  1842. _witchInst.broadcastPacket(msu);
  1843. // Send a message to all participants from the witch.
  1844. sendMessageToParticipants(NpcStringId.THE_MAIN_EVENT_WILL_START_IN_2_MINUTES_PLEASE_REGISTER_NOW);
  1845. }
  1846. protected void festivalStart()
  1847. {
  1848. spawnFestivalMonsters(FESTIVAL_DEFAULT_RESPAWN, 0);
  1849. }
  1850. protected void moveMonstersToCenter()
  1851. {
  1852. boolean isPositive;
  1853. for (L2FestivalMonsterInstance festivalMob : _npcInsts)
  1854. {
  1855. if (festivalMob.isDead())
  1856. {
  1857. continue;
  1858. }
  1859. // Only move monsters that are idle or doing their usual functions.
  1860. CtrlIntention currIntention = festivalMob.getAI().getIntention();
  1861. if ((currIntention != CtrlIntention.AI_INTENTION_IDLE) && (currIntention != CtrlIntention.AI_INTENTION_ACTIVE))
  1862. {
  1863. continue;
  1864. }
  1865. int x = _startLocation._x;
  1866. int y = _startLocation._y;
  1867. /*
  1868. * Random X and Y coords around the player start location, up to half of the maximum allowed offset are generated to prevent the mobs from all moving to the exact same place.
  1869. */
  1870. isPositive = (Rnd.nextInt(2) == 1);
  1871. if (isPositive)
  1872. {
  1873. x += Rnd.nextInt(FESTIVAL_MAX_OFFSET_X);
  1874. y += Rnd.nextInt(FESTIVAL_MAX_OFFSET_Y);
  1875. }
  1876. else
  1877. {
  1878. x -= Rnd.nextInt(FESTIVAL_MAX_OFFSET_X);
  1879. y -= Rnd.nextInt(FESTIVAL_MAX_OFFSET_Y);
  1880. }
  1881. festivalMob.setRunning();
  1882. festivalMob.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(x, y, _startLocation._z, Rnd.nextInt(65536)));
  1883. }
  1884. }
  1885. /**
  1886. * Used to spawn monsters unique to the festival. <BR>
  1887. * Valid SpawnTypes:<BR>
  1888. * 0 - All Primary Monsters (starting monsters) <BR>
  1889. * 1 - Same as 0, but without archers/marksmen. (used for challenge increase) <BR>
  1890. * 2 - Secondary Monsters (archers) <BR>
  1891. * 3 - Festival Chests
  1892. * @param respawnDelay
  1893. * @param spawnType
  1894. */
  1895. protected void spawnFestivalMonsters(int respawnDelay, int spawnType)
  1896. {
  1897. int[][] _npcSpawns = null;
  1898. switch (spawnType)
  1899. {
  1900. case 0:
  1901. case 1:
  1902. _npcSpawns = (_cabal == SevenSigns.CABAL_DAWN) ? FESTIVAL_DAWN_PRIMARY_SPAWNS[_levelRange] : FESTIVAL_DUSK_PRIMARY_SPAWNS[_levelRange];
  1903. break;
  1904. case 2:
  1905. _npcSpawns = (_cabal == SevenSigns.CABAL_DAWN) ? FESTIVAL_DAWN_SECONDARY_SPAWNS[_levelRange] : FESTIVAL_DUSK_SECONDARY_SPAWNS[_levelRange];
  1906. break;
  1907. case 3:
  1908. _npcSpawns = (_cabal == SevenSigns.CABAL_DAWN) ? FESTIVAL_DAWN_CHEST_SPAWNS[_levelRange] : FESTIVAL_DUSK_CHEST_SPAWNS[_levelRange];
  1909. break;
  1910. default:
  1911. return;
  1912. }
  1913. for (int[] _npcSpawn : _npcSpawns)
  1914. {
  1915. FestivalSpawn currSpawn = new FestivalSpawn(_npcSpawn);
  1916. // Only spawn archers/marksmen if specified to do so.
  1917. if ((spawnType == 1) && isFestivalArcher(currSpawn._npcId))
  1918. {
  1919. continue;
  1920. }
  1921. try
  1922. {
  1923. L2Spawn npcSpawn = new L2Spawn(currSpawn._npcId);
  1924. npcSpawn.setX(currSpawn._x);
  1925. npcSpawn.setY(currSpawn._y);
  1926. npcSpawn.setZ(currSpawn._z);
  1927. npcSpawn.setHeading(Rnd.nextInt(65536));
  1928. npcSpawn.setAmount(1);
  1929. npcSpawn.setRespawnDelay(respawnDelay);
  1930. // Needed as doSpawn() is required to be called also for the NpcInstance it returns.
  1931. npcSpawn.startRespawn();
  1932. SpawnTable.getInstance().addNewSpawn(npcSpawn, false);
  1933. L2FestivalMonsterInstance festivalMob = (L2FestivalMonsterInstance) npcSpawn.doSpawn();
  1934. // Set the offering bonus to 2x or 5x the amount per kill,
  1935. // if this spawn is part of an increased challenge or is a festival chest.
  1936. if (spawnType == 1)
  1937. {
  1938. festivalMob.setOfferingBonus(2);
  1939. }
  1940. else if (spawnType == 3)
  1941. {
  1942. festivalMob.setOfferingBonus(5);
  1943. }
  1944. _npcInsts.add(festivalMob);
  1945. }
  1946. catch (Exception e)
  1947. {
  1948. _log.log(Level.WARNING, "SevenSignsFestival: Error while spawning NPC ID " + currSpawn._npcId + ": " + e.getMessage(), e);
  1949. }
  1950. }
  1951. }
  1952. protected boolean increaseChallenge()
  1953. {
  1954. if (_challengeIncreased)
  1955. {
  1956. return false;
  1957. }
  1958. // Set this flag to true to make sure that this can only be done once.
  1959. _challengeIncreased = true;
  1960. // Spawn more festival monsters, but this time with a twist.
  1961. spawnFestivalMonsters(FESTIVAL_DEFAULT_RESPAWN, 1);
  1962. return true;
  1963. }
  1964. public void sendMessageToParticipants(NpcStringId npcStringId)
  1965. {
  1966. if ((_participants != null) && !_participants.isEmpty())
  1967. {
  1968. _witchInst.broadcastPacket(new CreatureSay(_witchInst.getObjectId(), Say2.NPC_ALL, "Festival Witch", npcStringId));
  1969. }
  1970. }
  1971. public void sendMessageToParticipants(String npcString)
  1972. {
  1973. if ((_participants != null) && !_participants.isEmpty())
  1974. {
  1975. _witchInst.broadcastPacket(new CreatureSay(_witchInst.getObjectId(), Say2.NPC_ALL, "Festival Witch", npcString));
  1976. }
  1977. }
  1978. protected void festivalEnd()
  1979. {
  1980. if ((_participants != null) && !_participants.isEmpty())
  1981. {
  1982. for (int participantObjId : _participants)
  1983. {
  1984. try
  1985. {
  1986. L2PcInstance participant = L2World.getInstance().getPlayer(participantObjId);
  1987. if (participant == null)
  1988. {
  1989. continue;
  1990. }
  1991. relocatePlayer(participant, false);
  1992. participant.sendMessage("The festival has ended. Your party leader must now register your score before the next festival takes place.");
  1993. }
  1994. catch (NullPointerException e)
  1995. {
  1996. }
  1997. }
  1998. if (_cabal == SevenSigns.CABAL_DAWN)
  1999. {
  2000. _dawnPreviousParticipants.put(_levelRange, _participants);
  2001. }
  2002. else
  2003. {
  2004. _duskPreviousParticipants.put(_levelRange, _participants);
  2005. }
  2006. }
  2007. _participants = null;
  2008. unspawnMobs();
  2009. }
  2010. protected void unspawnMobs()
  2011. {
  2012. // Delete all the NPCs in the current festival arena.
  2013. if (_witchInst != null)
  2014. {
  2015. _witchInst.getSpawn().stopRespawn();
  2016. _witchInst.deleteMe();
  2017. SpawnTable.getInstance().deleteSpawn(_witchInst.getSpawn(), false);
  2018. }
  2019. for (L2FestivalMonsterInstance monsterInst : _npcInsts)
  2020. {
  2021. if (monsterInst != null)
  2022. {
  2023. monsterInst.getSpawn().stopRespawn();
  2024. monsterInst.deleteMe();
  2025. SpawnTable.getInstance().deleteSpawn(monsterInst.getSpawn(), false);
  2026. }
  2027. }
  2028. }
  2029. public void relocatePlayer(L2PcInstance participant, boolean isRemoving)
  2030. {
  2031. try
  2032. {
  2033. FestivalSpawn origPosition = _originalLocations.get(participant.getObjectId());
  2034. if (isRemoving)
  2035. {
  2036. _originalLocations.remove(participant.getObjectId());
  2037. }
  2038. participant.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
  2039. participant.teleToLocation(new Location(origPosition._x, origPosition._y, origPosition._z), true);
  2040. participant.sendMessage("You have been removed from the festival arena.");
  2041. }
  2042. catch (Exception e)
  2043. {
  2044. // If an exception occurs, just move the player to the nearest town.
  2045. try
  2046. {
  2047. participant.teleToLocation(TeleportWhereType.TOWN);
  2048. participant.sendMessage("You have been removed from the festival arena.");
  2049. }
  2050. catch (NullPointerException e2)
  2051. {
  2052. }
  2053. }
  2054. }
  2055. }
  2056. private static class FestivalSpawn
  2057. {
  2058. protected final int _x;
  2059. protected final int _y;
  2060. protected final int _z;
  2061. protected final int _heading;
  2062. protected final int _npcId;
  2063. protected FestivalSpawn(int x, int y, int z, int heading)
  2064. {
  2065. _x = x;
  2066. _y = y;
  2067. _z = z;
  2068. // Generate a random heading if no positive one given.
  2069. _heading = (heading < 0) ? Rnd.nextInt(65536) : heading;
  2070. _npcId = -1;
  2071. }
  2072. protected FestivalSpawn(int[] spawnData)
  2073. {
  2074. _x = spawnData[0];
  2075. _y = spawnData[1];
  2076. _z = spawnData[2];
  2077. _heading = (spawnData[3] < 0) ? Rnd.nextInt(65536) : spawnData[3];
  2078. if (spawnData.length > 4)
  2079. {
  2080. _npcId = spawnData[4];
  2081. }
  2082. else
  2083. {
  2084. _npcId = -1;
  2085. }
  2086. }
  2087. }
  2088. private static class SingletonHolder
  2089. {
  2090. protected static final SevenSignsFestival _instance = new SevenSignsFestival();
  2091. }
  2092. }