SevenSignsFestival.java 74 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477
  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.List;
  27. import java.util.Map;
  28. import java.util.concurrent.ScheduledFuture;
  29. import java.util.logging.Level;
  30. import java.util.logging.Logger;
  31. import javolution.util.FastList;
  32. import javolution.util.FastMap;
  33. import com.l2jserver.Config;
  34. import com.l2jserver.L2DatabaseFactory;
  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; // 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;
  665. protected Map<Integer, List<Integer>> _duskFestivalParticipants;
  666. protected Map<Integer, List<Integer>> _dawnPreviousParticipants;
  667. protected Map<Integer, List<Integer>> _duskPreviousParticipants;
  668. private Map<Integer, Long> _dawnFestivalScores;
  669. private Map<Integer, Long> _duskFestivalScores;
  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 Map<Integer, Map<Integer, StatsSet>> _festivalData;
  675. protected SevenSignsFestival()
  676. {
  677. _accumulatedBonuses = new FastList<>();
  678. _dawnFestivalParticipants = new FastMap<>();
  679. _dawnPreviousParticipants = new FastMap<>();
  680. _dawnFestivalScores = new FastMap<>();
  681. _duskFestivalParticipants = new FastMap<>();
  682. _duskPreviousParticipants = new FastMap<>();
  683. _duskFestivalScores = new FastMap<>();
  684. _festivalData = new FastMap<>();
  685. restoreFestivalData();
  686. if (SevenSigns.getInstance().isSealValidationPeriod())
  687. {
  688. _log.info("SevenSignsFestival: Initialization bypassed due to Seal Validation in effect.");
  689. return;
  690. }
  691. L2Spawn.addSpawnListener(this);
  692. startFestivalManager();
  693. }
  694. public static SevenSignsFestival getInstance()
  695. {
  696. return SingletonHolder._instance;
  697. }
  698. /**
  699. * Returns the associated name (level range) to a given festival ID.
  700. * @param festivalID
  701. * @return String festivalName
  702. */
  703. public static final String getFestivalName(int festivalID)
  704. {
  705. String festivalName;
  706. switch (festivalID)
  707. {
  708. case FESTIVAL_LEVEL_MAX_31:
  709. festivalName = "Level 31 or lower";
  710. break;
  711. case FESTIVAL_LEVEL_MAX_42:
  712. festivalName = "Level 42 or lower";
  713. break;
  714. case FESTIVAL_LEVEL_MAX_53:
  715. festivalName = "Level 53 or lower";
  716. break;
  717. case FESTIVAL_LEVEL_MAX_64:
  718. festivalName = "Level 64 or lower";
  719. break;
  720. default:
  721. festivalName = "No Level Limit";
  722. break;
  723. }
  724. return festivalName;
  725. }
  726. /**
  727. * Returns the maximum allowed player level for the given festival type.
  728. * @param festivalId
  729. * @return int maxLevel
  730. */
  731. public static final int getMaxLevelForFestival(int festivalId)
  732. {
  733. int maxLevel = (ExperienceData.getInstance().getMaxLevel() - 1);
  734. switch (festivalId)
  735. {
  736. case SevenSignsFestival.FESTIVAL_LEVEL_MAX_31:
  737. maxLevel = 31;
  738. break;
  739. case SevenSignsFestival.FESTIVAL_LEVEL_MAX_42:
  740. maxLevel = 42;
  741. break;
  742. case SevenSignsFestival.FESTIVAL_LEVEL_MAX_53:
  743. maxLevel = 53;
  744. break;
  745. case SevenSignsFestival.FESTIVAL_LEVEL_MAX_64:
  746. maxLevel = 64;
  747. break;
  748. }
  749. return maxLevel;
  750. }
  751. /**
  752. * Returns true if the monster ID given is of an archer/marksman type.
  753. * @param npcId
  754. * @return boolean isArcher
  755. */
  756. protected static final boolean isFestivalArcher(int npcId)
  757. {
  758. if ((npcId < 18009) || (npcId > 18108))
  759. {
  760. return false;
  761. }
  762. int identifier = npcId % 10;
  763. return ((identifier == 4) || (identifier == 9));
  764. }
  765. /**
  766. * Returns true if the monster ID given is a festival chest.
  767. * @param npcId
  768. * @return boolean isChest
  769. */
  770. protected static final boolean isFestivalChest(int npcId)
  771. {
  772. return ((npcId < 18109) || (npcId > 18118));
  773. }
  774. /**
  775. * Primarily used to terminate the Festival Manager, when the Seven Signs period changes.
  776. * @return ScheduledFuture festManagerScheduler
  777. */
  778. protected final ScheduledFuture<?> getFestivalManagerSchedule()
  779. {
  780. if (_managerScheduledTask == null)
  781. {
  782. startFestivalManager();
  783. }
  784. return _managerScheduledTask;
  785. }
  786. /**
  787. * Used to start the Festival Manager, if the current period is not Seal Validation.
  788. */
  789. protected void startFestivalManager()
  790. {
  791. // Start the Festival Manager for the first time after the server has started
  792. // at the specified time, then invoke it automatically after every cycle.
  793. _managerInstance = new FestivalManager();
  794. setNextFestivalStart(Config.ALT_FESTIVAL_MANAGER_START + FESTIVAL_SIGNUP_TIME);
  795. _managerScheduledTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(_managerInstance, Config.ALT_FESTIVAL_MANAGER_START, Config.ALT_FESTIVAL_CYCLE_LENGTH);
  796. _log.info("SevenSignsFestival: The first Festival of Darkness cycle begins in " + (Config.ALT_FESTIVAL_MANAGER_START / 60000) + " minute(s).");
  797. }
  798. /**
  799. * Restores saved festival data, basic settings from the properties file and past high score data from the database.
  800. */
  801. protected void restoreFestivalData()
  802. {
  803. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  804. Statement s = con.createStatement();
  805. ResultSet rs = s.executeQuery("SELECT festivalId, cabal, cycle, date, score, members " + "FROM seven_signs_festival"))
  806. {
  807. while (rs.next())
  808. {
  809. int festivalCycle = rs.getInt("cycle");
  810. int festivalId = rs.getInt("festivalId");
  811. String cabal = rs.getString("cabal");
  812. StatsSet festivalDat = new StatsSet();
  813. festivalDat.set("festivalId", festivalId);
  814. festivalDat.set("cabal", cabal);
  815. festivalDat.set("cycle", festivalCycle);
  816. festivalDat.set("date", rs.getString("date"));
  817. festivalDat.set("score", rs.getInt("score"));
  818. festivalDat.set("members", rs.getString("members"));
  819. if (cabal.equals("dawn"))
  820. {
  821. festivalId += FESTIVAL_COUNT;
  822. }
  823. Map<Integer, StatsSet> tempData = _festivalData.get(festivalCycle);
  824. if (tempData == null)
  825. {
  826. tempData = new FastMap<>();
  827. }
  828. tempData.put(festivalId, festivalDat);
  829. _festivalData.put(festivalCycle, tempData);
  830. }
  831. }
  832. catch (SQLException e)
  833. {
  834. _log.log(Level.SEVERE, "SevenSignsFestival: Failed to load configuration: " + e.getMessage(), e);
  835. }
  836. StringBuilder query = new StringBuilder();
  837. query.append("SELECT festival_cycle, ");
  838. for (int i = 0; i < (FESTIVAL_COUNT - 1); i++)
  839. {
  840. query.append("accumulated_bonus");
  841. query.append(String.valueOf(i));
  842. query.append(", ");
  843. }
  844. query.append("accumulated_bonus");
  845. query.append(String.valueOf(FESTIVAL_COUNT - 1));
  846. query.append(' ');
  847. query.append("FROM seven_signs_status WHERE id=0");
  848. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  849. Statement s = con.createStatement();
  850. ResultSet rs = s.executeQuery(query.toString()))
  851. {
  852. while (rs.next())
  853. {
  854. _festivalCycle = rs.getInt("festival_cycle");
  855. for (int i = 0; i < FESTIVAL_COUNT; i++)
  856. {
  857. _accumulatedBonuses.add(i, rs.getInt("accumulated_bonus" + String.valueOf(i)));
  858. }
  859. }
  860. }
  861. catch (SQLException e)
  862. {
  863. _log.log(Level.SEVERE, "SevenSignsFestival: Failed to load configuration: " + e.getMessage(), e);
  864. }
  865. }
  866. /**
  867. * 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.
  868. * @param updateSettings
  869. */
  870. public void saveFestivalData(boolean updateSettings)
  871. {
  872. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  873. PreparedStatement psUpdate = con.prepareStatement("UPDATE seven_signs_festival SET date=?, score=?, members=? WHERE cycle=? AND cabal=? AND festivalId=?");
  874. PreparedStatement psInsert = con.prepareStatement("INSERT INTO seven_signs_festival (festivalId, cabal, cycle, date, score, members) VALUES (?,?,?,?,?,?)"))
  875. {
  876. for (Map<Integer, StatsSet> currCycleData : _festivalData.values())
  877. {
  878. for (StatsSet festivalDat : currCycleData.values())
  879. {
  880. int festivalCycle = festivalDat.getInt("cycle");
  881. int festivalId = festivalDat.getInt("festivalId");
  882. String cabal = festivalDat.getString("cabal");
  883. // Try to update an existing record.
  884. psUpdate.setLong(1, Long.valueOf(festivalDat.getString("date")));
  885. psUpdate.setInt(2, festivalDat.getInt("score"));
  886. psUpdate.setString(3, festivalDat.getString("members"));
  887. psUpdate.setInt(4, festivalCycle);
  888. psUpdate.setString(5, cabal);
  889. psUpdate.setInt(6, festivalId);
  890. // If there was no record to update, assume it doesn't exist and add a new one,
  891. // otherwise continue with the next record to store.
  892. if (psUpdate.executeUpdate() > 0)
  893. {
  894. continue;
  895. }
  896. psInsert.setInt(1, festivalId);
  897. psInsert.setString(2, cabal);
  898. psInsert.setInt(3, festivalCycle);
  899. psInsert.setLong(4, Long.valueOf(festivalDat.getString("date")));
  900. psInsert.setInt(5, festivalDat.getInt("score"));
  901. psInsert.setString(6, festivalDat.getString("members"));
  902. psInsert.execute();
  903. psInsert.clearParameters();
  904. }
  905. }
  906. }
  907. catch (SQLException e)
  908. {
  909. _log.log(Level.SEVERE, "SevenSignsFestival: Failed to save configuration: " + e.getMessage(), e);
  910. }
  911. // Updates Seven Signs DB data also, so call only if really necessary.
  912. if (updateSettings)
  913. {
  914. SevenSigns.getInstance().saveSevenSignsStatus();
  915. }
  916. }
  917. /**
  918. * If a clan member is a member of the highest-ranked party in the Festival of Darkness, 100 points are added per member
  919. */
  920. protected void rewardHighestRanked()
  921. {
  922. String[] partyMembers;
  923. StatsSet overallData = getOverallHighestScoreData(FESTIVAL_LEVEL_MAX_31);
  924. if (overallData != null)
  925. {
  926. partyMembers = overallData.getString("members").split(",");
  927. for (String partyMemberName : partyMembers)
  928. {
  929. addReputationPointsForPartyMemberClan(partyMemberName);
  930. }
  931. }
  932. overallData = getOverallHighestScoreData(FESTIVAL_LEVEL_MAX_42);
  933. if (overallData != null)
  934. {
  935. partyMembers = overallData.getString("members").split(",");
  936. for (String partyMemberName : partyMembers)
  937. {
  938. addReputationPointsForPartyMemberClan(partyMemberName);
  939. }
  940. }
  941. overallData = getOverallHighestScoreData(FESTIVAL_LEVEL_MAX_53);
  942. if (overallData != null)
  943. {
  944. partyMembers = overallData.getString("members").split(",");
  945. for (String partyMemberName : partyMembers)
  946. {
  947. addReputationPointsForPartyMemberClan(partyMemberName);
  948. }
  949. }
  950. overallData = getOverallHighestScoreData(FESTIVAL_LEVEL_MAX_64);
  951. if (overallData != null)
  952. {
  953. partyMembers = overallData.getString("members").split(",");
  954. for (String partyMemberName : partyMembers)
  955. {
  956. addReputationPointsForPartyMemberClan(partyMemberName);
  957. }
  958. }
  959. overallData = getOverallHighestScoreData(FESTIVAL_LEVEL_MAX_NONE);
  960. if (overallData != null)
  961. {
  962. partyMembers = overallData.getString("members").split(",");
  963. for (String partyMemberName : partyMembers)
  964. {
  965. addReputationPointsForPartyMemberClan(partyMemberName);
  966. }
  967. }
  968. }
  969. private void addReputationPointsForPartyMemberClan(String partyMemberName)
  970. {
  971. L2PcInstance player = L2World.getInstance().getPlayer(partyMemberName);
  972. if (player != null)
  973. {
  974. if (player.getClan() != null)
  975. {
  976. player.getClan().addReputationScore(Config.FESTIVAL_WIN_POINTS, true);
  977. SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.CLAN_MEMBER_C1_WAS_IN_HIGHEST_RANKED_PARTY_IN_FESTIVAL_OF_DARKNESS_AND_GAINED_S2_REPUTATION);
  978. sm.addString(partyMemberName);
  979. sm.addInt(Config.FESTIVAL_WIN_POINTS);
  980. player.getClan().broadcastToOnlineMembers(sm);
  981. }
  982. }
  983. else
  984. {
  985. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  986. PreparedStatement ps = con.prepareStatement(GET_CLAN_NAME))
  987. {
  988. ps.setString(1, partyMemberName);
  989. try (ResultSet rs = ps.executeQuery())
  990. {
  991. if (rs.next())
  992. {
  993. String clanName = rs.getString("clan_name");
  994. if (clanName != null)
  995. {
  996. L2Clan clan = ClanTable.getInstance().getClanByName(clanName);
  997. if (clan != null)
  998. {
  999. clan.addReputationScore(Config.FESTIVAL_WIN_POINTS, true);
  1000. SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.CLAN_MEMBER_C1_WAS_IN_HIGHEST_RANKED_PARTY_IN_FESTIVAL_OF_DARKNESS_AND_GAINED_S2_REPUTATION);
  1001. sm.addString(partyMemberName);
  1002. sm.addInt(Config.FESTIVAL_WIN_POINTS);
  1003. clan.broadcastToOnlineMembers(sm);
  1004. }
  1005. }
  1006. }
  1007. }
  1008. }
  1009. catch (Exception e)
  1010. {
  1011. _log.log(Level.WARNING, "Could not get clan name of " + partyMemberName + ": " + e.getMessage(), e);
  1012. }
  1013. }
  1014. }
  1015. /**
  1016. * Used to reset all festival data at the beginning of a new quest event period.
  1017. * @param updateSettings
  1018. */
  1019. protected void resetFestivalData(boolean updateSettings)
  1020. {
  1021. _festivalCycle = 0;
  1022. _signsCycle = SevenSigns.getInstance().getCurrentCycle();
  1023. // Set all accumulated bonuses back to 0.
  1024. for (int i = 0; i < FESTIVAL_COUNT; i++)
  1025. {
  1026. _accumulatedBonuses.set(i, 0);
  1027. }
  1028. _dawnFestivalParticipants.clear();
  1029. _dawnPreviousParticipants.clear();
  1030. _dawnFestivalScores.clear();
  1031. _duskFestivalParticipants.clear();
  1032. _duskPreviousParticipants.clear();
  1033. _duskFestivalScores.clear();
  1034. // Set up a new data set for the current cycle of festivals
  1035. Map<Integer, StatsSet> newData = new FastMap<>();
  1036. for (int i = 0; i < (FESTIVAL_COUNT * 2); i++)
  1037. {
  1038. int festivalId = i;
  1039. if (i >= FESTIVAL_COUNT)
  1040. {
  1041. festivalId -= FESTIVAL_COUNT;
  1042. }
  1043. // Create a new StatsSet with "default" data for Dusk
  1044. StatsSet tempStats = new StatsSet();
  1045. tempStats.set("festivalId", festivalId);
  1046. tempStats.set("cycle", _signsCycle);
  1047. tempStats.set("date", "0");
  1048. tempStats.set("score", 0);
  1049. tempStats.set("members", "");
  1050. if (i >= FESTIVAL_COUNT)
  1051. {
  1052. tempStats.set("cabal", SevenSigns.getCabalShortName(SevenSigns.CABAL_DAWN));
  1053. }
  1054. else
  1055. {
  1056. tempStats.set("cabal", SevenSigns.getCabalShortName(SevenSigns.CABAL_DUSK));
  1057. }
  1058. newData.put(i, tempStats);
  1059. }
  1060. // Add the newly created cycle data to the existing festival data, and
  1061. // subsequently save it to the database.
  1062. _festivalData.put(_signsCycle, newData);
  1063. saveFestivalData(updateSettings);
  1064. // Remove any unused blood offerings from online players.
  1065. for (L2PcInstance player : L2World.getInstance().getPlayers())
  1066. {
  1067. final L2ItemInstance bloodOfferings = player.getInventory().getItemByItemId(FESTIVAL_OFFERING_ID);
  1068. if (bloodOfferings != null)
  1069. {
  1070. player.destroyItem("SevenSigns", bloodOfferings, null, false);
  1071. }
  1072. }
  1073. _log.info("SevenSignsFestival: Reinitialized engine for next competition period.");
  1074. }
  1075. public final int getCurrentFestivalCycle()
  1076. {
  1077. return _festivalCycle;
  1078. }
  1079. public final boolean isFestivalInitialized()
  1080. {
  1081. return _festivalInitialized;
  1082. }
  1083. public final boolean isFestivalInProgress()
  1084. {
  1085. return _festivalInProgress;
  1086. }
  1087. public void setNextCycleStart()
  1088. {
  1089. _nextFestivalCycleStart = System.currentTimeMillis() + Config.ALT_FESTIVAL_CYCLE_LENGTH;
  1090. }
  1091. public void setNextFestivalStart(long milliFromNow)
  1092. {
  1093. _nextFestivalStart = System.currentTimeMillis() + milliFromNow;
  1094. }
  1095. public final long getMinsToNextCycle()
  1096. {
  1097. if (SevenSigns.getInstance().isSealValidationPeriod())
  1098. {
  1099. return -1;
  1100. }
  1101. return (_nextFestivalCycleStart - System.currentTimeMillis()) / 60000;
  1102. }
  1103. public final int getMinsToNextFestival()
  1104. {
  1105. if (SevenSigns.getInstance().isSealValidationPeriod())
  1106. {
  1107. return -1;
  1108. }
  1109. return (int) (((_nextFestivalStart - System.currentTimeMillis()) / 60000) + 1);
  1110. }
  1111. public final String getTimeToNextFestivalStr()
  1112. {
  1113. if (SevenSigns.getInstance().isSealValidationPeriod())
  1114. {
  1115. return "<font color=\"FF0000\">This is the Seal Validation period. Festivals will resume next week.</font>";
  1116. }
  1117. return "<font color=\"FF0000\">The next festival will begin in " + getMinsToNextFestival() + " minute(s).</font>";
  1118. }
  1119. /**
  1120. * 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.
  1121. * @param player
  1122. * @return int[] playerFestivalInfo
  1123. */
  1124. public final int[] getFestivalForPlayer(L2PcInstance player)
  1125. {
  1126. int[] playerFestivalInfo =
  1127. {
  1128. -1,
  1129. -1
  1130. };
  1131. int festivalId = 0;
  1132. while (festivalId < FESTIVAL_COUNT)
  1133. {
  1134. List<Integer> participants = _dawnFestivalParticipants.get(festivalId);
  1135. // If there are no participants in this festival, move on to the next.
  1136. if ((participants != null) && participants.contains(player.getObjectId()))
  1137. {
  1138. playerFestivalInfo[0] = SevenSigns.CABAL_DAWN;
  1139. playerFestivalInfo[1] = festivalId;
  1140. return playerFestivalInfo;
  1141. }
  1142. participants = _duskFestivalParticipants.get(++festivalId);
  1143. if ((participants != null) && participants.contains(player.getObjectId()))
  1144. {
  1145. playerFestivalInfo[0] = SevenSigns.CABAL_DUSK;
  1146. playerFestivalInfo[1] = festivalId;
  1147. return playerFestivalInfo;
  1148. }
  1149. festivalId++;
  1150. }
  1151. // Return default data if the player is not found as a participant.
  1152. return playerFestivalInfo;
  1153. }
  1154. public final boolean isParticipant(L2PcInstance player)
  1155. {
  1156. if (SevenSigns.getInstance().isSealValidationPeriod())
  1157. {
  1158. return false;
  1159. }
  1160. if (_managerInstance == null)
  1161. {
  1162. return false;
  1163. }
  1164. for (List<Integer> participants : _dawnFestivalParticipants.values())
  1165. {
  1166. if ((participants != null) && participants.contains(player.getObjectId()))
  1167. {
  1168. return true;
  1169. }
  1170. }
  1171. for (List<Integer> participants : _duskFestivalParticipants.values())
  1172. {
  1173. if ((participants != null) && participants.contains(player.getObjectId()))
  1174. {
  1175. return true;
  1176. }
  1177. }
  1178. return false;
  1179. }
  1180. public final List<Integer> getParticipants(int oracle, int festivalId)
  1181. {
  1182. if (oracle == SevenSigns.CABAL_DAWN)
  1183. {
  1184. return _dawnFestivalParticipants.get(festivalId);
  1185. }
  1186. return _duskFestivalParticipants.get(festivalId);
  1187. }
  1188. public final List<Integer> getPreviousParticipants(int oracle, int festivalId)
  1189. {
  1190. if (oracle == SevenSigns.CABAL_DAWN)
  1191. {
  1192. return _dawnPreviousParticipants.get(festivalId);
  1193. }
  1194. return _duskPreviousParticipants.get(festivalId);
  1195. }
  1196. public void setParticipants(int oracle, int festivalId, L2Party festivalParty)
  1197. {
  1198. List<Integer> participants = null;
  1199. if (festivalParty != null)
  1200. {
  1201. participants = new ArrayList<>(festivalParty.getMemberCount());
  1202. for (L2PcInstance player : festivalParty.getMembers())
  1203. {
  1204. if (player == null)
  1205. {
  1206. continue;
  1207. }
  1208. participants.add(player.getObjectId());
  1209. }
  1210. }
  1211. if (oracle == SevenSigns.CABAL_DAWN)
  1212. {
  1213. _dawnFestivalParticipants.put(festivalId, participants);
  1214. }
  1215. else
  1216. {
  1217. _duskFestivalParticipants.put(festivalId, participants);
  1218. }
  1219. }
  1220. public void updateParticipants(L2PcInstance player, L2Party festivalParty)
  1221. {
  1222. if (!isParticipant(player))
  1223. {
  1224. return;
  1225. }
  1226. final int[] playerFestInfo = getFestivalForPlayer(player);
  1227. final int oracle = playerFestInfo[0];
  1228. final int festivalId = playerFestInfo[1];
  1229. if (festivalId > -1)
  1230. {
  1231. if (_festivalInitialized)
  1232. {
  1233. L2DarknessFestival festivalInst = _managerInstance.getFestivalInstance(oracle, festivalId);
  1234. if (festivalParty == null)
  1235. {
  1236. for (int partyMemberObjId : getParticipants(oracle, festivalId))
  1237. {
  1238. L2PcInstance partyMember = L2World.getInstance().getPlayer(partyMemberObjId);
  1239. if (partyMember == null)
  1240. {
  1241. continue;
  1242. }
  1243. festivalInst.relocatePlayer(partyMember, true);
  1244. }
  1245. }
  1246. else
  1247. {
  1248. festivalInst.relocatePlayer(player, true);
  1249. }
  1250. }
  1251. setParticipants(oracle, festivalId, festivalParty);
  1252. // Check on disconnect if min player in party
  1253. if ((festivalParty != null) && (festivalParty.getMemberCount() < Config.ALT_FESTIVAL_MIN_PLAYER))
  1254. {
  1255. updateParticipants(player, null); // under minimum count
  1256. festivalParty.removePartyMember(player, messageType.Expelled);
  1257. }
  1258. }
  1259. }
  1260. public final long getFinalScore(int oracle, int festivalId)
  1261. {
  1262. if (oracle == SevenSigns.CABAL_DAWN)
  1263. {
  1264. return _dawnFestivalScores.get(festivalId);
  1265. }
  1266. return _duskFestivalScores.get(festivalId);
  1267. }
  1268. public final int getHighestScore(int oracle, int festivalId)
  1269. {
  1270. return getHighestScoreData(oracle, festivalId).getInt("score");
  1271. }
  1272. /**
  1273. * Returns a stats set containing the highest score <b>this cycle</b> for the the specified cabal and associated festival ID.
  1274. * @param oracle
  1275. * @param festivalId
  1276. * @return StatsSet festivalDat
  1277. */
  1278. public final StatsSet getHighestScoreData(int oracle, int festivalId)
  1279. {
  1280. int offsetId = festivalId;
  1281. if (oracle == SevenSigns.CABAL_DAWN)
  1282. {
  1283. offsetId += 5;
  1284. }
  1285. // Attempt to retrieve existing score data (if found), otherwise create a
  1286. // new blank data set and display a console warning.
  1287. StatsSet currData = null;
  1288. try
  1289. {
  1290. currData = _festivalData.get(_signsCycle).get(offsetId);
  1291. }
  1292. catch (Exception e)
  1293. {
  1294. currData = new StatsSet();
  1295. currData.set("score", 0);
  1296. currData.set("members", "");
  1297. }
  1298. return currData;
  1299. }
  1300. /**
  1301. * Returns a stats set containing the highest ever recorded score data for the specified festival.
  1302. * @param festivalId
  1303. * @return StatsSet result
  1304. */
  1305. public final StatsSet getOverallHighestScoreData(int festivalId)
  1306. {
  1307. StatsSet result = null;
  1308. int highestScore = 0;
  1309. for (Map<Integer, StatsSet> currCycleData : _festivalData.values())
  1310. {
  1311. for (StatsSet currFestData : currCycleData.values())
  1312. {
  1313. int currFestID = currFestData.getInt("festivalId");
  1314. int festivalScore = currFestData.getInt("score");
  1315. if (currFestID != festivalId)
  1316. {
  1317. continue;
  1318. }
  1319. if (festivalScore > highestScore)
  1320. {
  1321. highestScore = festivalScore;
  1322. result = currFestData;
  1323. }
  1324. }
  1325. }
  1326. return result;
  1327. }
  1328. /**
  1329. * 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>.
  1330. * @param player
  1331. * @param oracle
  1332. * @param festivalId
  1333. * @param offeringScore
  1334. * @return boolean isHighestScore
  1335. */
  1336. public boolean setFinalScore(L2PcInstance player, int oracle, int festivalId, long offeringScore)
  1337. {
  1338. List<String> partyMembers;
  1339. int currDawnHighScore = getHighestScore(SevenSigns.CABAL_DAWN, festivalId);
  1340. int currDuskHighScore = getHighestScore(SevenSigns.CABAL_DUSK, festivalId);
  1341. int thisCabalHighScore = 0;
  1342. int otherCabalHighScore = 0;
  1343. if (oracle == SevenSigns.CABAL_DAWN)
  1344. {
  1345. thisCabalHighScore = currDawnHighScore;
  1346. otherCabalHighScore = currDuskHighScore;
  1347. _dawnFestivalScores.put(festivalId, offeringScore);
  1348. }
  1349. else
  1350. {
  1351. thisCabalHighScore = currDuskHighScore;
  1352. otherCabalHighScore = currDawnHighScore;
  1353. _duskFestivalScores.put(festivalId, offeringScore);
  1354. }
  1355. StatsSet currFestData = getHighestScoreData(oracle, festivalId);
  1356. // Check if this is the highest score for this level range so far for the player's cabal.
  1357. if (offeringScore > thisCabalHighScore)
  1358. {
  1359. // If the current score is greater than that for the other cabal,
  1360. // then they already have the points from this festival.
  1361. if (thisCabalHighScore > otherCabalHighScore)
  1362. {
  1363. return false;
  1364. }
  1365. List<Integer> prevParticipants = getPreviousParticipants(oracle, festivalId);
  1366. partyMembers = new ArrayList<>(prevParticipants.size());
  1367. // Record a string list of the party members involved.
  1368. for (Integer partyMember : prevParticipants)
  1369. {
  1370. partyMembers.add(CharNameTable.getInstance().getNameById(partyMember));
  1371. }
  1372. // Update the highest scores and party list.
  1373. currFestData.set("date", String.valueOf(System.currentTimeMillis()));
  1374. currFestData.set("score", offeringScore);
  1375. currFestData.set("members", Util.implodeString(partyMembers, ","));
  1376. // Only add the score to the cabal's overall if it's higher than the other cabal's score.
  1377. if (offeringScore > otherCabalHighScore)
  1378. {
  1379. int contribPoints = FESTIVAL_LEVEL_SCORES[festivalId];
  1380. // Give this cabal the festival points, while deducting them from the other.
  1381. SevenSigns.getInstance().addFestivalScore(oracle, contribPoints);
  1382. }
  1383. saveFestivalData(true);
  1384. return true;
  1385. }
  1386. return false;
  1387. }
  1388. public final int getAccumulatedBonus(int festivalId)
  1389. {
  1390. return _accumulatedBonuses.get(festivalId);
  1391. }
  1392. public final int getTotalAccumulatedBonus()
  1393. {
  1394. int totalAccumBonus = 0;
  1395. for (int accumBonus : _accumulatedBonuses)
  1396. {
  1397. totalAccumBonus += accumBonus;
  1398. }
  1399. return totalAccumBonus;
  1400. }
  1401. public void addAccumulatedBonus(int festivalId, int stoneType, int stoneAmount)
  1402. {
  1403. int eachStoneBonus = 0;
  1404. switch (stoneType)
  1405. {
  1406. case SevenSigns.SEAL_STONE_BLUE_ID:
  1407. eachStoneBonus = SevenSigns.SEAL_STONE_BLUE_VALUE;
  1408. break;
  1409. case SevenSigns.SEAL_STONE_GREEN_ID:
  1410. eachStoneBonus = SevenSigns.SEAL_STONE_GREEN_VALUE;
  1411. break;
  1412. case SevenSigns.SEAL_STONE_RED_ID:
  1413. eachStoneBonus = SevenSigns.SEAL_STONE_RED_VALUE;
  1414. break;
  1415. }
  1416. int newTotalBonus = _accumulatedBonuses.get(festivalId) + (stoneAmount * eachStoneBonus);
  1417. _accumulatedBonuses.set(festivalId, newTotalBonus);
  1418. }
  1419. /**
  1420. * 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.
  1421. * @param player
  1422. * @return playerBonus (the share of the bonus for the party)
  1423. */
  1424. public final int distribAccumulatedBonus(L2PcInstance player)
  1425. {
  1426. int playerBonus = 0;
  1427. String playerName = player.getName();
  1428. int playerCabal = SevenSigns.getInstance().getPlayerCabal(player.getObjectId());
  1429. if (playerCabal != SevenSigns.getInstance().getCabalHighestScore())
  1430. {
  1431. return 0;
  1432. }
  1433. if (_festivalData.get(_signsCycle) != null)
  1434. {
  1435. for (StatsSet festivalData : _festivalData.get(_signsCycle).values())
  1436. {
  1437. if (festivalData.getString("members").indexOf(playerName) > -1)
  1438. {
  1439. int festivalId = festivalData.getInt("festivalId");
  1440. int numPartyMembers = festivalData.getString("members").split(",").length;
  1441. int totalAccumBonus = _accumulatedBonuses.get(festivalId);
  1442. playerBonus = totalAccumBonus / numPartyMembers;
  1443. _accumulatedBonuses.set(festivalId, totalAccumBonus - playerBonus);
  1444. break;
  1445. }
  1446. }
  1447. }
  1448. return playerBonus;
  1449. }
  1450. /**
  1451. * Used to send a "shout" message to all players currently present in an Oracle.<br>
  1452. * Primarily used for Festival Guide and Witch related speech.
  1453. * @param senderName
  1454. * @param npcString
  1455. */
  1456. public void sendMessageToAll(String senderName, NpcStringId npcString)
  1457. {
  1458. if ((_dawnChatGuide == null) || (_duskChatGuide == null))
  1459. {
  1460. return;
  1461. }
  1462. sendMessageToAll(senderName, npcString, _dawnChatGuide);
  1463. sendMessageToAll(senderName, npcString, _duskChatGuide);
  1464. }
  1465. /**
  1466. * @param senderName
  1467. * @param npcString
  1468. * @param npc
  1469. */
  1470. public void sendMessageToAll(String senderName, NpcStringId npcString, L2Npc npc)
  1471. {
  1472. CreatureSay cs = new CreatureSay(npc.getObjectId(), Say2.NPC_SHOUT, senderName, npcString);
  1473. if (npcString.getParamCount() == 1)
  1474. {
  1475. cs.addStringParameter(String.valueOf(getMinsToNextFestival()));
  1476. }
  1477. npc.broadcastPacket(cs);
  1478. }
  1479. /**
  1480. * Basically a wrapper-call to signal to increase the challenge of the specified festival.
  1481. * @param oracle
  1482. * @param festivalId
  1483. * @return boolean isChalIncreased
  1484. */
  1485. public final boolean increaseChallenge(int oracle, int festivalId)
  1486. {
  1487. L2DarknessFestival festivalInst = _managerInstance.getFestivalInstance(oracle, festivalId);
  1488. return festivalInst.increaseChallenge();
  1489. }
  1490. /**
  1491. * Used with the SpawnListener, to update the required "chat guide" instances, for use with announcements in the oracles.
  1492. * @param npc
  1493. */
  1494. @Override
  1495. public void npcSpawned(L2Npc npc)
  1496. {
  1497. if (npc == null)
  1498. {
  1499. return;
  1500. }
  1501. int npcId = npc.getId();
  1502. // If the spawned NPC ID matches the ones we need, assign their instances.
  1503. if (npcId == 31127)
  1504. {
  1505. _dawnChatGuide = npc;
  1506. }
  1507. if (npcId == 31137)
  1508. {
  1509. _duskChatGuide = npc;
  1510. }
  1511. }
  1512. /**
  1513. * The FestivalManager class is the main runner of all the festivals. It is used for easier integration and management of all running festivals.
  1514. * @author Tempy
  1515. */
  1516. private class FestivalManager implements Runnable
  1517. {
  1518. protected Map<Integer, L2DarknessFestival> _festivalInstances;
  1519. public FestivalManager()
  1520. {
  1521. _festivalInstances = new FastMap<>();
  1522. // Increment the cycle counter.
  1523. _festivalCycle++;
  1524. // Set the next start timers.
  1525. setNextCycleStart();
  1526. setNextFestivalStart(Config.ALT_FESTIVAL_CYCLE_LENGTH - FESTIVAL_SIGNUP_TIME);
  1527. }
  1528. @Override
  1529. public synchronized void run()
  1530. {
  1531. try
  1532. {
  1533. // The manager shouldn't be running if Seal Validation is in effect.
  1534. if (SevenSigns.getInstance().isSealValidationPeriod())
  1535. {
  1536. return;
  1537. }
  1538. // If the next period is due to start before the end of this
  1539. // festival cycle, then don't run it.
  1540. if (SevenSigns.getInstance().getMilliToPeriodChange() < Config.ALT_FESTIVAL_CYCLE_LENGTH)
  1541. {
  1542. return;
  1543. }
  1544. else if (getMinsToNextFestival() == 2)
  1545. {
  1546. sendMessageToAll("Festival Guide", NpcStringId.THE_MAIN_EVENT_WILL_START_IN_2_MINUTES_PLEASE_REGISTER_NOW);
  1547. }
  1548. // Stand by until the allowed signup period has elapsed.
  1549. try
  1550. {
  1551. wait(FESTIVAL_SIGNUP_TIME);
  1552. }
  1553. catch (InterruptedException e)
  1554. {
  1555. }
  1556. // Clear past participants, they can no longer register their score if not done so already.
  1557. _dawnPreviousParticipants.clear();
  1558. _duskPreviousParticipants.clear();
  1559. // Get rid of random monsters that avoided deletion after last festival
  1560. for (L2DarknessFestival festivalInst : _festivalInstances.values())
  1561. {
  1562. festivalInst.unspawnMobs();
  1563. }
  1564. // Start only if participants signed up
  1565. _noPartyRegister = true;
  1566. while (_noPartyRegister)
  1567. {
  1568. if ((_duskFestivalParticipants.isEmpty() && _dawnFestivalParticipants.isEmpty()))
  1569. {
  1570. try
  1571. {
  1572. setNextCycleStart();
  1573. setNextFestivalStart(Config.ALT_FESTIVAL_CYCLE_LENGTH - FESTIVAL_SIGNUP_TIME);
  1574. wait(Config.ALT_FESTIVAL_CYCLE_LENGTH - FESTIVAL_SIGNUP_TIME);
  1575. for (L2DarknessFestival festivalInst : _festivalInstances.values())
  1576. {
  1577. if (!festivalInst._npcInsts.isEmpty())
  1578. {
  1579. festivalInst.unspawnMobs();
  1580. }
  1581. }
  1582. }
  1583. catch (InterruptedException e)
  1584. {
  1585. }
  1586. }
  1587. else
  1588. {
  1589. _noPartyRegister = false;
  1590. }
  1591. }
  1592. /* INITIATION */
  1593. // Set the festival timer to 0, as it is just beginning.
  1594. long elapsedTime = 0;
  1595. // Create the instances for the festivals in both Oracles,
  1596. // but only if they have participants signed up for them.
  1597. for (int i = 0; i < FESTIVAL_COUNT; i++)
  1598. {
  1599. if (_duskFestivalParticipants.get(i) != null)
  1600. {
  1601. _festivalInstances.put(10 + i, new L2DarknessFestival(SevenSigns.CABAL_DUSK, i));
  1602. }
  1603. if (_dawnFestivalParticipants.get(i) != null)
  1604. {
  1605. _festivalInstances.put(20 + i, new L2DarknessFestival(SevenSigns.CABAL_DAWN, i));
  1606. }
  1607. }
  1608. // Prevent future signups while festival is in progress.
  1609. _festivalInitialized = true;
  1610. setNextFestivalStart(Config.ALT_FESTIVAL_CYCLE_LENGTH);
  1611. sendMessageToAll("Festival Guide", NpcStringId.THE_MAIN_EVENT_IS_NOW_STARTING);
  1612. // Stand by for a short length of time before starting the festival.
  1613. try
  1614. {
  1615. wait(Config.ALT_FESTIVAL_FIRST_SPAWN);
  1616. }
  1617. catch (InterruptedException e)
  1618. {
  1619. }
  1620. elapsedTime = Config.ALT_FESTIVAL_FIRST_SPAWN;
  1621. // Participants can now opt to increase the challenge, if desired.
  1622. _festivalInProgress = true;
  1623. /* PROPOGATION */
  1624. // Sequentially set all festivals to begin, spawn the Festival Witch and notify participants.
  1625. for (L2DarknessFestival festivalInst : _festivalInstances.values())
  1626. {
  1627. festivalInst.festivalStart();
  1628. festivalInst.sendMessageToParticipants(NpcStringId.THE_MAIN_EVENT_IS_NOW_STARTING);
  1629. }
  1630. // After a short time period, move all idle spawns to the center of the arena.
  1631. try
  1632. {
  1633. wait(Config.ALT_FESTIVAL_FIRST_SWARM - Config.ALT_FESTIVAL_FIRST_SPAWN);
  1634. }
  1635. catch (InterruptedException e)
  1636. {
  1637. }
  1638. elapsedTime += Config.ALT_FESTIVAL_FIRST_SWARM - Config.ALT_FESTIVAL_FIRST_SPAWN;
  1639. for (L2DarknessFestival festivalInst : _festivalInstances.values())
  1640. {
  1641. festivalInst.moveMonstersToCenter();
  1642. }
  1643. // Stand by until the time comes for the second spawn.
  1644. try
  1645. {
  1646. wait(Config.ALT_FESTIVAL_SECOND_SPAWN - Config.ALT_FESTIVAL_FIRST_SWARM);
  1647. }
  1648. catch (InterruptedException e)
  1649. {
  1650. }
  1651. // Spawn an extra set of monsters (archers) on the free platforms with
  1652. // a faster respawn when killed.
  1653. for (L2DarknessFestival festivalInst : _festivalInstances.values())
  1654. {
  1655. festivalInst.spawnFestivalMonsters(FESTIVAL_DEFAULT_RESPAWN / 2, 2);
  1656. long end = (Config.ALT_FESTIVAL_LENGTH - Config.ALT_FESTIVAL_SECOND_SPAWN) / 60000;
  1657. if (end == 2)
  1658. {
  1659. festivalInst.sendMessageToParticipants(NpcStringId.THE_FESTIVAL_OF_DARKNESS_WILL_END_IN_TWO_MINUTES);
  1660. }
  1661. else
  1662. {
  1663. festivalInst.sendMessageToParticipants("The Festival of Darkness will end in " + end + " minute(s).");
  1664. }
  1665. }
  1666. elapsedTime += Config.ALT_FESTIVAL_SECOND_SPAWN - Config.ALT_FESTIVAL_FIRST_SWARM;
  1667. // After another short time period, again move all idle spawns to the center of the arena.
  1668. try
  1669. {
  1670. wait(Config.ALT_FESTIVAL_SECOND_SWARM - Config.ALT_FESTIVAL_SECOND_SPAWN);
  1671. }
  1672. catch (InterruptedException e)
  1673. {
  1674. }
  1675. for (L2DarknessFestival festivalInst : _festivalInstances.values())
  1676. {
  1677. festivalInst.moveMonstersToCenter();
  1678. }
  1679. elapsedTime += Config.ALT_FESTIVAL_SECOND_SWARM - Config.ALT_FESTIVAL_SECOND_SPAWN;
  1680. // Stand by until the time comes for the chests to be spawned.
  1681. try
  1682. {
  1683. wait(Config.ALT_FESTIVAL_CHEST_SPAWN - Config.ALT_FESTIVAL_SECOND_SWARM);
  1684. }
  1685. catch (InterruptedException e)
  1686. {
  1687. }
  1688. // Spawn the festival chests, which enable the team to gain greater rewards
  1689. // for each chest they kill.
  1690. for (L2DarknessFestival festivalInst : _festivalInstances.values())
  1691. {
  1692. festivalInst.spawnFestivalMonsters(FESTIVAL_DEFAULT_RESPAWN, 3);
  1693. festivalInst.sendMessageToParticipants("The chests have spawned! Be quick, the festival will end soon."); // FIXME What is the correct npcString?
  1694. }
  1695. elapsedTime += Config.ALT_FESTIVAL_CHEST_SPAWN - Config.ALT_FESTIVAL_SECOND_SWARM;
  1696. // Stand by and wait until it's time to end the festival.
  1697. try
  1698. {
  1699. wait(Config.ALT_FESTIVAL_LENGTH - elapsedTime);
  1700. }
  1701. catch (InterruptedException e)
  1702. {
  1703. }
  1704. // Participants can no longer opt to increase the challenge, as the festival will soon close.
  1705. _festivalInProgress = false;
  1706. /* TERMINATION */
  1707. // Sequentially begin the ending sequence for all running festivals.
  1708. for (L2DarknessFestival festivalInst : _festivalInstances.values())
  1709. {
  1710. festivalInst.festivalEnd();
  1711. }
  1712. // Clear the participants list for the next round of signups.
  1713. _dawnFestivalParticipants.clear();
  1714. _duskFestivalParticipants.clear();
  1715. // Allow signups for the next festival cycle.
  1716. _festivalInitialized = false;
  1717. sendMessageToAll("Festival Witch", NpcStringId.THAT_WILL_DO_ILL_MOVE_YOU_TO_THE_OUTSIDE_SOON);
  1718. }
  1719. catch (Exception e)
  1720. {
  1721. _log.warning(e.getMessage());
  1722. }
  1723. }
  1724. /**
  1725. * Returns the running instance of a festival for the given Oracle and festivalID. <BR>
  1726. * A <B>null</B> value is returned if there are no participants in that festival.
  1727. * @param oracle
  1728. * @param festivalId
  1729. * @return L2DarknessFestival festivalInst
  1730. */
  1731. public final L2DarknessFestival getFestivalInstance(int oracle, int festivalId)
  1732. {
  1733. if (!isFestivalInitialized())
  1734. {
  1735. return null;
  1736. }
  1737. /*
  1738. * Compute the offset if a Dusk instance is required. ID: 0 1 2 3 4 Dusk 1:1011121314 Dawn 2:2021222324
  1739. */
  1740. festivalId += (oracle == SevenSigns.CABAL_DUSK) ? 10 : 20;
  1741. return _festivalInstances.get(festivalId);
  1742. }
  1743. }
  1744. /**
  1745. * 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.
  1746. * @author Tempy
  1747. */
  1748. private class L2DarknessFestival
  1749. {
  1750. protected final int _cabal;
  1751. protected final int _levelRange;
  1752. protected boolean _challengeIncreased;
  1753. private FestivalSpawn _startLocation;
  1754. private FestivalSpawn _witchSpawn;
  1755. private L2Npc _witchInst;
  1756. List<L2FestivalMonsterInstance> _npcInsts;
  1757. private List<Integer> _participants;
  1758. private final Map<Integer, FestivalSpawn> _originalLocations;
  1759. protected L2DarknessFestival(int cabal, int levelRange)
  1760. {
  1761. _cabal = cabal;
  1762. _levelRange = levelRange;
  1763. _originalLocations = new FastMap<>();
  1764. _npcInsts = new FastList<>();
  1765. if (cabal == SevenSigns.CABAL_DAWN)
  1766. {
  1767. _participants = _dawnFestivalParticipants.get(levelRange);
  1768. _witchSpawn = new FestivalSpawn(FESTIVAL_DAWN_WITCH_SPAWNS[levelRange]);
  1769. _startLocation = new FestivalSpawn(FESTIVAL_DAWN_PLAYER_SPAWNS[levelRange]);
  1770. }
  1771. else
  1772. {
  1773. _participants = _duskFestivalParticipants.get(levelRange);
  1774. _witchSpawn = new FestivalSpawn(FESTIVAL_DUSK_WITCH_SPAWNS[levelRange]);
  1775. _startLocation = new FestivalSpawn(FESTIVAL_DUSK_PLAYER_SPAWNS[levelRange]);
  1776. }
  1777. // FOR TESTING!
  1778. if (_participants == null)
  1779. {
  1780. _participants = new ArrayList<>();
  1781. }
  1782. festivalInit();
  1783. }
  1784. protected void festivalInit()
  1785. {
  1786. boolean isPositive;
  1787. // Teleport all players to arena and notify them.
  1788. if ((_participants != null) && !_participants.isEmpty())
  1789. {
  1790. try
  1791. {
  1792. for (int participantObjId : _participants)
  1793. {
  1794. L2PcInstance participant = L2World.getInstance().getPlayer(participantObjId);
  1795. if (participant == null)
  1796. {
  1797. continue;
  1798. }
  1799. _originalLocations.put(participantObjId, new FestivalSpawn(participant.getX(), participant.getY(), participant.getZ(), participant.getHeading()));
  1800. // Randomize the spawn point around the specific centerpoint for each player.
  1801. int x = _startLocation._x;
  1802. int y = _startLocation._y;
  1803. isPositive = (Rnd.nextInt(2) == 1);
  1804. if (isPositive)
  1805. {
  1806. x += Rnd.nextInt(FESTIVAL_MAX_OFFSET_X);
  1807. y += Rnd.nextInt(FESTIVAL_MAX_OFFSET_Y);
  1808. }
  1809. else
  1810. {
  1811. x -= Rnd.nextInt(FESTIVAL_MAX_OFFSET_X);
  1812. y -= Rnd.nextInt(FESTIVAL_MAX_OFFSET_Y);
  1813. }
  1814. participant.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
  1815. participant.teleToLocation(new Location(x, y, _startLocation._z), true);
  1816. // Remove all buffs from all participants on entry. Works like the skill Cancel.
  1817. participant.stopAllEffectsExceptThoseThatLastThroughDeath();
  1818. // Remove any stray blood offerings in inventory
  1819. L2ItemInstance bloodOfferings = participant.getInventory().getItemByItemId(FESTIVAL_OFFERING_ID);
  1820. if (bloodOfferings != null)
  1821. {
  1822. participant.destroyItem("SevenSigns", bloodOfferings, null, true);
  1823. }
  1824. }
  1825. }
  1826. catch (NullPointerException e)
  1827. {
  1828. // deleteMe handling should teleport party out in case of disconnect
  1829. }
  1830. }
  1831. // Spawn the festival witch for this arena
  1832. try
  1833. {
  1834. L2Spawn npcSpawn = new L2Spawn(_witchSpawn._npcId);
  1835. npcSpawn.setX(_witchSpawn._x);
  1836. npcSpawn.setY(_witchSpawn._y);
  1837. npcSpawn.setZ(_witchSpawn._z);
  1838. npcSpawn.setHeading(_witchSpawn._heading);
  1839. npcSpawn.setAmount(1);
  1840. npcSpawn.setRespawnDelay(1);
  1841. // Needed as doSpawn() is required to be called also for the NpcInstance it returns.
  1842. npcSpawn.startRespawn();
  1843. SpawnTable.getInstance().addNewSpawn(npcSpawn, false);
  1844. _witchInst = npcSpawn.doSpawn();
  1845. }
  1846. catch (Exception e)
  1847. {
  1848. _log.log(Level.WARNING, "SevenSignsFestival: Error while spawning Festival Witch ID " + _witchSpawn._npcId + ": " + e.getMessage(), e);
  1849. }
  1850. // Make it appear as though the Witch has apparated there.
  1851. MagicSkillUse msu = new MagicSkillUse(_witchInst, _witchInst, 2003, 1, 1, 0);
  1852. _witchInst.broadcastPacket(msu);
  1853. // And another one...:D
  1854. msu = new MagicSkillUse(_witchInst, _witchInst, 2133, 1, 1, 0);
  1855. _witchInst.broadcastPacket(msu);
  1856. // Send a message to all participants from the witch.
  1857. sendMessageToParticipants(NpcStringId.THE_MAIN_EVENT_WILL_START_IN_2_MINUTES_PLEASE_REGISTER_NOW);
  1858. }
  1859. protected void festivalStart()
  1860. {
  1861. spawnFestivalMonsters(FESTIVAL_DEFAULT_RESPAWN, 0);
  1862. }
  1863. protected void moveMonstersToCenter()
  1864. {
  1865. boolean isPositive;
  1866. for (L2FestivalMonsterInstance festivalMob : _npcInsts)
  1867. {
  1868. if (festivalMob.isDead())
  1869. {
  1870. continue;
  1871. }
  1872. // Only move monsters that are idle or doing their usual functions.
  1873. CtrlIntention currIntention = festivalMob.getAI().getIntention();
  1874. if ((currIntention != CtrlIntention.AI_INTENTION_IDLE) && (currIntention != CtrlIntention.AI_INTENTION_ACTIVE))
  1875. {
  1876. continue;
  1877. }
  1878. int x = _startLocation._x;
  1879. int y = _startLocation._y;
  1880. /*
  1881. * 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.
  1882. */
  1883. isPositive = (Rnd.nextInt(2) == 1);
  1884. if (isPositive)
  1885. {
  1886. x += Rnd.nextInt(FESTIVAL_MAX_OFFSET_X);
  1887. y += Rnd.nextInt(FESTIVAL_MAX_OFFSET_Y);
  1888. }
  1889. else
  1890. {
  1891. x -= Rnd.nextInt(FESTIVAL_MAX_OFFSET_X);
  1892. y -= Rnd.nextInt(FESTIVAL_MAX_OFFSET_Y);
  1893. }
  1894. festivalMob.setRunning();
  1895. festivalMob.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(x, y, _startLocation._z, Rnd.nextInt(65536)));
  1896. }
  1897. }
  1898. /**
  1899. * Used to spawn monsters unique to the festival. <BR>
  1900. * Valid SpawnTypes:<BR>
  1901. * 0 - All Primary Monsters (starting monsters) <BR>
  1902. * 1 - Same as 0, but without archers/marksmen. (used for challenge increase) <BR>
  1903. * 2 - Secondary Monsters (archers) <BR>
  1904. * 3 - Festival Chests
  1905. * @param respawnDelay
  1906. * @param spawnType
  1907. */
  1908. protected void spawnFestivalMonsters(int respawnDelay, int spawnType)
  1909. {
  1910. int[][] _npcSpawns = null;
  1911. switch (spawnType)
  1912. {
  1913. case 0:
  1914. case 1:
  1915. _npcSpawns = (_cabal == SevenSigns.CABAL_DAWN) ? FESTIVAL_DAWN_PRIMARY_SPAWNS[_levelRange] : FESTIVAL_DUSK_PRIMARY_SPAWNS[_levelRange];
  1916. break;
  1917. case 2:
  1918. _npcSpawns = (_cabal == SevenSigns.CABAL_DAWN) ? FESTIVAL_DAWN_SECONDARY_SPAWNS[_levelRange] : FESTIVAL_DUSK_SECONDARY_SPAWNS[_levelRange];
  1919. break;
  1920. case 3:
  1921. _npcSpawns = (_cabal == SevenSigns.CABAL_DAWN) ? FESTIVAL_DAWN_CHEST_SPAWNS[_levelRange] : FESTIVAL_DUSK_CHEST_SPAWNS[_levelRange];
  1922. break;
  1923. default:
  1924. return;
  1925. }
  1926. for (int[] _npcSpawn : _npcSpawns)
  1927. {
  1928. FestivalSpawn currSpawn = new FestivalSpawn(_npcSpawn);
  1929. // Only spawn archers/marksmen if specified to do so.
  1930. if ((spawnType == 1) && isFestivalArcher(currSpawn._npcId))
  1931. {
  1932. continue;
  1933. }
  1934. try
  1935. {
  1936. L2Spawn npcSpawn = new L2Spawn(currSpawn._npcId);
  1937. npcSpawn.setX(currSpawn._x);
  1938. npcSpawn.setY(currSpawn._y);
  1939. npcSpawn.setZ(currSpawn._z);
  1940. npcSpawn.setHeading(Rnd.nextInt(65536));
  1941. npcSpawn.setAmount(1);
  1942. npcSpawn.setRespawnDelay(respawnDelay);
  1943. // Needed as doSpawn() is required to be called also for the NpcInstance it returns.
  1944. npcSpawn.startRespawn();
  1945. SpawnTable.getInstance().addNewSpawn(npcSpawn, false);
  1946. L2FestivalMonsterInstance festivalMob = (L2FestivalMonsterInstance) npcSpawn.doSpawn();
  1947. // Set the offering bonus to 2x or 5x the amount per kill,
  1948. // if this spawn is part of an increased challenge or is a festival chest.
  1949. if (spawnType == 1)
  1950. {
  1951. festivalMob.setOfferingBonus(2);
  1952. }
  1953. else if (spawnType == 3)
  1954. {
  1955. festivalMob.setOfferingBonus(5);
  1956. }
  1957. _npcInsts.add(festivalMob);
  1958. }
  1959. catch (Exception e)
  1960. {
  1961. _log.log(Level.WARNING, "SevenSignsFestival: Error while spawning NPC ID " + currSpawn._npcId + ": " + e.getMessage(), e);
  1962. }
  1963. }
  1964. }
  1965. protected boolean increaseChallenge()
  1966. {
  1967. if (_challengeIncreased)
  1968. {
  1969. return false;
  1970. }
  1971. // Set this flag to true to make sure that this can only be done once.
  1972. _challengeIncreased = true;
  1973. // Spawn more festival monsters, but this time with a twist.
  1974. spawnFestivalMonsters(FESTIVAL_DEFAULT_RESPAWN, 1);
  1975. return true;
  1976. }
  1977. public void sendMessageToParticipants(NpcStringId npcStringId)
  1978. {
  1979. if ((_participants != null) && !_participants.isEmpty())
  1980. {
  1981. _witchInst.broadcastPacket(new CreatureSay(_witchInst.getObjectId(), Say2.NPC_ALL, "Festival Witch", npcStringId));
  1982. }
  1983. }
  1984. public void sendMessageToParticipants(String npcString)
  1985. {
  1986. if ((_participants != null) && !_participants.isEmpty())
  1987. {
  1988. _witchInst.broadcastPacket(new CreatureSay(_witchInst.getObjectId(), Say2.NPC_ALL, "Festival Witch", npcString));
  1989. }
  1990. }
  1991. protected void festivalEnd()
  1992. {
  1993. if ((_participants != null) && !_participants.isEmpty())
  1994. {
  1995. for (int participantObjId : _participants)
  1996. {
  1997. try
  1998. {
  1999. L2PcInstance participant = L2World.getInstance().getPlayer(participantObjId);
  2000. if (participant == null)
  2001. {
  2002. continue;
  2003. }
  2004. relocatePlayer(participant, false);
  2005. participant.sendMessage("The festival has ended. Your party leader must now register your score before the next festival takes place.");
  2006. }
  2007. catch (NullPointerException e)
  2008. {
  2009. }
  2010. }
  2011. if (_cabal == SevenSigns.CABAL_DAWN)
  2012. {
  2013. _dawnPreviousParticipants.put(_levelRange, _participants);
  2014. }
  2015. else
  2016. {
  2017. _duskPreviousParticipants.put(_levelRange, _participants);
  2018. }
  2019. }
  2020. _participants = null;
  2021. unspawnMobs();
  2022. }
  2023. protected void unspawnMobs()
  2024. {
  2025. // Delete all the NPCs in the current festival arena.
  2026. if (_witchInst != null)
  2027. {
  2028. _witchInst.getSpawn().stopRespawn();
  2029. _witchInst.deleteMe();
  2030. SpawnTable.getInstance().deleteSpawn(_witchInst.getSpawn(), false);
  2031. }
  2032. if (_npcInsts != null)
  2033. {
  2034. for (L2FestivalMonsterInstance monsterInst : _npcInsts)
  2035. {
  2036. if (monsterInst != null)
  2037. {
  2038. monsterInst.getSpawn().stopRespawn();
  2039. monsterInst.deleteMe();
  2040. SpawnTable.getInstance().deleteSpawn(monsterInst.getSpawn(), false);
  2041. }
  2042. }
  2043. }
  2044. }
  2045. public void relocatePlayer(L2PcInstance participant, boolean isRemoving)
  2046. {
  2047. try
  2048. {
  2049. FestivalSpawn origPosition = _originalLocations.get(participant.getObjectId());
  2050. if (isRemoving)
  2051. {
  2052. _originalLocations.remove(participant.getObjectId());
  2053. }
  2054. participant.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
  2055. participant.teleToLocation(new Location(origPosition._x, origPosition._y, origPosition._z), true);
  2056. participant.sendMessage("You have been removed from the festival arena.");
  2057. }
  2058. catch (Exception e)
  2059. {
  2060. // If an exception occurs, just move the player to the nearest town.
  2061. try
  2062. {
  2063. participant.teleToLocation(TeleportWhereType.TOWN);
  2064. participant.sendMessage("You have been removed from the festival arena.");
  2065. }
  2066. catch (NullPointerException e2)
  2067. {
  2068. }
  2069. }
  2070. }
  2071. }
  2072. private static class FestivalSpawn
  2073. {
  2074. protected final int _x;
  2075. protected final int _y;
  2076. protected final int _z;
  2077. protected final int _heading;
  2078. protected final int _npcId;
  2079. protected FestivalSpawn(int x, int y, int z, int heading)
  2080. {
  2081. _x = x;
  2082. _y = y;
  2083. _z = z;
  2084. // Generate a random heading if no positive one given.
  2085. _heading = (heading < 0) ? Rnd.nextInt(65536) : heading;
  2086. _npcId = -1;
  2087. }
  2088. protected FestivalSpawn(int[] spawnData)
  2089. {
  2090. _x = spawnData[0];
  2091. _y = spawnData[1];
  2092. _z = spawnData[2];
  2093. _heading = (spawnData[3] < 0) ? Rnd.nextInt(65536) : spawnData[3];
  2094. if (spawnData.length > 4)
  2095. {
  2096. _npcId = spawnData[4];
  2097. }
  2098. else
  2099. {
  2100. _npcId = -1;
  2101. }
  2102. }
  2103. }
  2104. private static class SingletonHolder
  2105. {
  2106. protected static final SevenSignsFestival _instance = new SevenSignsFestival();
  2107. }
  2108. }