L2Npc.java 94 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033
  1. /*
  2. * This program is free software: you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation, either version 3 of the License, or (at your option) any later
  5. * version.
  6. *
  7. * This program is distributed in the hope that it will be useful, but WITHOUT
  8. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  10. * details.
  11. *
  12. * You should have received a copy of the GNU General Public License along with
  13. * this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. package com.l2jserver.gameserver.model.actor;
  16. import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
  17. import java.text.DateFormat;
  18. import java.util.Collection;
  19. import java.util.List;
  20. import java.util.logging.Level;
  21. import javolution.util.FastList;
  22. import com.l2jserver.Config;
  23. import com.l2jserver.gameserver.SevenSigns;
  24. import com.l2jserver.gameserver.SevenSignsFestival;
  25. import com.l2jserver.gameserver.ThreadPoolManager;
  26. import com.l2jserver.gameserver.ai.CtrlIntention;
  27. import com.l2jserver.gameserver.cache.HtmCache;
  28. import com.l2jserver.gameserver.datatables.ClanTable;
  29. import com.l2jserver.gameserver.datatables.HelperBuffTable;
  30. import com.l2jserver.gameserver.datatables.ItemTable;
  31. import com.l2jserver.gameserver.datatables.NpcTable;
  32. import com.l2jserver.gameserver.datatables.SkillTable;
  33. import com.l2jserver.gameserver.datatables.SpawnTable;
  34. import com.l2jserver.gameserver.idfactory.IdFactory;
  35. import com.l2jserver.gameserver.instancemanager.CastleManager;
  36. import com.l2jserver.gameserver.instancemanager.DimensionalRiftManager;
  37. import com.l2jserver.gameserver.instancemanager.FortManager;
  38. import com.l2jserver.gameserver.instancemanager.QuestManager;
  39. import com.l2jserver.gameserver.instancemanager.TownManager;
  40. import com.l2jserver.gameserver.instancemanager.games.Lottery;
  41. import com.l2jserver.gameserver.model.L2Clan;
  42. import com.l2jserver.gameserver.model.L2DropCategory;
  43. import com.l2jserver.gameserver.model.L2DropData;
  44. import com.l2jserver.gameserver.model.L2ItemInstance;
  45. import com.l2jserver.gameserver.model.L2Multisell;
  46. import com.l2jserver.gameserver.model.L2NpcAIData;
  47. import com.l2jserver.gameserver.model.L2Object;
  48. import com.l2jserver.gameserver.model.L2Skill;
  49. import com.l2jserver.gameserver.model.L2Spawn;
  50. import com.l2jserver.gameserver.model.L2World;
  51. import com.l2jserver.gameserver.model.L2WorldRegion;
  52. import com.l2jserver.gameserver.model.MobGroupTable;
  53. import com.l2jserver.gameserver.model.actor.instance.L2ClanHallManagerInstance;
  54. import com.l2jserver.gameserver.model.actor.instance.L2ControllableMobInstance;
  55. import com.l2jserver.gameserver.model.actor.instance.L2DoormenInstance;
  56. import com.l2jserver.gameserver.model.actor.instance.L2FestivalGuideInstance;
  57. import com.l2jserver.gameserver.model.actor.instance.L2FishermanInstance;
  58. import com.l2jserver.gameserver.model.actor.instance.L2MerchantInstance;
  59. import com.l2jserver.gameserver.model.actor.instance.L2NpcInstance;
  60. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  61. import com.l2jserver.gameserver.model.actor.instance.L2SummonInstance;
  62. import com.l2jserver.gameserver.model.actor.instance.L2TeleporterInstance;
  63. import com.l2jserver.gameserver.model.actor.instance.L2TrainerInstance;
  64. import com.l2jserver.gameserver.model.actor.instance.L2WarehouseInstance;
  65. import com.l2jserver.gameserver.model.actor.knownlist.NpcKnownList;
  66. import com.l2jserver.gameserver.model.actor.stat.NpcStat;
  67. import com.l2jserver.gameserver.model.actor.status.NpcStatus;
  68. import com.l2jserver.gameserver.model.entity.Castle;
  69. import com.l2jserver.gameserver.model.entity.Fort;
  70. import com.l2jserver.gameserver.model.entity.L2Event;
  71. import com.l2jserver.gameserver.model.olympiad.Olympiad;
  72. import com.l2jserver.gameserver.model.quest.Quest;
  73. import com.l2jserver.gameserver.model.quest.QuestState;
  74. import com.l2jserver.gameserver.model.quest.State;
  75. import com.l2jserver.gameserver.model.zone.type.L2TownZone;
  76. import com.l2jserver.gameserver.network.SystemMessageId;
  77. import com.l2jserver.gameserver.network.serverpackets.AbstractNpcInfo;
  78. import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
  79. import com.l2jserver.gameserver.network.serverpackets.EtcStatusUpdate;
  80. import com.l2jserver.gameserver.network.serverpackets.ExShowBaseAttributeCancelWindow;
  81. import com.l2jserver.gameserver.network.serverpackets.ExShowVariationCancelWindow;
  82. import com.l2jserver.gameserver.network.serverpackets.ExShowVariationMakeWindow;
  83. import com.l2jserver.gameserver.network.serverpackets.InventoryUpdate;
  84. import com.l2jserver.gameserver.network.serverpackets.MagicSkillUse;
  85. import com.l2jserver.gameserver.network.serverpackets.MyTargetSelected;
  86. import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
  87. import com.l2jserver.gameserver.network.serverpackets.RadarControl;
  88. import com.l2jserver.gameserver.network.serverpackets.ServerObjectInfo;
  89. import com.l2jserver.gameserver.network.serverpackets.SocialAction;
  90. import com.l2jserver.gameserver.network.serverpackets.StatusUpdate;
  91. import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
  92. import com.l2jserver.gameserver.network.serverpackets.ValidateLocation;
  93. import com.l2jserver.gameserver.skills.Stats;
  94. import com.l2jserver.gameserver.taskmanager.DecayTaskManager;
  95. import com.l2jserver.gameserver.templates.L2HelperBuff;
  96. import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
  97. import com.l2jserver.gameserver.templates.chars.L2NpcTemplate.AIType;
  98. import com.l2jserver.gameserver.templates.item.L2Item;
  99. import com.l2jserver.gameserver.templates.item.L2Weapon;
  100. import com.l2jserver.gameserver.templates.skills.L2SkillType;
  101. import com.l2jserver.gameserver.util.Broadcast;
  102. import com.l2jserver.gameserver.util.StringUtil;
  103. import com.l2jserver.util.Rnd;
  104. /**
  105. * This class represents a Non-Player-Character in the world. It can be a monster or a friendly character.
  106. * It also uses a template to fetch some static values. The templates are hardcoded in the client, so we can rely on them.<BR><BR>
  107. *
  108. * L2Character :<BR><BR>
  109. * <li>L2Attackable</li>
  110. * <li>L2BoxInstance</li>
  111. * <li>L2FolkInstance</li>
  112. *
  113. * @version $Revision: 1.32.2.7.2.24 $ $Date: 2005/04/11 10:06:09 $
  114. */
  115. public class L2Npc extends L2Character
  116. {
  117. //private static Logger _log = Logger.getLogger(L2NpcInstance.class.getName());
  118. /** The interaction distance of the L2NpcInstance(is used as offset in MovetoLocation method) */
  119. public static final int INTERACTION_DISTANCE = 150;
  120. /** The L2Spawn object that manage this L2NpcInstance */
  121. private L2Spawn _spawn;
  122. /** The flag to specify if this L2NpcInstance is busy */
  123. private boolean _isBusy = false;
  124. /** The busy message for this L2NpcInstance */
  125. private String _busyMessage = "";
  126. /** True if endDecayTask has already been called */
  127. volatile boolean _isDecayed = false;
  128. /** The castle index in the array of L2Castle this L2NpcInstance belongs to */
  129. private int _castleIndex = -2;
  130. /** The fortress index in the array of L2Fort this L2NpcInstance belongs to */
  131. private int _fortIndex = -2;
  132. public boolean isEventMob = false;
  133. private boolean _isInTown = false;
  134. /** Time of last social packet broadcast*/
  135. private long _lastSocialBroadcast = 0;
  136. /** Minimum interval between social packets*/
  137. private int _minimalSocialInterval = 6000;
  138. protected RandomAnimationTask _rAniTask = null;
  139. private int _currentLHandId; // normally this shouldn't change from the template, but there exist exceptions
  140. private int _currentRHandId; // normally this shouldn't change from the template, but there exist exceptions
  141. private int _currentEnchant; // normally this shouldn't change from the template, but there exist exceptions
  142. private double _currentCollisionHeight; // used for npc grow effect skills
  143. private double _currentCollisionRadius; // used for npc grow effect skills
  144. public boolean _soulshotcharged = false;
  145. public boolean _spiritshotcharged = false;
  146. private int _soulshotamount = 0;
  147. private int _spiritshotamount = 0;
  148. public boolean _ssrecharged = true;
  149. public boolean _spsrecharged = true;
  150. //AI Recall
  151. public int getSoulShot()
  152. {
  153. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  154. L2NpcAIData AI = npcData.getAIDataStatic();
  155. if (AI == null)
  156. return 0;
  157. else
  158. return AI.getSoulShot();
  159. }
  160. public int getSpiritShot()
  161. {
  162. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  163. L2NpcAIData AI = npcData.getAIDataStatic();
  164. if (AI == null)
  165. return 0;
  166. else
  167. return AI.getSpiritShot();
  168. }
  169. public int getSoulShotChance()
  170. {
  171. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  172. L2NpcAIData AI = npcData.getAIDataStatic();
  173. if (AI == null)
  174. return 0;
  175. else
  176. return AI.getSoulShotChance();
  177. }
  178. public int getSpiritShotChance()
  179. {
  180. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  181. L2NpcAIData AI = npcData.getAIDataStatic();
  182. if (AI == null)
  183. return 0;
  184. else
  185. return AI.getSpiritShotChance();
  186. }
  187. public boolean useSoulShot()
  188. {
  189. if(_soulshotcharged)
  190. return true;
  191. if(_ssrecharged)
  192. {
  193. _soulshotamount = getSoulShot();
  194. _ssrecharged = false;
  195. }
  196. else if (_soulshotamount>0)
  197. {
  198. if (Rnd.get(100) <= getSoulShotChance())
  199. {
  200. _soulshotamount = _soulshotamount - 1;
  201. Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 360000);
  202. _soulshotcharged = true;
  203. }
  204. }
  205. else return false;
  206. return _soulshotcharged;
  207. }
  208. public boolean useSpiritShot()
  209. {
  210. if(_spiritshotcharged)
  211. return true;
  212. else
  213. {
  214. //_spiritshotcharged = false;
  215. if(_spsrecharged)
  216. {
  217. _spiritshotamount = getSpiritShot();
  218. _spsrecharged = false;
  219. }
  220. else if (_spiritshotamount>0)
  221. {
  222. if (Rnd.get(100) <= getSpiritShotChance())
  223. {
  224. _spiritshotamount = _spiritshotamount - 1;
  225. Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 360000);
  226. _spiritshotcharged = true;
  227. }
  228. }
  229. else return false;
  230. }
  231. return _spiritshotcharged;
  232. }
  233. public int getEnemyRange()
  234. {
  235. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  236. L2NpcAIData AI = npcData.getAIDataStatic();
  237. if (AI == null)
  238. return 0;
  239. else
  240. return AI.getEnemyRange();
  241. }
  242. public String getEnemyClan()
  243. {
  244. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  245. L2NpcAIData AI = npcData.getAIDataStatic();
  246. if (AI == null || AI.getEnemyClan() == null || "".equals(AI.getEnemyClan()))
  247. return "none";
  248. else
  249. return AI.getEnemyClan();
  250. }
  251. public String getClan()
  252. {
  253. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  254. L2NpcAIData AI = npcData.getAIDataStatic();
  255. if (AI == null || AI.getClan() == null || "".equals(AI.getClan()))
  256. return "none";
  257. else
  258. return AI.getClan();
  259. }
  260. // GET THE PRIMARY ATTACK
  261. public int getPrimaryAttack()
  262. {
  263. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  264. L2NpcAIData AI = npcData.getAIDataStatic();
  265. if (AI == null)
  266. return 0;
  267. else
  268. return AI.getPrimaryAttack();
  269. }
  270. public int getSkillChance()
  271. {
  272. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  273. L2NpcAIData AI = npcData.getAIDataStatic();
  274. if (AI == null)
  275. return 20;
  276. else
  277. return AI.getSkillChance();
  278. }
  279. public int getCanMove()
  280. {
  281. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  282. L2NpcAIData AI = npcData.getAIDataStatic();
  283. if (AI == null)
  284. return 0;
  285. else
  286. return AI.getCanMove();
  287. }
  288. public int getIsChaos()
  289. {
  290. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  291. L2NpcAIData AI = npcData.getAIDataStatic();
  292. if (AI == null)
  293. return 0;
  294. else
  295. return AI.getIsChaos();
  296. }
  297. public int getCanDodge()
  298. {
  299. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  300. L2NpcAIData AI = npcData.getAIDataStatic();
  301. if (AI == null)
  302. return 0;
  303. else
  304. return AI.getDodge();
  305. }
  306. public int getSSkillChance()
  307. {
  308. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  309. L2NpcAIData AI = npcData.getAIDataStatic();
  310. if (AI == null)
  311. return 0;
  312. else
  313. return AI.getShortRangeChance();
  314. }
  315. public int getLSkillChance()
  316. {
  317. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  318. L2NpcAIData AI = npcData.getAIDataStatic();
  319. if (AI == null)
  320. return 0;
  321. else
  322. return AI.getLongRangeChance();
  323. }
  324. public int getSwitchRangeChance()
  325. {
  326. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  327. L2NpcAIData AI = npcData.getAIDataStatic();
  328. if (AI == null)
  329. return 0;
  330. else
  331. return AI.getSwitchRangeChance();
  332. }
  333. public boolean hasLSkill()
  334. {
  335. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  336. L2NpcAIData AI = npcData.getAIDataStatic();
  337. if (AI == null || AI.getLongRangeSkill() == 0)
  338. return false;
  339. else
  340. return true;
  341. }
  342. public boolean hasSSkill()
  343. {
  344. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(this.getTemplate().npcId);
  345. L2NpcAIData AI = npcData.getAIDataStatic();
  346. if (AI == null || AI.getShortRangeSkill() == 0)
  347. return false;
  348. else
  349. return true;
  350. }
  351. public FastList<L2Skill> getLrangeSkill()
  352. {
  353. FastList<L2Skill> skilldata = new FastList <L2Skill>();
  354. boolean hasLrange = false;
  355. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(getTemplate().npcId);
  356. L2NpcAIData AI = npcData.getAIDataStatic();
  357. if (AI == null || AI.getLongRangeSkill() == 0)
  358. return null;
  359. switch (AI.getLongRangeSkill())
  360. {
  361. case -1:
  362. {
  363. L2Skill[] skills = null;
  364. skills = getAllSkills();
  365. if (skills != null)
  366. {
  367. for (L2Skill sk: skills)
  368. {
  369. if (sk == null || sk.isPassive()
  370. || sk.getTargetType() == L2Skill.SkillTargetType.TARGET_SELF)
  371. continue;
  372. if (sk.getCastRange() >= 200)
  373. {
  374. skilldata.add(sk);
  375. hasLrange = true;
  376. }
  377. }
  378. }
  379. break;
  380. }
  381. case 1:
  382. {
  383. if (npcData._universalskills != null)
  384. {
  385. for (L2Skill sk: npcData._universalskills)
  386. {
  387. if (sk.getCastRange() >= 200)
  388. {
  389. skilldata.add(sk);
  390. hasLrange = true;
  391. }
  392. }
  393. }
  394. break;
  395. }
  396. default:
  397. {
  398. for (L2Skill sk: getAllSkills())
  399. {
  400. if (sk.getId() == AI.getLongRangeSkill())
  401. {
  402. skilldata.add(sk);
  403. hasLrange = true;
  404. }
  405. }
  406. }
  407. }
  408. return (hasLrange ? skilldata : null);
  409. }
  410. public FastList<L2Skill> getSrangeSkill()
  411. {
  412. FastList<L2Skill> skilldata = new FastList <L2Skill>();
  413. boolean hasSrange = false;
  414. L2NpcTemplate npcData = NpcTable.getInstance().getTemplate(getTemplate().npcId);
  415. L2NpcAIData AI = npcData.getAIDataStatic();
  416. if (AI == null || AI.getShortRangeSkill() == 0)
  417. return null;
  418. switch (AI.getShortRangeSkill())
  419. {
  420. case -1:
  421. {
  422. L2Skill[] skills = null;
  423. skills = getAllSkills();
  424. if (skills != null)
  425. {
  426. for (L2Skill sk: skills)
  427. {
  428. if (sk == null || sk.isPassive()
  429. || sk.getTargetType() == L2Skill.SkillTargetType.TARGET_SELF)
  430. continue;
  431. if (sk.getCastRange() <= 200)
  432. {
  433. skilldata.add(sk);
  434. hasSrange = true;
  435. }
  436. }
  437. }
  438. break;
  439. }
  440. case 1:
  441. {
  442. if (npcData._universalskills != null)
  443. {
  444. for (L2Skill sk: npcData._universalskills)
  445. {
  446. if (sk.getCastRange() <= 200)
  447. {
  448. skilldata.add(sk);
  449. hasSrange = true;
  450. }
  451. }
  452. }
  453. break;
  454. }
  455. default:
  456. {
  457. for (L2Skill sk: getAllSkills())
  458. {
  459. if (sk.getId() == AI.getShortRangeSkill())
  460. {
  461. skilldata.add(sk);
  462. hasSrange = true;
  463. }
  464. }
  465. }
  466. }
  467. return (hasSrange ? skilldata : null);
  468. }
  469. /** Task launching the function onRandomAnimation() */
  470. protected class RandomAnimationTask implements Runnable
  471. {
  472. public void run()
  473. {
  474. try
  475. {
  476. if (this != _rAniTask)
  477. return; // Shouldn't happen, but who knows... just to make sure every active npc has only one timer.
  478. if (isMob())
  479. {
  480. // Cancel further animation timers until intention is changed to ACTIVE again.
  481. if (getAI().getIntention() != AI_INTENTION_ACTIVE)
  482. return;
  483. }
  484. else
  485. {
  486. if (!isInActiveRegion()) // NPCs in inactive region don't run this task
  487. return;
  488. }
  489. if (!(isDead() || isStunned() || isSleeping() || isParalyzed()))
  490. onRandomAnimation();
  491. startRandomAnimationTimer();
  492. }
  493. catch (Exception e)
  494. {
  495. _log.log(Level.SEVERE, "", e);
  496. }
  497. }
  498. }
  499. /**
  500. * Send a packet SocialAction to all L2PcInstance in the _KnownPlayers of the L2NpcInstance and create a new RandomAnimation Task.<BR><BR>
  501. */
  502. public void onRandomAnimation()
  503. {
  504. // Send a packet SocialAction to all L2PcInstance in the _KnownPlayers of the L2NpcInstance
  505. long now = System.currentTimeMillis();
  506. if (now - _lastSocialBroadcast > _minimalSocialInterval)
  507. {
  508. _lastSocialBroadcast = now;
  509. broadcastPacket(new SocialAction(getObjectId(), Rnd.get(2, 3)));
  510. }
  511. }
  512. /**
  513. * Create a RandomAnimation Task that will be launched after the calculated delay.<BR><BR>
  514. */
  515. public void startRandomAnimationTimer()
  516. {
  517. if (!hasRandomAnimation())
  518. return;
  519. int minWait = isMob() ? Config.MIN_MONSTER_ANIMATION : Config.MIN_NPC_ANIMATION;
  520. int maxWait = isMob() ? Config.MAX_MONSTER_ANIMATION : Config.MAX_NPC_ANIMATION;
  521. // Calculate the delay before the next animation
  522. int interval = Rnd.get(minWait, maxWait) * 1000;
  523. // Create a RandomAnimation Task that will be launched after the calculated delay
  524. _rAniTask = new RandomAnimationTask();
  525. ThreadPoolManager.getInstance().scheduleGeneral(_rAniTask, interval);
  526. }
  527. /**
  528. * Check if the server allows Random Animation.<BR><BR>
  529. */
  530. public boolean hasRandomAnimation()
  531. {
  532. return (Config.MAX_NPC_ANIMATION > 0 && !getTemplate().AI.equals(AIType.CORPSE));
  533. }
  534. /**
  535. * Constructor of L2NpcInstance (use L2Character constructor).<BR><BR>
  536. *
  537. * <B><U> Actions</U> :</B><BR><BR>
  538. * <li>Call the L2Character constructor to set the _template of the L2Character (copy skills from template to object and link _calculators to NPC_STD_CALCULATOR) </li>
  539. * <li>Set the name of the L2Character</li>
  540. * <li>Create a RandomAnimation Task that will be launched after the calculated delay if the server allow it </li><BR><BR>
  541. *
  542. * @param objectId Identifier of the object to initialized
  543. * @param template The L2NpcTemplate to apply to the NPC
  544. *
  545. */
  546. public L2Npc(int objectId, L2NpcTemplate template)
  547. {
  548. // Call the L2Character constructor to set the _template of the L2Character, copy skills from template to object
  549. // and link _calculators to NPC_STD_CALCULATOR
  550. super(objectId, template);
  551. initCharStatusUpdateValues();
  552. // initialize the "current" equipment
  553. _currentLHandId = getTemplate().lhand;
  554. _currentRHandId = getTemplate().rhand;
  555. _currentEnchant = Config.ENABLE_RANDOM_ENCHANT_EFFECT ? Rnd.get(4,21) : getTemplate().enchantEffect;
  556. // initialize the "current" collisions
  557. _currentCollisionHeight = getTemplate().fCollisionHeight;
  558. _currentCollisionRadius = getTemplate().fCollisionRadius;
  559. if (template == null)
  560. {
  561. _log.severe("No template for Npc. Please check your datapack is setup correctly.");
  562. return;
  563. }
  564. // Set the name of the L2Character
  565. setName(template.name);
  566. }
  567. @Override
  568. public NpcKnownList getKnownList()
  569. {
  570. return (NpcKnownList) super.getKnownList();
  571. }
  572. @Override
  573. public void initKnownList()
  574. {
  575. setKnownList(new NpcKnownList(this));
  576. }
  577. @Override
  578. public NpcStat getStat()
  579. {
  580. return (NpcStat) super.getStat();
  581. }
  582. @Override
  583. public void initCharStat()
  584. {
  585. setStat(new NpcStat(this));
  586. }
  587. @Override
  588. public NpcStatus getStatus()
  589. {
  590. return (NpcStatus) super.getStatus();
  591. }
  592. @Override
  593. public void initCharStatus()
  594. {
  595. setStatus(new NpcStatus(this));
  596. }
  597. /** Return the L2NpcTemplate of the L2NpcInstance. */
  598. @Override
  599. public final L2NpcTemplate getTemplate()
  600. {
  601. return (L2NpcTemplate) super.getTemplate();
  602. }
  603. /**
  604. * Return the generic Identifier of this L2NpcInstance contained in the L2NpcTemplate.<BR><BR>
  605. */
  606. public int getNpcId()
  607. {
  608. return getTemplate().npcId;
  609. }
  610. @Override
  611. public boolean isAttackable()
  612. {
  613. return Config.ALT_ATTACKABLE_NPCS;
  614. }
  615. /**
  616. * Return the faction Identifier of this L2NpcInstance contained in the L2NpcTemplate.<BR><BR>
  617. *
  618. * <B><U> Concept</U> :</B><BR><BR>
  619. * If a NPC belows to a Faction, other NPC of the faction inside the Faction range will help it if it's attacked<BR><BR>
  620. *
  621. */
  622. public final String getFactionId()
  623. {
  624. return getTemplate().factionId;
  625. }
  626. /**
  627. * Return the Level of this L2NpcInstance contained in the L2NpcTemplate.<BR><BR>
  628. */
  629. @Override
  630. public final int getLevel()
  631. {
  632. return getTemplate().level;
  633. }
  634. /**
  635. * Return True if the L2NpcInstance is agressive (ex : L2MonsterInstance in function of aggroRange).<BR><BR>
  636. */
  637. public boolean isAggressive()
  638. {
  639. return false;
  640. }
  641. /**
  642. * Return the Aggro Range of this L2NpcInstance contained in the L2NpcTemplate.<BR><BR>
  643. */
  644. public int getAggroRange()
  645. {
  646. return getTemplate().aggroRange;
  647. }
  648. /**
  649. * Return the Faction Range of this L2NpcInstance contained in the L2NpcTemplate.<BR><BR>
  650. */
  651. public int getFactionRange()
  652. {
  653. return getTemplate().factionRange;
  654. }
  655. /**
  656. * Return True if this L2NpcInstance is undead in function of the L2NpcTemplate.<BR><BR>
  657. */
  658. @Override
  659. public boolean isUndead()
  660. {
  661. return getTemplate().isUndead;
  662. }
  663. /**
  664. * Send a packet NpcInfo with state of abnormal effect to all L2PcInstance in the _KnownPlayers of the L2NpcInstance.<BR><BR>
  665. */
  666. @Override
  667. public void updateAbnormalEffect()
  668. {
  669. // Send a Server->Client packet NpcInfo with state of abnormal effect to all L2PcInstance in the _KnownPlayers of the L2NpcInstance
  670. Collection<L2PcInstance> plrs = getKnownList().getKnownPlayers().values();
  671. //synchronized (getKnownList().getKnownPlayers())
  672. {
  673. for (L2PcInstance player : plrs)
  674. {
  675. if (getRunSpeed() == 0)
  676. player.sendPacket(new ServerObjectInfo(this, player));
  677. else
  678. player.sendPacket(new AbstractNpcInfo.NpcInfo(this, player));
  679. }
  680. }
  681. }
  682. /**
  683. * Return the distance under which the object must be add to _knownObject in
  684. * function of the object type.<BR>
  685. * <BR>
  686. *
  687. * <B><U> Values </U> :</B><BR>
  688. * <BR>
  689. * <li> object is a L2FolkInstance : 0 (don't remember it) </li>
  690. * <li> object is a L2Character : 0 (don't remember it) </li>
  691. * <li> object is a L2PlayableInstance : 1500 </li>
  692. * <li> others : 500 </li>
  693. * <BR>
  694. * <BR>
  695. *
  696. * <B><U> Override in </U> :</B><BR>
  697. * <BR>
  698. * <li> L2Attackable</li>
  699. * <BR>
  700. * <BR>
  701. *
  702. * @param object
  703. * The Object to add to _knownObject
  704. *
  705. */
  706. public int getDistanceToWatchObject(L2Object object)
  707. {
  708. if (object instanceof L2FestivalGuideInstance)
  709. return 10000;
  710. if (object instanceof L2NpcInstance || !(object instanceof L2Character))
  711. return 0;
  712. if (object instanceof L2Playable)
  713. return 1500;
  714. return 500;
  715. }
  716. /**
  717. * Return the distance after which the object must be remove from _knownObject in function of the object type.<BR><BR>
  718. *
  719. * <B><U> Values </U> :</B><BR><BR>
  720. * <li> object is not a L2Character : 0 (don't remember it) </li>
  721. * <li> object is a L2FolkInstance : 0 (don't remember it)</li>
  722. * <li> object is a L2PlayableInstance : 3000 </li>
  723. * <li> others : 1000 </li><BR><BR>
  724. *
  725. * <B><U> Overridden in </U> :</B><BR><BR>
  726. * <li> L2Attackable</li><BR><BR>
  727. *
  728. * @param object The Object to remove from _knownObject
  729. *
  730. */
  731. public int getDistanceToForgetObject(L2Object object)
  732. {
  733. return 2 * getDistanceToWatchObject(object);
  734. }
  735. /**
  736. * Return False.<BR><BR>
  737. *
  738. * <B><U> Overridden in </U> :</B><BR><BR>
  739. * <li> L2MonsterInstance : Check if the attacker is not another L2MonsterInstance</li>
  740. * <li> L2PcInstance</li><BR><BR>
  741. */
  742. @Override
  743. public boolean isAutoAttackable(L2Character attacker)
  744. {
  745. return false;
  746. }
  747. /**
  748. * Return the Identifier of the item in the left hand of this L2NpcInstance contained in the L2NpcTemplate.<BR><BR>
  749. */
  750. public int getLeftHandItem()
  751. {
  752. return _currentLHandId;
  753. }
  754. /**
  755. * Return the Identifier of the item in the right hand of this L2NpcInstance contained in the L2NpcTemplate.<BR><BR>
  756. */
  757. public int getRightHandItem()
  758. {
  759. return _currentRHandId;
  760. }
  761. public int getEnchantEffect()
  762. {
  763. return _currentEnchant;
  764. }
  765. /**
  766. * Return the busy status of this L2NpcInstance.<BR><BR>
  767. */
  768. public final boolean isBusy()
  769. {
  770. return _isBusy;
  771. }
  772. /**
  773. * Set the busy status of this L2NpcInstance.<BR><BR>
  774. */
  775. public void setBusy(boolean isBusy)
  776. {
  777. _isBusy = isBusy;
  778. }
  779. /**
  780. * Return the busy message of this L2NpcInstance.<BR><BR>
  781. */
  782. public final String getBusyMessage()
  783. {
  784. return _busyMessage;
  785. }
  786. /**
  787. * Set the busy message of this L2NpcInstance.<BR><BR>
  788. */
  789. public void setBusyMessage(String message)
  790. {
  791. _busyMessage = message;
  792. }
  793. /**
  794. * Return true if this L2Npc instance can be warehouse manager.<BR><BR>
  795. */
  796. public boolean isWarehouse()
  797. {
  798. return false;
  799. }
  800. protected boolean canTarget(L2PcInstance player)
  801. {
  802. if (player.isOutOfControl())
  803. {
  804. player.sendPacket(ActionFailed.STATIC_PACKET);
  805. return false;
  806. }
  807. if (player.isLockedTarget() && player.getLockedTarget() != this)
  808. {
  809. player.sendPacket(new SystemMessage(SystemMessageId.FAILED_CHANGE_TARGET));
  810. player.sendPacket(ActionFailed.STATIC_PACKET);
  811. return false;
  812. }
  813. // TODO: More checks...
  814. return true;
  815. }
  816. public boolean canInteract(L2PcInstance player)
  817. {
  818. // TODO: NPC busy check etc...
  819. if (player.isCastingNow() || player.isCastingSimultaneouslyNow())
  820. return false;
  821. if (player.isDead() || player.isFakeDeath())
  822. return false;
  823. if (player.isSitting())
  824. return false;
  825. if (player.getPrivateStoreType() != 0)
  826. return false;
  827. if (!isInsideRadius(player, INTERACTION_DISTANCE, true, false))
  828. return false;
  829. if (player.getInstanceId() != getInstanceId()
  830. && player.getInstanceId() != -1)
  831. return false;
  832. return true;
  833. }
  834. /**
  835. * Manage actions when a player click on the L2NpcInstance.<BR><BR>
  836. *
  837. * <B><U> Actions on first click on the L2NpcInstance (Select it)</U> :</B><BR><BR>
  838. * <li>Set the L2NpcInstance as target of the L2PcInstance player (if necessary)</li>
  839. * <li>Send a Server->Client packet MyTargetSelected to the L2PcInstance player (display the select window)</li>
  840. * <li>If L2NpcInstance is autoAttackable, send a Server->Client packet StatusUpdate to the L2PcInstance in order to update L2NpcInstance HP bar </li>
  841. * <li>Send a Server->Client packet ValidateLocation to correct the L2NpcInstance position and heading on the client </li><BR><BR>
  842. *
  843. * <B><U> Actions on second click on the L2NpcInstance (Attack it/Intercat with it)</U> :</B><BR><BR>
  844. * <li>Send a Server->Client packet MyTargetSelected to the L2PcInstance player (display the select window)</li>
  845. * <li>If L2NpcInstance is autoAttackable, notify the L2PcInstance AI with AI_INTENTION_ATTACK (after a height verification)</li>
  846. * <li>If L2NpcInstance is NOT autoAttackable, notify the L2PcInstance AI with AI_INTENTION_INTERACT (after a distance verification) and show message</li><BR><BR>
  847. *
  848. * <FONT COLOR=#FF0000><B> <U>Caution</U> : Each group of Server->Client packet must be terminated by a ActionFailed packet in order to avoid
  849. * that client wait an other packet</B></FONT><BR><BR>
  850. *
  851. * <B><U> Example of use </U> :</B><BR><BR>
  852. * <li> Client packet : Action, AttackRequest</li><BR><BR>
  853. *
  854. * <B><U> Overridden in </U> :</B><BR><BR>
  855. * <li> L2ArtefactInstance : Manage only fisrt click to select Artefact</li><BR><BR>
  856. * <li> L2GuardInstance : </li><BR><BR>
  857. *
  858. * @param player The L2PcInstance that start an action on the L2NpcInstance
  859. *
  860. */
  861. @Override
  862. public void onAction(L2PcInstance player, boolean interact)
  863. {
  864. if (!canTarget(player))
  865. return;
  866. player.setLastFolkNPC(this);
  867. // Check if the L2PcInstance already target the L2NpcInstance
  868. if (this != player.getTarget())
  869. {
  870. if (Config.DEBUG)
  871. _log.fine("new target selected:" + getObjectId());
  872. // Set the target of the L2PcInstance player
  873. player.setTarget(this);
  874. // Check if the player is attackable (without a forced attack)
  875. if (isAutoAttackable(player))
  876. {
  877. // Send a Server->Client packet MyTargetSelected to the L2PcInstance player
  878. // The player.getLevel() - getLevel() permit to display the correct color in the select window
  879. MyTargetSelected my = new MyTargetSelected(getObjectId(), player.getLevel() - getLevel());
  880. player.sendPacket(my);
  881. // Send a Server->Client packet StatusUpdate of the L2NpcInstance to the L2PcInstance to update its HP bar
  882. StatusUpdate su = new StatusUpdate(getObjectId());
  883. su.addAttribute(StatusUpdate.CUR_HP, (int) getCurrentHp());
  884. su.addAttribute(StatusUpdate.MAX_HP, getMaxHp());
  885. player.sendPacket(su);
  886. }
  887. else
  888. {
  889. // Send a Server->Client packet MyTargetSelected to the L2PcInstance player
  890. MyTargetSelected my = new MyTargetSelected(getObjectId(), 0);
  891. player.sendPacket(my);
  892. }
  893. // Send a Server->Client packet ValidateLocation to correct the L2NpcInstance position and heading on the client
  894. player.sendPacket(new ValidateLocation(this));
  895. }
  896. else if (interact)
  897. {
  898. player.sendPacket(new ValidateLocation(this));
  899. // Check if the player is attackable (without a forced attack) and isn't dead
  900. if (isAutoAttackable(player) && !isAlikeDead())
  901. {
  902. // Check the height difference
  903. if (Math.abs(player.getZ() - getZ()) < 400) // this max heigth difference might need some tweaking
  904. {
  905. // Set the L2PcInstance Intention to AI_INTENTION_ATTACK
  906. player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
  907. // player.startAttack(this);
  908. }
  909. else
  910. {
  911. // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  912. player.sendPacket(ActionFailed.STATIC_PACKET);
  913. }
  914. }
  915. else if (!isAutoAttackable(player))
  916. {
  917. // Calculate the distance between the L2PcInstance and the L2NpcInstance
  918. if (!canInteract(player))
  919. {
  920. // Notify the L2PcInstance AI with AI_INTENTION_INTERACT
  921. player.getAI().setIntention(CtrlIntention.AI_INTENTION_INTERACT, this);
  922. }
  923. else
  924. {
  925. // Send a Server->Client packet SocialAction to the all L2PcInstance on the _knownPlayer of the L2NpcInstance
  926. // to display a social action of the L2NpcInstance on their client
  927. long now = System.currentTimeMillis();
  928. if (now - _lastSocialBroadcast > _minimalSocialInterval && !getTemplate().AI.equals(AIType.CORPSE))
  929. {
  930. _lastSocialBroadcast = now;
  931. broadcastPacket(new SocialAction(getObjectId(), Rnd.get(8)));
  932. }
  933. // Open a chat window on client with the text of the L2NpcInstance
  934. if (isEventMob)
  935. {
  936. L2Event.showEventHtml(player, String.valueOf(getObjectId()));
  937. }
  938. else
  939. {
  940. Quest[] qlsa = getTemplate().getEventQuests(Quest.QuestEventType.QUEST_START);
  941. if ((qlsa != null) && qlsa.length > 0)
  942. player.setLastQuestNpcObject(getObjectId());
  943. Quest[] qlst = getTemplate().getEventQuests(Quest.QuestEventType.ON_FIRST_TALK);
  944. if ((qlst != null) && qlst.length == 1)
  945. qlst[0].notifyFirstTalk(this, player);
  946. else
  947. showChatWindow(player);
  948. }
  949. }
  950. }
  951. }
  952. player.sendPacket(ActionFailed.STATIC_PACKET);
  953. }
  954. /**
  955. * Manage and Display the GM console to modify the L2NpcInstance (GM only).<BR><BR>
  956. *
  957. * <B><U> Actions (If the L2PcInstance is a GM only)</U> :</B><BR><BR>
  958. * <li>Set the L2NpcInstance as target of the L2PcInstance player (if necessary)</li>
  959. * <li>Send a Server->Client packet MyTargetSelected to the L2PcInstance player (display the select window)</li>
  960. * <li>If L2NpcInstance is autoAttackable, send a Server->Client packet StatusUpdate to the L2PcInstance in order to update L2NpcInstance HP bar </li>
  961. * <li>Send a Server->Client NpcHtmlMessage() containing the GM console about this L2NpcInstance </li><BR><BR>
  962. *
  963. * <FONT COLOR=#FF0000><B> <U>Caution</U> : Each group of Server->Client packet must be terminated by a ActionFailed packet in order to avoid
  964. * that client wait an other packet</B></FONT><BR><BR>
  965. *
  966. * <B><U> Example of use </U> :</B><BR><BR>
  967. * <li> Client packet : Action</li><BR><BR>
  968. *
  969. * @param client The thread that manage the player that pessed Shift and click on the L2NpcInstance
  970. *
  971. */
  972. @Override
  973. public void onActionShift(L2PcInstance player)
  974. {
  975. if (player == null)
  976. return;
  977. // Check if the L2PcInstance is a GM
  978. if (player.getAccessLevel().isGm())
  979. {
  980. // Set the target of the L2PcInstance player
  981. player.setTarget(this);
  982. // Send a Server->Client packet MyTargetSelected to the L2PcInstance player
  983. // The player.getLevel() - getLevel() permit to display the correct color in the select window
  984. MyTargetSelected my = new MyTargetSelected(getObjectId(), player.getLevel() - getLevel());
  985. player.sendPacket(my);
  986. // Check if the player is attackable (without a forced attack)
  987. if (isAutoAttackable(player))
  988. {
  989. // Send a Server->Client packet StatusUpdate of the L2NpcInstance to the L2PcInstance to update its HP bar
  990. StatusUpdate su = new StatusUpdate(getObjectId());
  991. su.addAttribute(StatusUpdate.CUR_HP, (int) getCurrentHp());
  992. su.addAttribute(StatusUpdate.MAX_HP, getMaxHp());
  993. player.sendPacket(su);
  994. }
  995. // Send a Server->Client NpcHtmlMessage() containing the GM console about this L2NpcInstance
  996. NpcHtmlMessage html = new NpcHtmlMessage(0);
  997. final StringBuilder html1 = StringUtil.startAppend(500,
  998. "<html><body><center><font color=\"LEVEL\">NPC Info</font></center><br>" +
  999. "Instance Type: ",
  1000. getClass().getSimpleName(),
  1001. "<br1>Faction: ",
  1002. getFactionId() != null ? getFactionId() : "null"
  1003. );
  1004. StringUtil.append(html1,
  1005. "<br1>Coords: ",
  1006. String.valueOf(getX()),
  1007. ", ",
  1008. String.valueOf(getY()),
  1009. ", ",
  1010. String.valueOf(getZ())
  1011. );
  1012. if (getSpawn() != null)
  1013. StringUtil.append(html1,
  1014. "<br1>Spawn: ",
  1015. String.valueOf(getSpawn().getLocx()),
  1016. ", ",
  1017. String.valueOf(getSpawn().getLocy()),
  1018. ", ",
  1019. String.valueOf(getSpawn().getLocz()),
  1020. " ; Loc ID: ",
  1021. String.valueOf(getSpawn().getLocation()),
  1022. "<br1>Distance from spawn 2D: ",
  1023. String.valueOf((int)Math.sqrt(getPlanDistanceSq(getSpawn().getLocx(), getSpawn().getLocy()))),
  1024. " ; 3D: ",
  1025. String.valueOf((int)Math.sqrt(getDistanceSq(getSpawn().getLocx(), getSpawn().getLocy(), getSpawn().getLocz())))
  1026. );
  1027. if (this instanceof L2ControllableMobInstance)
  1028. {
  1029. StringUtil.append(html1,
  1030. "<br1>Mob Group: ",
  1031. String.valueOf(MobGroupTable.getInstance().getGroupForMob((L2ControllableMobInstance) this).getGroupId()),
  1032. "<br>"
  1033. );
  1034. }
  1035. else
  1036. {
  1037. StringUtil.append(html1,
  1038. "<br1>Respawn Time: ",
  1039. (getSpawn() != null ? String.valueOf(getSpawn().getRespawnDelay() / 1000) : "?"),
  1040. " Seconds<br>"
  1041. );
  1042. }
  1043. StringUtil.append(html1,
  1044. "<table border=\"0\" width=\"100%\">" +
  1045. "<tr><td>Level</td><td>",
  1046. String.valueOf(getLevel()),
  1047. "</td><td> </td><td>NPC ID</td><td>",
  1048. String.valueOf(getTemplate().npcId),
  1049. "</td></tr>" +
  1050. "<tr><td>Aggro</td><td>" +
  1051. String.valueOf((this instanceof L2Attackable) ? ((L2Attackable) this).getAggroRange() : 0),
  1052. "</td><td> </td><td>Object ID</td><td>",
  1053. String.valueOf(getObjectId()),
  1054. "</td></tr>" +
  1055. "<tr><td>Castle</td><td>",
  1056. String.valueOf(getCastle().getCastleId()),
  1057. "</td><td> </td><td>AI </td><td>",
  1058. (hasAI() ? String.valueOf(getAI().getIntention().name()) : "NULL"),
  1059. "</td></tr>" +
  1060. "</table><br>" +
  1061. "<font color=\"LEVEL\">Combat</font>" +
  1062. "<table border=\"0\" width=\"100%\">" +
  1063. "<tr><td>Current HP</td><td>",
  1064. String.valueOf(getCurrentHp()),
  1065. "</td><td>Current MP</td><td>",
  1066. String.valueOf(getCurrentMp()),
  1067. "</td></tr>" +
  1068. "<tr><td>Max.HP</td><td>",
  1069. String.valueOf((int) (getMaxHp() / getStat().calcStat(Stats.MAX_HP, 1, this, null))),
  1070. "*",
  1071. String.valueOf((int) (getStat().calcStat(Stats.MAX_HP, 1, this, null))),
  1072. "</td><td>Max.MP</td><td>",
  1073. String.valueOf(getMaxMp()),
  1074. "</td></tr>" +
  1075. "<tr><td>P.Atk.</td><td>",
  1076. String.valueOf(getPAtk(null)),
  1077. "</td><td>M.Atk.</td><td>",
  1078. String.valueOf(getMAtk(null, null)),
  1079. "</td></tr>" +
  1080. "<tr><td>P.Def.</td><td>",
  1081. String.valueOf(getPDef(null)),
  1082. "</td><td>M.Def.</td><td>",
  1083. String.valueOf(getMDef(null, null)),
  1084. "</td></tr>" +
  1085. "<tr><td>Accuracy</td><td>" +
  1086. String.valueOf(getAccuracy()),
  1087. "</td><td>Evasion</td><td>",
  1088. String.valueOf(getEvasionRate(null)),
  1089. "</td></tr>" +
  1090. "<tr><td>Critical</td><td>",
  1091. String.valueOf(getCriticalHit(null, null)),
  1092. "</td><td>Speed</td><td>",
  1093. String.valueOf(getRunSpeed()),
  1094. "</td></tr>" +
  1095. "<tr><td>Atk.Speed</td><td>",
  1096. String.valueOf(getPAtkSpd()),
  1097. "</td><td>Cast.Speed</td><td>",
  1098. String.valueOf(getMAtkSpd()),
  1099. "</td></tr>" +
  1100. "</table><br>" +
  1101. "<font color=\"LEVEL\">Basic Stats</font>" +
  1102. "<table border=\"0\" width=\"100%\">" +
  1103. "<tr><td>STR</td><td>",
  1104. String.valueOf(getSTR()),
  1105. "</td><td>DEX</td><td>",
  1106. String.valueOf(getDEX()),
  1107. "</td><td>CON</td><td>",
  1108. String.valueOf(getCON()),
  1109. "</td></tr>" +
  1110. "<tr><td>INT</td><td>",
  1111. String.valueOf(getINT()),
  1112. "</td><td>WIT</td><td>",
  1113. String.valueOf(getWIT()),
  1114. "</td><td>MEN</td><td>",
  1115. String.valueOf(getMEN()),
  1116. "</td></tr>" +
  1117. "</table>" +
  1118. "<br><center><table><tr><td><button value=\"Edit NPC\" action=\"bypass -h admin_edit_npc ",
  1119. String.valueOf(getTemplate().npcId),
  1120. "\" width=100 height=20 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"><br1></td>" +
  1121. "<td><button value=\"Kill\" action=\"bypass -h admin_kill\" width=40 height=20 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td><br1></tr>" +
  1122. "<tr><td><button value=\"Show DropList\" action=\"bypass -h admin_show_droplist ",
  1123. String.valueOf(getTemplate().npcId),
  1124. "\" width=100 height=20 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td></tr>" +
  1125. "<td><button value=\"Delete\" action=\"bypass -h admin_delete\" width=40 height=20 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td></tr>" +
  1126. "<tr><td><button value=\"Show SkillList\" action=\"bypass -h admin_show_skilllist_npc ",
  1127. String.valueOf(getTemplate().npcId),
  1128. "\" width=100 height=20 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td><td></td></tr></table></center><br></body></html>"
  1129. );
  1130. html.setHtml(html1.toString());
  1131. player.sendPacket(html);
  1132. }
  1133. else if (Config.ALT_GAME_VIEWNPC)
  1134. {
  1135. // Set the target of the L2PcInstance player
  1136. player.setTarget(this);
  1137. // Send a Server->Client packet MyTargetSelected to the L2PcInstance player
  1138. // The player.getLevel() - getLevel() permit to display the correct color in the select window
  1139. MyTargetSelected my = new MyTargetSelected(getObjectId(), player.getLevel() - getLevel());
  1140. player.sendPacket(my);
  1141. // Check if the player is attackable (without a forced attack)
  1142. if (isAutoAttackable(player))
  1143. {
  1144. // Send a Server->Client packet StatusUpdate of the L2NpcInstance to the L2PcInstance to update its HP bar
  1145. StatusUpdate su = new StatusUpdate(getObjectId());
  1146. su.addAttribute(StatusUpdate.CUR_HP, (int) getCurrentHp());
  1147. su.addAttribute(StatusUpdate.MAX_HP, getMaxHp());
  1148. player.sendPacket(su);
  1149. }
  1150. NpcHtmlMessage html = new NpcHtmlMessage(0);
  1151. final StringBuilder html1 = StringUtil.startAppend(
  1152. 1000,
  1153. "<html><body>" +
  1154. "<br><center><font color=\"LEVEL\">[Combat Stats]</font></center>" +
  1155. "<table border=0 width=\"100%\">" +
  1156. "<tr><td>Max.HP</td><td>",
  1157. String.valueOf((int) (getMaxHp() / getStat().calcStat(Stats.MAX_HP, 1, this, null))),
  1158. "*",
  1159. String.valueOf((int) getStat().calcStat(Stats.MAX_HP, 1, this, null)),
  1160. "</td><td>Max.MP</td><td>",
  1161. String.valueOf(getMaxMp()),
  1162. "</td></tr>" +
  1163. "<tr><td>P.Atk.</td><td>",
  1164. String.valueOf(getPAtk(null)),
  1165. "</td><td>M.Atk.</td><td>",
  1166. String.valueOf(getMAtk(null, null)),
  1167. "</td></tr>" +
  1168. "<tr><td>P.Def.</td><td>",
  1169. String.valueOf(getPDef(null)),
  1170. "</td><td>M.Def.</td><td>",
  1171. String.valueOf(getMDef(null, null)),
  1172. "</td></tr>" +
  1173. "<tr><td>Accuracy</td><td>",
  1174. String.valueOf(getAccuracy()),
  1175. "</td><td>Evasion</td><td>",
  1176. String.valueOf(getEvasionRate(null)),
  1177. "</td></tr>" +
  1178. "<tr><td>Critical</td><td>",
  1179. String.valueOf(getCriticalHit(null, null)),
  1180. "</td><td>Speed</td><td>",
  1181. String.valueOf(getRunSpeed()),
  1182. "</td></tr>" +
  1183. "<tr><td>Atk.Speed</td><td>",
  1184. String.valueOf(getPAtkSpd()),
  1185. "</td><td>Cast.Speed</td><td>",
  1186. String.valueOf(getMAtkSpd()),
  1187. "</td></tr>" +
  1188. "<tr><td>Race</td><td>",
  1189. getTemplate().getRace().toString(),
  1190. "</td><td></td><td></td></tr>" +
  1191. "</table>" +
  1192. "<br><center><font color=\"LEVEL\">[Basic Stats]</font></center>" +
  1193. "<table border=0 width=\"100%\">" +
  1194. "<tr><td>STR</td><td>",
  1195. String.valueOf(getSTR()),
  1196. "</td><td>DEX</td><td>",
  1197. String.valueOf(getDEX()),
  1198. "</td><td>CON</td><td>",
  1199. String.valueOf(getCON()),
  1200. "</td></tr>" +
  1201. "<tr><td>INT</td><td>",
  1202. String.valueOf(getINT()),
  1203. "</td><td>WIT</td><td>",
  1204. String.valueOf(getWIT()),
  1205. "</td><td>MEN</td><td>",
  1206. String.valueOf(getMEN()),
  1207. "</td></tr>" +
  1208. "</table>"
  1209. );
  1210. if (getTemplate().getDropData() != null)
  1211. {
  1212. StringUtil.append(html1,
  1213. "<br><center><font color=\"LEVEL\">[Drop Info]</font></center>" +
  1214. "<br>Rates legend: <font color=\"ff0000\">50%+</font> <font color=\"00ff00\">30%+</font> <font color=\"0000ff\">less than 30%</font>" +
  1215. "<table border=0 width=\"100%\">"
  1216. );
  1217. for (L2DropCategory cat : getTemplate().getDropData())
  1218. {
  1219. for (L2DropData drop : cat.getAllDrops())
  1220. {
  1221. final L2Item item = ItemTable.getInstance().getTemplate(drop.getItemId());
  1222. if (item == null)
  1223. continue;
  1224. final String color;
  1225. if (drop.getChance() >= 500000)
  1226. color = "ff0000";
  1227. else if (drop.getChance() >= 300000)
  1228. color = "00ff00";
  1229. else
  1230. color = "0000ff";
  1231. StringUtil.append(html1,
  1232. "<tr><td><font color=\"",
  1233. color,
  1234. "\">",
  1235. item.getName(),
  1236. "</font></td><td>",
  1237. (drop.isQuestDrop() ? "Quest" : (cat.isSweep() ? "Sweep" : "Drop")),
  1238. "</td></tr>"
  1239. );
  1240. }
  1241. }
  1242. html1.append("</table>");
  1243. }
  1244. html1.append("</body></html>");
  1245. html.setHtml(html1.toString());
  1246. player.sendPacket(html);
  1247. }
  1248. // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  1249. player.sendPacket(ActionFailed.STATIC_PACKET);
  1250. }
  1251. /** Return the L2Castle this L2NpcInstance belongs to. */
  1252. public final Castle getCastle()
  1253. {
  1254. // Get castle this NPC belongs to (excluding L2Attackable)
  1255. if (_castleIndex < 0)
  1256. {
  1257. L2TownZone town = TownManager.getTown(getX(), getY(), getZ());
  1258. if (town != null)
  1259. _castleIndex = CastleManager.getInstance().getCastleIndex(town.getTaxById());
  1260. if (_castleIndex < 0)
  1261. {
  1262. _castleIndex = CastleManager.getInstance().findNearestCastleIndex(this);
  1263. }
  1264. else
  1265. _isInTown = true; // Npc was spawned in town
  1266. }
  1267. if (_castleIndex < 0)
  1268. return null;
  1269. return CastleManager.getInstance().getCastles().get(_castleIndex);
  1270. }
  1271. /** Return the L2Fort this L2NpcInstance belongs to. */
  1272. public final Fort getFort()
  1273. {
  1274. // Get Fort this NPC belongs to (excluding L2Attackable)
  1275. if (_fortIndex < 0)
  1276. {
  1277. Fort fort = FortManager.getInstance().getFort(getX(), getY(), getZ());
  1278. if (fort != null)
  1279. _fortIndex = FortManager.getInstance().getFortIndex(fort.getFortId());
  1280. if (_fortIndex < 0)
  1281. _fortIndex = FortManager.getInstance().findNearestFortIndex(this);
  1282. }
  1283. if (_fortIndex < 0)
  1284. return null;
  1285. return FortManager.getInstance().getForts().get(_fortIndex);
  1286. }
  1287. public final boolean getIsInTown()
  1288. {
  1289. if (_castleIndex < 0)
  1290. getCastle();
  1291. return _isInTown;
  1292. }
  1293. /**
  1294. * Open a quest or chat window on client with the text of the L2NpcInstance in function of the command.<BR><BR>
  1295. *
  1296. * <B><U> Example of use </U> :</B><BR><BR>
  1297. * <li> Client packet : RequestBypassToServer</li><BR><BR>
  1298. *
  1299. * @param command The command string received from client
  1300. *
  1301. */
  1302. public void onBypassFeedback(L2PcInstance player, String command)
  1303. {
  1304. //if (canInteract(player))
  1305. {
  1306. if (isBusy() && getBusyMessage().length() > 0)
  1307. {
  1308. player.sendPacket(ActionFailed.STATIC_PACKET);
  1309. NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  1310. html.setFile("data/html/npcbusy.htm");
  1311. html.replace("%busymessage%", getBusyMessage());
  1312. html.replace("%npcname%", getName());
  1313. html.replace("%playername%", player.getName());
  1314. player.sendPacket(html);
  1315. }
  1316. else if (command.equalsIgnoreCase("TerritoryStatus"))
  1317. {
  1318. NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  1319. {
  1320. if (getCastle().getOwnerId() > 0)
  1321. {
  1322. html.setFile("data/html/territorystatus.htm");
  1323. L2Clan clan = ClanTable.getInstance().getClan(getCastle().getOwnerId());
  1324. html.replace("%clanname%", clan.getName());
  1325. html.replace("%clanleadername%", clan.getLeaderName());
  1326. }
  1327. else
  1328. {
  1329. html.setFile("data/html/territorynoclan.htm");
  1330. }
  1331. }
  1332. html.replace("%castlename%", getCastle().getName());
  1333. html.replace("%taxpercent%", "" + getCastle().getTaxPercent());
  1334. html.replace("%objectId%", String.valueOf(getObjectId()));
  1335. {
  1336. if (getCastle().getCastleId() > 6)
  1337. {
  1338. html.replace("%territory%", "The Kingdom of Elmore");
  1339. }
  1340. else
  1341. {
  1342. html.replace("%territory%", "The Kingdom of Aden");
  1343. }
  1344. }
  1345. player.sendPacket(html);
  1346. }
  1347. else if (command.startsWith("Quest"))
  1348. {
  1349. String quest = "";
  1350. try
  1351. {
  1352. quest = command.substring(5).trim();
  1353. }
  1354. catch (IndexOutOfBoundsException ioobe)
  1355. {
  1356. }
  1357. if (quest.length() == 0)
  1358. showQuestWindow(player);
  1359. else
  1360. showQuestWindow(player, quest);
  1361. }
  1362. else if (command.startsWith("Chat"))
  1363. {
  1364. int val = 0;
  1365. try
  1366. {
  1367. val = Integer.parseInt(command.substring(5));
  1368. }
  1369. catch (IndexOutOfBoundsException ioobe)
  1370. {
  1371. }
  1372. catch (NumberFormatException nfe)
  1373. {
  1374. }
  1375. showChatWindow(player, val);
  1376. }
  1377. else if (command.startsWith("Link"))
  1378. {
  1379. String path = command.substring(5).trim();
  1380. if (path.indexOf("..") != -1)
  1381. return;
  1382. String filename = "data/html/" + path;
  1383. NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  1384. html.setFile(filename);
  1385. html.replace("%objectId%", String.valueOf(getObjectId()));
  1386. player.sendPacket(html);
  1387. }
  1388. else if (command.startsWith("NobleTeleport"))
  1389. {
  1390. if (!player.isNoble())
  1391. {
  1392. String filename = "data/html/teleporter/nobleteleporter-no.htm";
  1393. NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  1394. html.setFile(filename);
  1395. html.replace("%objectId%", String.valueOf(getObjectId()));
  1396. html.replace("%npcname%", getName());
  1397. player.sendPacket(html);
  1398. return;
  1399. }
  1400. int val = 0;
  1401. try
  1402. {
  1403. val = Integer.parseInt(command.substring(5));
  1404. }
  1405. catch (IndexOutOfBoundsException ioobe)
  1406. {
  1407. }
  1408. catch (NumberFormatException nfe)
  1409. {
  1410. }
  1411. showChatWindow(player, val);
  1412. }
  1413. else if (command.startsWith("Loto"))
  1414. {
  1415. int val = 0;
  1416. try
  1417. {
  1418. val = Integer.parseInt(command.substring(5));
  1419. }
  1420. catch (IndexOutOfBoundsException ioobe)
  1421. {
  1422. }
  1423. catch (NumberFormatException nfe)
  1424. {
  1425. }
  1426. if (val == 0)
  1427. {
  1428. // new loto ticket
  1429. for (int i = 0; i < 5; i++)
  1430. player.setLoto(i, 0);
  1431. }
  1432. showLotoWindow(player, val);
  1433. }
  1434. else if (command.startsWith("CPRecovery"))
  1435. {
  1436. makeCPRecovery(player);
  1437. }
  1438. else if (command.startsWith("SupportMagicServitor"))
  1439. {
  1440. makeSupportMagic(player,true);
  1441. }
  1442. else if (command.startsWith("SupportMagic"))
  1443. {
  1444. makeSupportMagic(player,false);
  1445. }
  1446. else if (command.startsWith("GiveBlessing"))
  1447. {
  1448. giveBlessingSupport(player);
  1449. }
  1450. else if (command.startsWith("multisell"))
  1451. {
  1452. int listId = Integer.parseInt(command.substring(9).trim());
  1453. L2Multisell.getInstance().separateAndSend(listId, player, getNpcId(), false, getCastle().getTaxRate());
  1454. }
  1455. else if (command.startsWith("exc_multisell"))
  1456. {
  1457. int listId = Integer.parseInt(command.substring(13).trim());
  1458. L2Multisell.getInstance().separateAndSend(listId, player, getNpcId(), true, getCastle().getTaxRate());
  1459. }
  1460. else if (command.startsWith("Augment"))
  1461. {
  1462. int cmdChoice = Integer.parseInt(command.substring(8, 9).trim());
  1463. switch (cmdChoice)
  1464. {
  1465. case 1:
  1466. player.sendPacket(new ExShowVariationMakeWindow());
  1467. break;
  1468. case 2:
  1469. player.sendPacket(new ExShowVariationCancelWindow());
  1470. break;
  1471. }
  1472. }
  1473. else if (command.startsWith("npcfind_byid"))
  1474. {
  1475. try
  1476. {
  1477. L2Spawn spawn = SpawnTable.getInstance().getTemplate(Integer.parseInt(command.substring(12).trim()));
  1478. if (spawn != null)
  1479. {
  1480. player.sendPacket(new RadarControl(2, 2, spawn.getLocx(), spawn.getLocy(), spawn.getLocz()));
  1481. player.sendPacket(new RadarControl(0, 1, spawn.getLocx(), spawn.getLocy(), spawn.getLocz()));
  1482. }
  1483. }
  1484. catch (NumberFormatException nfe)
  1485. {
  1486. player.sendMessage("Wrong command parameters");
  1487. }
  1488. }
  1489. else if (command.startsWith("EnterRift"))
  1490. {
  1491. try
  1492. {
  1493. Byte b1 = Byte.parseByte(command.substring(10)); // Selected Area: Recruit, Soldier etc
  1494. DimensionalRiftManager.getInstance().start(player, b1, this);
  1495. }
  1496. catch (Exception e)
  1497. {
  1498. }
  1499. }
  1500. else if (command.startsWith("ChangeRiftRoom"))
  1501. {
  1502. if (player.isInParty() && player.getParty().isInDimensionalRift())
  1503. {
  1504. player.getParty().getDimensionalRift().manualTeleport(player, this);
  1505. }
  1506. else
  1507. {
  1508. DimensionalRiftManager.getInstance().handleCheat(player, this);
  1509. }
  1510. }
  1511. else if (command.startsWith("remove_dp"))
  1512. {
  1513. int cmdChoice = Integer.parseInt(command.substring(10, 11).trim());
  1514. int[] pen_clear_price =
  1515. {
  1516. 3600, 8640, 25200, 50400, 86400, 144000, 144000, 144000
  1517. };
  1518. switch (cmdChoice)
  1519. {
  1520. case 1:
  1521. String filename = "data/html/default/30981-1.htm";
  1522. NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  1523. html.setFile(filename);
  1524. html.replace("%objectId%", String.valueOf(getObjectId()));
  1525. html.replace("%dp_price%", String.valueOf(pen_clear_price[player.getExpertiseIndex()]));
  1526. player.sendPacket(html);
  1527. break;
  1528. case 2:
  1529. NpcHtmlMessage Reply = new NpcHtmlMessage(getObjectId());
  1530. final StringBuilder replyMSG = StringUtil.startAppend(400,
  1531. "<html><body>Black Judge:<br>"
  1532. );
  1533. if (player.getDeathPenaltyBuffLevel() > 0)
  1534. {
  1535. if (player.getAdena() >= pen_clear_price[player.getExpertiseIndex()])
  1536. {
  1537. if (!player.reduceAdena("DeathPenality", pen_clear_price[player.getExpertiseIndex()], this, true))
  1538. return;
  1539. player.setDeathPenaltyBuffLevel(player.getDeathPenaltyBuffLevel() - 1);
  1540. player.sendPacket(new SystemMessage(SystemMessageId.DEATH_PENALTY_LIFTED));
  1541. player.sendPacket(new EtcStatusUpdate(player));
  1542. return;
  1543. }
  1544. else
  1545. {
  1546. replyMSG.append("The wound you have received from death's touch is too deep to be healed for the money you have to give me. Find more money if you wish death's mark to be fully removed from you.");
  1547. }
  1548. }
  1549. else
  1550. {
  1551. replyMSG.append("You have no more death wounds that require healing.<br>" +
  1552. "Go forth and fight, both for this world and your own glory.");
  1553. }
  1554. replyMSG.append("</body></html>");
  1555. Reply.setHtml(replyMSG.toString());
  1556. player.sendPacket(Reply);
  1557. break;
  1558. }
  1559. }
  1560. else if (command.startsWith("ExitRift"))
  1561. {
  1562. if (player.isInParty() && player.getParty().isInDimensionalRift())
  1563. {
  1564. player.getParty().getDimensionalRift().manualExitRift(player, this);
  1565. }
  1566. else
  1567. {
  1568. DimensionalRiftManager.getInstance().handleCheat(player, this);
  1569. }
  1570. }
  1571. else if (command.startsWith("ReleaseAttribute"))
  1572. {
  1573. player.sendPacket(new ExShowBaseAttributeCancelWindow(player));
  1574. }
  1575. else
  1576. {
  1577. _log.info(getClass().getSimpleName()+": Unknown NPC bypass: \""+command+"\" NpcId: "+getNpcId());
  1578. }
  1579. }
  1580. }
  1581. /**
  1582. * Return null (regular NPCs don't have weapons instancies).<BR><BR>
  1583. */
  1584. @Override
  1585. public L2ItemInstance getActiveWeaponInstance()
  1586. {
  1587. // regular NPCs dont have weapons instancies
  1588. return null;
  1589. }
  1590. /**
  1591. * Return the weapon item equiped in the right hand of the L2NpcInstance or null.<BR><BR>
  1592. */
  1593. @Override
  1594. public L2Weapon getActiveWeaponItem()
  1595. {
  1596. // Get the weapon identifier equiped in the right hand of the L2NpcInstance
  1597. int weaponId = getTemplate().rhand;
  1598. if (weaponId < 1)
  1599. return null;
  1600. // Get the weapon item equiped in the right hand of the L2NpcInstance
  1601. L2Item item = ItemTable.getInstance().getTemplate(getTemplate().rhand);
  1602. if (!(item instanceof L2Weapon))
  1603. return null;
  1604. return (L2Weapon) item;
  1605. }
  1606. public void giveBlessingSupport(L2PcInstance player)
  1607. {
  1608. if (player == null)
  1609. return;
  1610. // Blessing of protection - author kerberos_20. Used codes from Rayan - L2Emu project.
  1611. // Prevent a cursed weapon weilder of being buffed - I think no need of that becouse karma check > 0
  1612. // if (player.isCursedWeaponEquiped())
  1613. // return;
  1614. int player_level = player.getLevel();
  1615. // Select the player
  1616. setTarget(player);
  1617. // If the player is too high level, display a message and return
  1618. if (player_level > 39 || player.getClassId().level() >= 2)
  1619. {
  1620. String content = "<html><body>Newbie Guide:<br>I'm sorry, but you are not eligible to receive the protection blessing.<br1>It can only be bestowed on <font color=\"LEVEL\">characters below level 39 who have not made a seccond transfer.</font></body></html>";
  1621. insertObjectIdAndShowChatWindow(player, content);
  1622. return;
  1623. }
  1624. L2Skill skill = SkillTable.getInstance().getInfo(5182, 1);
  1625. doCast(skill);
  1626. }
  1627. /**
  1628. * Return null (regular NPCs don't have weapons instancies).<BR><BR>
  1629. */
  1630. @Override
  1631. public L2ItemInstance getSecondaryWeaponInstance()
  1632. {
  1633. // regular NPCs dont have weapons instancies
  1634. return null;
  1635. }
  1636. /**
  1637. * Return the weapon item equiped in the left hand of the L2NpcInstance or null.<BR><BR>
  1638. */
  1639. @Override
  1640. public L2Weapon getSecondaryWeaponItem()
  1641. {
  1642. // Get the weapon identifier equiped in the right hand of the L2NpcInstance
  1643. int weaponId = getTemplate().lhand;
  1644. if (weaponId < 1)
  1645. return null;
  1646. // Get the weapon item equiped in the right hand of the L2NpcInstance
  1647. L2Item item = ItemTable.getInstance().getTemplate(getTemplate().lhand);
  1648. if (!(item instanceof L2Weapon))
  1649. return null;
  1650. return (L2Weapon) item;
  1651. }
  1652. /**
  1653. * Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in order to display the message of the L2NpcInstance.<BR><BR>
  1654. *
  1655. * @param player The L2PcInstance who talks with the L2NpcInstance
  1656. * @param content The text of the L2NpcMessage
  1657. *
  1658. */
  1659. public void insertObjectIdAndShowChatWindow(L2PcInstance player, String content)
  1660. {
  1661. // Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in order to display the message of the L2NpcInstance
  1662. content = content.replaceAll("%objectId%", String.valueOf(getObjectId()));
  1663. NpcHtmlMessage npcReply = new NpcHtmlMessage(getObjectId());
  1664. npcReply.setHtml(content);
  1665. player.sendPacket(npcReply);
  1666. }
  1667. /**
  1668. * Return the pathfile of the selected HTML file in function of the npcId and of the page number.<BR><BR>
  1669. *
  1670. * <B><U> Format of the pathfile </U> :</B><BR><BR>
  1671. * <li> if the file exists on the server (page number = 0) : <B>data/html/default/12006.htm</B> (npcId-page number)</li>
  1672. * <li> if the file exists on the server (page number > 0) : <B>data/html/default/12006-1.htm</B> (npcId-page number)</li>
  1673. * <li> if the file doesn't exist on the server : <B>data/html/npcdefault.htm</B> (message : "I have nothing to say to you")</li><BR><BR>
  1674. *
  1675. * <B><U> Overridden in </U> :</B><BR><BR>
  1676. * <li> L2GuardInstance : Set the pathfile to data/html/guard/12006-1.htm (npcId-page number)</li><BR><BR>
  1677. *
  1678. * @param npcId The Identifier of the L2NpcInstance whose text must be display
  1679. * @param val The number of the page to display
  1680. *
  1681. */
  1682. public String getHtmlPath(int npcId, int val)
  1683. {
  1684. String pom = "";
  1685. if (val == 0)
  1686. pom = "" + npcId;
  1687. else
  1688. pom = npcId + "-" + val;
  1689. String temp = "data/html/default/" + pom + ".htm";
  1690. if (!Config.LAZY_CACHE)
  1691. {
  1692. // If not running lazy cache the file must be in the cache or it doesnt exist
  1693. if (HtmCache.getInstance().contains(temp))
  1694. return temp;
  1695. }
  1696. else
  1697. {
  1698. if (HtmCache.getInstance().isLoadable(temp))
  1699. return temp;
  1700. }
  1701. // If the file is not found, the standard message "I have nothing to say to you" is returned
  1702. return "data/html/npcdefault.htm";
  1703. }
  1704. /**
  1705. * Open a choose quest window on client with all quests available of the L2NpcInstance.<BR><BR>
  1706. *
  1707. * <B><U> Actions</U> :</B><BR><BR>
  1708. * <li>Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance </li><BR><BR>
  1709. *
  1710. * @param player The L2PcInstance that talk with the L2NpcInstance
  1711. * @param quests The table containing quests of the L2NpcInstance
  1712. *
  1713. */
  1714. public void showQuestChooseWindow(L2PcInstance player, Quest[] quests)
  1715. {
  1716. final StringBuilder sb = StringUtil.startAppend(150,
  1717. "<html><body>"
  1718. );
  1719. for (Quest q : quests)
  1720. {
  1721. StringUtil.append(sb,
  1722. "<a action=\"bypass -h npc_",
  1723. String.valueOf(getObjectId()),
  1724. "_Quest ",
  1725. q.getName(),
  1726. "\">[",
  1727. q.getDescr()
  1728. );
  1729. QuestState qs = player.getQuestState(q.getScriptName());
  1730. if (qs != null)
  1731. {
  1732. if (qs.getState() == State.STARTED && qs.getInt("cond") > 0)
  1733. sb.append(" (In Progress)");
  1734. else if (qs.getState() == State.COMPLETED)
  1735. sb.append(" (Done)");
  1736. }
  1737. sb.append("]</a><br>");
  1738. }
  1739. sb.append("</body></html>");
  1740. // Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in order to display the message of the L2NpcInstance
  1741. insertObjectIdAndShowChatWindow(player, sb.toString());
  1742. }
  1743. /**
  1744. * Open a quest window on client with the text of the L2NpcInstance.<BR><BR>
  1745. *
  1746. * <B><U> Actions</U> :</B><BR><BR>
  1747. * <li>Get the text of the quest state in the folder data/scripts/quests/questId/stateId.htm </li>
  1748. * <li>Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance </li>
  1749. * <li>Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet </li><BR><BR>
  1750. *
  1751. * @param player The L2PcInstance that talk with the L2NpcInstance
  1752. * @param questId The Identifier of the quest to display the message
  1753. *
  1754. */
  1755. public void showQuestWindow(L2PcInstance player, String questId)
  1756. {
  1757. String content = null;
  1758. Quest q = QuestManager.getInstance().getQuest(questId);
  1759. // Get the state of the selected quest
  1760. QuestState qs = player.getQuestState(questId);
  1761. if (q == null)
  1762. {
  1763. // no quests found
  1764. content = "<html><body>You are either not on a quest that involves this NPC, or you don't meet this NPC's minimum quest requirements.</body></html>";
  1765. }
  1766. else
  1767. {
  1768. if ((q.getQuestIntId() >= 1 && q.getQuestIntId() < 20000) && (player.getWeightPenalty() >= 3 || player.getInventoryLimit() * 0.8 <= player.getInventory().getSize()))
  1769. {
  1770. player.sendPacket(new SystemMessage(SystemMessageId.INVENTORY_LESS_THAN_80_PERCENT));
  1771. return;
  1772. }
  1773. if (qs == null)
  1774. {
  1775. if (q.getQuestIntId() >= 1 && q.getQuestIntId() < 20000)
  1776. {
  1777. Quest[] questList = player.getAllActiveQuests();
  1778. if (questList.length >= 25) // if too many ongoing quests, don't show window and send message
  1779. {
  1780. player.sendPacket(new SystemMessage(SystemMessageId.TOO_MANY_QUESTS));
  1781. return;
  1782. }
  1783. }
  1784. // check for start point
  1785. Quest[] qlst = getTemplate().getEventQuests(Quest.QuestEventType.QUEST_START);
  1786. if (qlst != null && qlst.length > 0)
  1787. {
  1788. for (Quest temp : qlst)
  1789. {
  1790. if (temp == q)
  1791. {
  1792. qs = q.newQuestState(player);
  1793. break;
  1794. }
  1795. }
  1796. }
  1797. }
  1798. }
  1799. if (qs != null)
  1800. {
  1801. // If the quest is alreday started, no need to show a window
  1802. if (!qs.getQuest().notifyTalk(this, qs))
  1803. return;
  1804. questId = qs.getQuest().getName();
  1805. String stateId = State.getStateName(qs.getState());
  1806. String path = "data/scripts/quests/" + questId + "/" + stateId + ".htm";
  1807. content = HtmCache.getInstance().getHtm(path); //TODO path for quests html
  1808. if (Config.DEBUG)
  1809. {
  1810. if (content != null)
  1811. {
  1812. _log.fine("Showing quest window for quest " + questId + " html path: " + path);
  1813. }
  1814. else
  1815. {
  1816. _log.fine("File not exists for quest " + questId + " html path: " + path);
  1817. }
  1818. }
  1819. }
  1820. // Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in order to display the message of the L2NpcInstance
  1821. if (content != null)
  1822. insertObjectIdAndShowChatWindow(player, content);
  1823. // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  1824. player.sendPacket(ActionFailed.STATIC_PACKET);
  1825. }
  1826. /**
  1827. * Collect awaiting quests/start points and display a QuestChooseWindow (if several available) or QuestWindow.<BR><BR>
  1828. *
  1829. * @param player The L2PcInstance that talk with the L2NpcInstance
  1830. *
  1831. */
  1832. public void showQuestWindow(L2PcInstance player)
  1833. {
  1834. // collect awaiting quests and start points
  1835. List<Quest> options = new FastList<Quest>();
  1836. QuestState[] awaits = player.getQuestsForTalk(getTemplate().npcId);
  1837. Quest[] starts = getTemplate().getEventQuests(Quest.QuestEventType.QUEST_START);
  1838. // Quests are limited between 1 and 999 because those are the quests that are supported by the client.
  1839. // By limiting them there, we are allowed to create custom quests at higher IDs without interfering
  1840. if (awaits != null)
  1841. {
  1842. for (QuestState x : awaits)
  1843. {
  1844. if (!options.contains(x.getQuest()))
  1845. if ((x.getQuest().getQuestIntId() > 0) && (x.getQuest().getQuestIntId() < 20000))
  1846. options.add(x.getQuest());
  1847. }
  1848. }
  1849. if (starts != null)
  1850. {
  1851. for (Quest x : starts)
  1852. {
  1853. if (!options.contains(x))
  1854. if ((x.getQuestIntId() > 0) && (x.getQuestIntId() < 20000))
  1855. options.add(x);
  1856. }
  1857. }
  1858. // Display a QuestChooseWindow (if several quests are available) or QuestWindow
  1859. if (options.size() > 1)
  1860. {
  1861. showQuestChooseWindow(player, options.toArray(new Quest[options.size()]));
  1862. }
  1863. else if (options.size() == 1)
  1864. {
  1865. showQuestWindow(player, options.get(0).getName());
  1866. }
  1867. else
  1868. {
  1869. showQuestWindow(player, "");
  1870. }
  1871. }
  1872. /**
  1873. * Open a Loto window on client with the text of the L2NpcInstance.<BR><BR>
  1874. *
  1875. * <B><U> Actions</U> :</B><BR><BR>
  1876. * <li>Get the text of the selected HTML file in function of the npcId and of the page number </li>
  1877. * <li>Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance </li>
  1878. * <li>Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet </li><BR>
  1879. *
  1880. * @param player The L2PcInstance that talk with the L2NpcInstance
  1881. * @param val The number of the page of the L2NpcInstance to display
  1882. *
  1883. */
  1884. // 0 - first buy lottery ticket window
  1885. // 1-20 - buttons
  1886. // 21 - second buy lottery ticket window
  1887. // 22 - selected ticket with 5 numbers
  1888. // 23 - current lottery jackpot
  1889. // 24 - Previous winning numbers/Prize claim
  1890. // >24 - check lottery ticket by item object id
  1891. public void showLotoWindow(L2PcInstance player, int val)
  1892. {
  1893. int npcId = getTemplate().npcId;
  1894. String filename;
  1895. SystemMessage sm;
  1896. NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  1897. if (val == 0) // 0 - first buy lottery ticket window
  1898. {
  1899. filename = (getHtmlPath(npcId, 1));
  1900. html.setFile(filename);
  1901. }
  1902. else if (val >= 1 && val <= 21) // 1-20 - buttons, 21 - second buy lottery ticket window
  1903. {
  1904. if (!Lottery.getInstance().isStarted())
  1905. {
  1906. //tickets can't be sold
  1907. player.sendPacket(new SystemMessage(SystemMessageId.NO_LOTTERY_TICKETS_CURRENT_SOLD));
  1908. return;
  1909. }
  1910. if (!Lottery.getInstance().isSellableTickets())
  1911. {
  1912. //tickets can't be sold
  1913. player.sendPacket(new SystemMessage(SystemMessageId.NO_LOTTERY_TICKETS_AVAILABLE));
  1914. return;
  1915. }
  1916. filename = (getHtmlPath(npcId, 5));
  1917. html.setFile(filename);
  1918. int count = 0;
  1919. int found = 0;
  1920. // counting buttons and unsetting button if found
  1921. for (int i = 0; i < 5; i++)
  1922. {
  1923. if (player.getLoto(i) == val)
  1924. {
  1925. //unsetting button
  1926. player.setLoto(i, 0);
  1927. found = 1;
  1928. }
  1929. else if (player.getLoto(i) > 0)
  1930. {
  1931. count++;
  1932. }
  1933. }
  1934. //if not rearched limit 5 and not unseted value
  1935. if (count < 5 && found == 0 && val <= 20)
  1936. for (int i = 0; i < 5; i++)
  1937. if (player.getLoto(i) == 0)
  1938. {
  1939. player.setLoto(i, val);
  1940. break;
  1941. }
  1942. //setting pusshed buttons
  1943. count = 0;
  1944. for (int i = 0; i < 5; i++)
  1945. if (player.getLoto(i) > 0)
  1946. {
  1947. count++;
  1948. String button = String.valueOf(player.getLoto(i));
  1949. if (player.getLoto(i) < 10)
  1950. button = "0" + button;
  1951. String search = "fore=\"L2UI.lottoNum" + button + "\" back=\"L2UI.lottoNum" + button + "a_check\"";
  1952. String replace = "fore=\"L2UI.lottoNum" + button + "a_check\" back=\"L2UI.lottoNum" + button + "\"";
  1953. html.replace(search, replace);
  1954. }
  1955. if (count == 5)
  1956. {
  1957. String search = "0\">Return";
  1958. String replace = "22\">The winner selected the numbers above.";
  1959. html.replace(search, replace);
  1960. }
  1961. }
  1962. else if (val == 22) //22 - selected ticket with 5 numbers
  1963. {
  1964. if (!Lottery.getInstance().isStarted())
  1965. {
  1966. //tickets can't be sold
  1967. player.sendPacket(new SystemMessage(SystemMessageId.NO_LOTTERY_TICKETS_CURRENT_SOLD));
  1968. return;
  1969. }
  1970. if (!Lottery.getInstance().isSellableTickets())
  1971. {
  1972. //tickets can't be sold
  1973. player.sendPacket(new SystemMessage(SystemMessageId.NO_LOTTERY_TICKETS_AVAILABLE));
  1974. return;
  1975. }
  1976. long price = Config.ALT_LOTTERY_TICKET_PRICE;
  1977. int lotonumber = Lottery.getInstance().getId();
  1978. int enchant = 0;
  1979. int type2 = 0;
  1980. for (int i = 0; i < 5; i++)
  1981. {
  1982. if (player.getLoto(i) == 0)
  1983. return;
  1984. if (player.getLoto(i) < 17)
  1985. enchant += Math.pow(2, player.getLoto(i) - 1);
  1986. else
  1987. type2 += Math.pow(2, player.getLoto(i) - 17);
  1988. }
  1989. if (player.getAdena() < price)
  1990. {
  1991. sm = new SystemMessage(SystemMessageId.YOU_NOT_ENOUGH_ADENA);
  1992. player.sendPacket(sm);
  1993. return;
  1994. }
  1995. if (!player.reduceAdena("Loto", price, this, true))
  1996. return;
  1997. Lottery.getInstance().increasePrize(price);
  1998. sm = new SystemMessage(SystemMessageId.ACQUIRED_S1_S2);
  1999. sm.addNumber(lotonumber);
  2000. sm.addItemName(4442);
  2001. player.sendPacket(sm);
  2002. L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), 4442);
  2003. item.setCount(1);
  2004. item.setCustomType1(lotonumber);
  2005. item.setEnchantLevel(enchant);
  2006. item.setCustomType2(type2);
  2007. player.getInventory().addItem("Loto", item, player, this);
  2008. InventoryUpdate iu = new InventoryUpdate();
  2009. iu.addItem(item);
  2010. L2ItemInstance adenaupdate = player.getInventory().getItemByItemId(57);
  2011. iu.addModifiedItem(adenaupdate);
  2012. player.sendPacket(iu);
  2013. filename = (getHtmlPath(npcId, 3));
  2014. html.setFile(filename);
  2015. }
  2016. else if (val == 23) //23 - current lottery jackpot
  2017. {
  2018. filename = (getHtmlPath(npcId, 3));
  2019. html.setFile(filename);
  2020. }
  2021. else if (val == 24) // 24 - Previous winning numbers/Prize claim
  2022. {
  2023. filename = (getHtmlPath(npcId, 4));
  2024. html.setFile(filename);
  2025. int lotonumber = Lottery.getInstance().getId();
  2026. String message = "";
  2027. for (L2ItemInstance item : player.getInventory().getItems())
  2028. {
  2029. if (item == null)
  2030. continue;
  2031. if (item.getItemId() == 4442 && item.getCustomType1() < lotonumber)
  2032. {
  2033. message = message + "<a action=\"bypass -h npc_%objectId%_Loto " + item.getObjectId() + "\">" + item.getCustomType1() + " Event Number ";
  2034. int[] numbers = Lottery.getInstance().decodeNumbers(item.getEnchantLevel(), item.getCustomType2());
  2035. for (int i = 0; i < 5; i++)
  2036. {
  2037. message += numbers[i] + " ";
  2038. }
  2039. long[] check = Lottery.getInstance().checkTicket(item);
  2040. if (check[0] > 0)
  2041. {
  2042. switch ((int)check[0])
  2043. {
  2044. case 1:
  2045. message += "- 1st Prize";
  2046. break;
  2047. case 2:
  2048. message += "- 2nd Prize";
  2049. break;
  2050. case 3:
  2051. message += "- 3th Prize";
  2052. break;
  2053. case 4:
  2054. message += "- 4th Prize";
  2055. break;
  2056. }
  2057. message += " " + check[1] + "a.";
  2058. }
  2059. message += "</a><br>";
  2060. }
  2061. }
  2062. if (message.isEmpty())
  2063. {
  2064. message += "There is no winning lottery ticket...<br>";
  2065. }
  2066. html.replace("%result%", message);
  2067. }
  2068. else if (val > 24) // >24 - check lottery ticket by item object id
  2069. {
  2070. int lotonumber = Lottery.getInstance().getId();
  2071. L2ItemInstance item = player.getInventory().getItemByObjectId(val);
  2072. if (item == null || item.getItemId() != 4442 || item.getCustomType1() >= lotonumber)
  2073. return;
  2074. long[] check = Lottery.getInstance().checkTicket(item);
  2075. sm = new SystemMessage(SystemMessageId.S2_S1_DISAPPEARED);
  2076. sm.addItemName(4442);
  2077. sm.addItemNumber(1);
  2078. player.sendPacket(sm);
  2079. long adena = check[1];
  2080. if (adena > 0)
  2081. player.addAdena("Loto", adena, this, true);
  2082. player.destroyItem("Loto", item, this, false);
  2083. return;
  2084. }
  2085. html.replace("%objectId%", String.valueOf(getObjectId()));
  2086. html.replace("%race%", "" + Lottery.getInstance().getId());
  2087. html.replace("%adena%", "" + Lottery.getInstance().getPrize());
  2088. html.replace("%ticket_price%", "" + Config.ALT_LOTTERY_TICKET_PRICE);
  2089. html.replace("%prize5%", "" + (Config.ALT_LOTTERY_5_NUMBER_RATE * 100));
  2090. html.replace("%prize4%", "" + (Config.ALT_LOTTERY_4_NUMBER_RATE * 100));
  2091. html.replace("%prize3%", "" + (Config.ALT_LOTTERY_3_NUMBER_RATE * 100));
  2092. html.replace("%prize2%", "" + Config.ALT_LOTTERY_2_AND_1_NUMBER_PRIZE);
  2093. html.replace("%enddate%", "" + DateFormat.getDateInstance().format(Lottery.getInstance().getEndDate()));
  2094. player.sendPacket(html);
  2095. // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  2096. player.sendPacket(ActionFailed.STATIC_PACKET);
  2097. }
  2098. public void makeCPRecovery(L2PcInstance player)
  2099. {
  2100. if (getNpcId() != 31225 && getNpcId() != 31226)
  2101. return;
  2102. if (player.isCursedWeaponEquipped())
  2103. {
  2104. player.sendMessage("Go away, you're not welcome here.");
  2105. player.sendPacket(ActionFailed.STATIC_PACKET);
  2106. return;
  2107. }
  2108. int neededmoney = 100;
  2109. if (!player.reduceAdena("RestoreCP", neededmoney, player.getLastFolkNPC(), true))
  2110. return;
  2111. L2Skill skill = SkillTable.getInstance().getInfo(4380, 1);
  2112. if (skill != null)
  2113. {
  2114. setTarget(player);
  2115. doCast(skill);
  2116. }
  2117. player.sendPacket(ActionFailed.STATIC_PACKET);
  2118. }
  2119. /**
  2120. * Add Newbie helper buffs to L2Player according to its level.<BR><BR>
  2121. *
  2122. * <B><U> Actions</U> :</B><BR><BR>
  2123. * <li>Get the range level in wich player must be to obtain buff </li>
  2124. * <li>If player level is out of range, display a message and return </li>
  2125. * <li>According to player level cast buff </li><BR><BR>
  2126. *
  2127. * <FONT COLOR=#FF0000><B> Newbie Helper Buff list is define in sql table helper_buff_list</B></FONT><BR><BR>
  2128. *
  2129. * @param player The L2PcInstance that talk with the L2NpcInstance
  2130. *
  2131. */
  2132. public void makeSupportMagic(L2PcInstance player, boolean isSummon)
  2133. {
  2134. if (player == null)
  2135. return;
  2136. // Prevent a cursed weapon weilder of being buffed
  2137. if (player.isCursedWeaponEquipped())
  2138. return;
  2139. int player_level = player.getLevel();
  2140. int lowestLevel = 0;
  2141. int highestLevel = 0;
  2142. if (isSummon)
  2143. {
  2144. if (player.getPet() == null || !(player.getPet() instanceof L2SummonInstance))
  2145. {
  2146. String content = "<html><body>Only servitors can receive this Support Magic. If you do not have a servitor, you cannot access these spells.</body></html>";
  2147. insertObjectIdAndShowChatWindow(player, content);
  2148. return;
  2149. }
  2150. setTarget(player.getPet());
  2151. }
  2152. else
  2153. // Select the player
  2154. setTarget(player);
  2155. if (isSummon)
  2156. {
  2157. lowestLevel = HelperBuffTable.getInstance().getServitorLowestLevel();
  2158. highestLevel = HelperBuffTable.getInstance().getServitorHighestLevel();
  2159. }
  2160. else
  2161. {
  2162. // Calculate the min and max level between which the player must be to obtain buff
  2163. if (player.isMageClass())
  2164. {
  2165. lowestLevel = HelperBuffTable.getInstance().getMagicClassLowestLevel();
  2166. highestLevel = HelperBuffTable.getInstance().getMagicClassHighestLevel();
  2167. }
  2168. else
  2169. {
  2170. lowestLevel = HelperBuffTable.getInstance().getPhysicClassLowestLevel();
  2171. highestLevel = HelperBuffTable.getInstance().getPhysicClassHighestLevel();
  2172. }
  2173. }
  2174. // If the player is too high level, display a message and return
  2175. if (player_level > highestLevel)
  2176. {
  2177. String content = "<html><body>Newbie Guide:<br>Only a <font color=\"LEVEL\">novice character of level " + highestLevel
  2178. + " or less</font> can receive my support magic.<br>Your novice character is the first one that you created and raised in this world.</body></html>";
  2179. insertObjectIdAndShowChatWindow(player, content);
  2180. return;
  2181. }
  2182. // If the player is too low level, display a message and return
  2183. if (player_level < lowestLevel)
  2184. {
  2185. String content = "<html><body>Come back here when you have reached level " + lowestLevel + ". I will give you support magic then.</body></html>";
  2186. insertObjectIdAndShowChatWindow(player, content);
  2187. return;
  2188. }
  2189. L2Skill skill = null;
  2190. if (isSummon)
  2191. {
  2192. for (L2HelperBuff helperBuffItem : HelperBuffTable.getInstance().getHelperBuffTable())
  2193. {
  2194. if (helperBuffItem.isForSummon())
  2195. {
  2196. skill = SkillTable.getInstance().getInfo(helperBuffItem.getSkillID(), helperBuffItem.getSkillLevel());
  2197. if (skill != null)
  2198. doCast(skill);
  2199. }
  2200. }
  2201. }
  2202. else
  2203. {
  2204. // Go through the Helper Buff list define in sql table helper_buff_list and cast skill
  2205. for (L2HelperBuff helperBuffItem : HelperBuffTable.getInstance().getHelperBuffTable())
  2206. {
  2207. if (helperBuffItem.isMagicClassBuff() == player.isMageClass())
  2208. {
  2209. if (player_level >= helperBuffItem.getLowerLevel() && player_level <= helperBuffItem.getUpperLevel())
  2210. {
  2211. skill = SkillTable.getInstance().getInfo(helperBuffItem.getSkillID(), helperBuffItem.getSkillLevel());
  2212. if (skill.getSkillType() == L2SkillType.SUMMON)
  2213. player.doSimultaneousCast(skill);
  2214. else
  2215. doCast(skill);
  2216. }
  2217. }
  2218. }
  2219. }
  2220. }
  2221. public void showChatWindow(L2PcInstance player)
  2222. {
  2223. showChatWindow(player, 0);
  2224. }
  2225. /**
  2226. * Returns true if html exists
  2227. * @param player
  2228. * @param type
  2229. * @return boolean
  2230. */
  2231. private boolean showPkDenyChatWindow(L2PcInstance player, String type)
  2232. {
  2233. String html = HtmCache.getInstance().getHtm("data/html/" + type + "/" + getNpcId() + "-pk.htm");
  2234. if (html != null)
  2235. {
  2236. NpcHtmlMessage pkDenyMsg = new NpcHtmlMessage(getObjectId());
  2237. pkDenyMsg.setHtml(html);
  2238. player.sendPacket(pkDenyMsg);
  2239. player.sendPacket(ActionFailed.STATIC_PACKET);
  2240. return true;
  2241. }
  2242. return false;
  2243. }
  2244. /**
  2245. * Open a chat window on client with the text of the L2NpcInstance.<BR><BR>
  2246. *
  2247. * <B><U> Actions</U> :</B><BR><BR>
  2248. * <li>Get the text of the selected HTML file in function of the npcId and of the page number </li>
  2249. * <li>Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance </li>
  2250. * <li>Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet </li><BR>
  2251. *
  2252. * @param player The L2PcInstance that talk with the L2NpcInstance
  2253. * @param val The number of the page of the L2NpcInstance to display
  2254. *
  2255. */
  2256. public void showChatWindow(L2PcInstance player, int val)
  2257. {
  2258. if (player.isCursedWeaponEquipped() && (!(player.getTarget() instanceof L2ClanHallManagerInstance) || !(player.getTarget() instanceof L2DoormenInstance)))
  2259. {
  2260. player.setTarget(player);
  2261. return;
  2262. }
  2263. if (player.getKarma() > 0)
  2264. {
  2265. if (!Config.ALT_GAME_KARMA_PLAYER_CAN_SHOP && this instanceof L2MerchantInstance)
  2266. {
  2267. if (showPkDenyChatWindow(player, "merchant"))
  2268. return;
  2269. }
  2270. else if (!Config.ALT_GAME_KARMA_PLAYER_CAN_USE_GK && this instanceof L2TeleporterInstance)
  2271. {
  2272. if (showPkDenyChatWindow(player, "teleporter"))
  2273. return;
  2274. }
  2275. else if (!Config.ALT_GAME_KARMA_PLAYER_CAN_USE_WAREHOUSE && this instanceof L2WarehouseInstance)
  2276. {
  2277. if (showPkDenyChatWindow(player, "warehouse"))
  2278. return;
  2279. }
  2280. else if (!Config.ALT_GAME_KARMA_PLAYER_CAN_SHOP && this instanceof L2FishermanInstance)
  2281. {
  2282. if (showPkDenyChatWindow(player, "fisherman"))
  2283. return;
  2284. }
  2285. }
  2286. if ("L2Auctioneer".equals(getTemplate().type) && val == 0)
  2287. return;
  2288. int npcId = getTemplate().npcId;
  2289. /* For use with Seven Signs implementation */
  2290. String filename = SevenSigns.SEVEN_SIGNS_HTML_PATH;
  2291. int sealAvariceOwner = SevenSigns.getInstance().getSealOwner(SevenSigns.SEAL_AVARICE);
  2292. int sealGnosisOwner = SevenSigns.getInstance().getSealOwner(SevenSigns.SEAL_GNOSIS);
  2293. int playerCabal = SevenSigns.getInstance().getPlayerCabal(player);
  2294. int compWinner = SevenSigns.getInstance().getCabalHighestScore();
  2295. switch (npcId)
  2296. {
  2297. case 31127: //
  2298. case 31128: //
  2299. case 31129: // Dawn Festival Guides
  2300. case 31130: //
  2301. case 31131: //
  2302. filename += "festival/dawn_guide.htm";
  2303. break;
  2304. case 31137: //
  2305. case 31138: //
  2306. case 31139: // Dusk Festival Guides
  2307. case 31140: //
  2308. case 31141: //
  2309. filename += "festival/dusk_guide.htm";
  2310. break;
  2311. case 31092: // Black Marketeer of Mammon
  2312. filename += "blkmrkt_1.htm";
  2313. break;
  2314. case 31113: // Merchant of Mammon
  2315. if (Config.ALT_STRICT_SEVENSIGNS)
  2316. {
  2317. switch (compWinner)
  2318. {
  2319. case SevenSigns.CABAL_DAWN:
  2320. if (playerCabal != compWinner || playerCabal != sealAvariceOwner)
  2321. {
  2322. player.sendPacket(new SystemMessage(SystemMessageId.CAN_BE_USED_BY_DAWN));
  2323. player.sendPacket(ActionFailed.STATIC_PACKET);
  2324. return;
  2325. }
  2326. break;
  2327. case SevenSigns.CABAL_DUSK:
  2328. if (playerCabal != compWinner || playerCabal != sealAvariceOwner)
  2329. {
  2330. player.sendPacket(new SystemMessage(SystemMessageId.CAN_BE_USED_BY_DUSK));
  2331. player.sendPacket(ActionFailed.STATIC_PACKET);
  2332. return;
  2333. }
  2334. break;
  2335. default:
  2336. player.sendPacket(new SystemMessage(SystemMessageId.QUEST_EVENT_PERIOD));
  2337. return;
  2338. }
  2339. }
  2340. filename += "mammmerch_1.htm";
  2341. break;
  2342. case 31126: // Blacksmith of Mammon
  2343. if (Config.ALT_STRICT_SEVENSIGNS)
  2344. {
  2345. switch (compWinner)
  2346. {
  2347. case SevenSigns.CABAL_DAWN:
  2348. if (playerCabal != compWinner || playerCabal != sealGnosisOwner)
  2349. {
  2350. player.sendPacket(new SystemMessage(SystemMessageId.CAN_BE_USED_BY_DAWN));
  2351. player.sendPacket(ActionFailed.STATIC_PACKET);
  2352. return;
  2353. }
  2354. break;
  2355. case SevenSigns.CABAL_DUSK:
  2356. if (playerCabal != compWinner || playerCabal != sealGnosisOwner)
  2357. {
  2358. player.sendPacket(new SystemMessage(SystemMessageId.CAN_BE_USED_BY_DUSK));
  2359. player.sendPacket(ActionFailed.STATIC_PACKET);
  2360. return;
  2361. }
  2362. break;
  2363. default:
  2364. player.sendPacket(new SystemMessage(SystemMessageId.QUEST_EVENT_PERIOD));
  2365. return;
  2366. }
  2367. }
  2368. filename += "mammblack_1.htm";
  2369. break;
  2370. case 31132:
  2371. case 31133:
  2372. case 31134:
  2373. case 31135:
  2374. case 31136: // Festival Witches
  2375. case 31142:
  2376. case 31143:
  2377. case 31144:
  2378. case 31145:
  2379. case 31146:
  2380. filename += "festival/festival_witch.htm";
  2381. break;
  2382. case 31688:
  2383. if (player.isNoble())
  2384. filename = Olympiad.OLYMPIAD_HTML_PATH + "noble_main.htm";
  2385. else
  2386. filename = (getHtmlPath(npcId, val));
  2387. break;
  2388. case 31690:
  2389. case 31769:
  2390. case 31770:
  2391. case 31771:
  2392. case 31772:
  2393. if (player.isHero() || player.isNoble())
  2394. filename = Olympiad.OLYMPIAD_HTML_PATH + "hero_main.htm";
  2395. else
  2396. filename = (getHtmlPath(npcId, val));
  2397. break;
  2398. case 36402:
  2399. if (player.olyBuff > 0)
  2400. filename = (player.olyBuff == 5 ? Olympiad.OLYMPIAD_HTML_PATH + "olympiad_buffs.htm" : Olympiad.OLYMPIAD_HTML_PATH + "olympiad_5buffs.htm");
  2401. else
  2402. filename = Olympiad.OLYMPIAD_HTML_PATH + "olympiad_nobuffs.htm";
  2403. break;
  2404. default:
  2405. if (npcId >= 31865 && npcId <= 31918)
  2406. {
  2407. if (val == 0 )
  2408. filename += "rift/GuardianOfBorder.htm";
  2409. else
  2410. filename += "rift/GuardianOfBorder-" + val + ".htm";
  2411. break;
  2412. }
  2413. if ((npcId >= 31093 && npcId <= 31094) || (npcId >= 31172 && npcId <= 31201) || (npcId >= 31239 && npcId <= 31254))
  2414. return;
  2415. // Get the text of the selected HTML file in function of the npcId and of the page number
  2416. filename = (getHtmlPath(npcId, val));
  2417. break;
  2418. }
  2419. // Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance
  2420. NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  2421. html.setFile(filename);
  2422. if (this instanceof L2MerchantInstance)
  2423. {
  2424. if (Config.LIST_PET_RENT_NPC.contains(npcId))
  2425. html.replace("_Quest", "_RentPet\">Rent Pet</a><br><a action=\"bypass -h npc_%objectId%_Quest");
  2426. }
  2427. html.replace("%objectId%", String.valueOf(getObjectId()));
  2428. html.replace("%festivalMins%", SevenSignsFestival.getInstance().getTimeToNextFestivalStr());
  2429. player.sendPacket(html);
  2430. // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  2431. player.sendPacket(ActionFailed.STATIC_PACKET);
  2432. }
  2433. /**
  2434. * Open a chat window on client with the text specified by the given file name and path,<BR>
  2435. * relative to the datapack root.
  2436. * <BR><BR>
  2437. * Added by Tempy
  2438. * @param player The L2PcInstance that talk with the L2NpcInstance
  2439. * @param filename The filename that contains the text to send
  2440. *
  2441. */
  2442. public void showChatWindow(L2PcInstance player, String filename)
  2443. {
  2444. // Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance
  2445. NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  2446. html.setFile(filename);
  2447. html.replace("%objectId%", String.valueOf(getObjectId()));
  2448. player.sendPacket(html);
  2449. // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  2450. player.sendPacket(ActionFailed.STATIC_PACKET);
  2451. }
  2452. /**
  2453. * Return the Exp Reward of this L2NpcInstance contained in the L2NpcTemplate (modified by RATE_XP).<BR><BR>
  2454. */
  2455. public int getExpReward()
  2456. {
  2457. double rateXp = getStat().calcStat(Stats.MAX_HP, 1, this, null);
  2458. return (int) (getTemplate().rewardExp * rateXp * Config.RATE_XP);
  2459. }
  2460. /**
  2461. * Return the SP Reward of this L2NpcInstance contained in the L2NpcTemplate (modified by RATE_SP).<BR><BR>
  2462. */
  2463. public int getSpReward()
  2464. {
  2465. double rateSp = getStat().calcStat(Stats.MAX_HP, 1, this, null);
  2466. return (int) (getTemplate().rewardSp * rateSp * Config.RATE_SP);
  2467. }
  2468. /**
  2469. * Kill the L2NpcInstance (the corpse disappeared after 7 seconds).<BR><BR>
  2470. *
  2471. * <B><U> Actions</U> :</B><BR><BR>
  2472. * <li>Create a DecayTask to remove the corpse of the L2NpcInstance after 7 seconds </li>
  2473. * <li>Set target to null and cancel Attack or Cast </li>
  2474. * <li>Stop movement </li>
  2475. * <li>Stop HP/MP/CP Regeneration task </li>
  2476. * <li>Stop all active skills effects in progress on the L2Character </li>
  2477. * <li>Send the Server->Client packet StatusUpdate with current HP and MP to all other L2PcInstance to inform </li>
  2478. * <li>Notify L2Character AI </li><BR><BR>
  2479. *
  2480. * <B><U> Overridden in </U> :</B><BR><BR>
  2481. * <li> L2Attackable </li><BR><BR>
  2482. *
  2483. * @param killer The L2Character who killed it
  2484. *
  2485. */
  2486. @Override
  2487. public boolean doDie(L2Character killer)
  2488. {
  2489. if (!super.doDie(killer))
  2490. return false;
  2491. // normally this wouldn't really be needed, but for those few exceptions,
  2492. // we do need to reset the weapons back to the initial templated weapon.
  2493. _currentLHandId = getTemplate().lhand;
  2494. _currentRHandId = getTemplate().rhand;
  2495. _currentCollisionHeight = getTemplate().fCollisionHeight;
  2496. _currentCollisionRadius = getTemplate().fCollisionRadius;
  2497. DecayTaskManager.getInstance().addDecayTask(this);
  2498. return true;
  2499. }
  2500. /**
  2501. * Set the spawn of the L2NpcInstance.<BR><BR>
  2502. *
  2503. * @param spawn The L2Spawn that manage the L2NpcInstance
  2504. *
  2505. */
  2506. public void setSpawn(L2Spawn spawn)
  2507. {
  2508. _spawn = spawn;
  2509. }
  2510. @Override
  2511. public void onSpawn()
  2512. {
  2513. super.onSpawn();
  2514. if (getTemplate().getEventQuests(Quest.QuestEventType.ON_SPAWN) != null)
  2515. for (Quest quest : getTemplate().getEventQuests(Quest.QuestEventType.ON_SPAWN))
  2516. quest.notifySpawn(this);
  2517. }
  2518. /**
  2519. * Remove the L2NpcInstance from the world and update its spawn object (for a complete removal use the deleteMe method).<BR><BR>
  2520. *
  2521. * <B><U> Actions</U> :</B><BR><BR>
  2522. * <li>Remove the L2NpcInstance from the world when the decay task is launched </li>
  2523. * <li>Decrease its spawn counter </li>
  2524. * <li>Manage Siege task (killFlag, killCT) </li><BR><BR>
  2525. *
  2526. * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T REMOVE the object from _allObjects of L2World </B></FONT><BR>
  2527. * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND Server->Client packets to players</B></FONT><BR><BR>
  2528. *
  2529. */
  2530. @Override
  2531. public void onDecay()
  2532. {
  2533. if (isDecayed())
  2534. return;
  2535. setDecayed(true);
  2536. // Remove the L2NpcInstance from the world when the decay task is launched
  2537. super.onDecay();
  2538. // Decrease its spawn counter
  2539. if (_spawn != null)
  2540. _spawn.decreaseCount(this);
  2541. }
  2542. /**
  2543. * Remove PROPERLY the L2NpcInstance from the world.<BR><BR>
  2544. *
  2545. * <B><U> Actions</U> :</B><BR><BR>
  2546. * <li>Remove the L2NpcInstance from the world and update its spawn object </li>
  2547. * <li>Remove all L2Object from _knownObjects and _knownPlayer of the L2NpcInstance then cancel Attack or Cast and notify AI </li>
  2548. * <li>Remove L2Object object from _allObjects of L2World </li><BR><BR>
  2549. *
  2550. * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND Server->Client packets to players</B></FONT><BR><BR>
  2551. *
  2552. */
  2553. public void deleteMe()
  2554. {
  2555. L2WorldRegion oldRegion = getWorldRegion();
  2556. try
  2557. {
  2558. decayMe();
  2559. }
  2560. catch (Exception e)
  2561. {
  2562. _log.log(Level.SEVERE, "Failed decayMe().", e);
  2563. }
  2564. try
  2565. {
  2566. if (_fusionSkill != null)
  2567. abortCast();
  2568. for (L2Character character : getKnownList().getKnownCharacters())
  2569. if (character.getFusionSkill() != null && character.getFusionSkill().getTarget() == this)
  2570. character.abortCast();
  2571. }
  2572. catch (Exception e)
  2573. {
  2574. _log.log(Level.SEVERE, "deleteMe()", e);
  2575. }
  2576. if (oldRegion != null)
  2577. oldRegion.removeFromZones(this);
  2578. // Remove all L2Object from _knownObjects and _knownPlayer of the L2Character then cancel Attak or Cast and notify AI
  2579. try
  2580. {
  2581. getKnownList().removeAllKnownObjects();
  2582. }
  2583. catch (Exception e)
  2584. {
  2585. _log.log(Level.SEVERE, "Failed removing cleaning knownlist.", e);
  2586. }
  2587. // Remove L2Object object from _allObjects of L2World
  2588. L2World.getInstance().removeObject(this);
  2589. }
  2590. /**
  2591. * Return the L2Spawn object that manage this L2NpcInstance.<BR><BR>
  2592. */
  2593. public L2Spawn getSpawn()
  2594. {
  2595. return _spawn;
  2596. }
  2597. @Override
  2598. public String toString()
  2599. {
  2600. return getClass().getSimpleName()+":"+getTemplate().name+"("+getNpcId()+")"+"["+getObjectId()+"]";
  2601. }
  2602. public boolean isDecayed()
  2603. {
  2604. return _isDecayed;
  2605. }
  2606. public void setDecayed(boolean decayed)
  2607. {
  2608. _isDecayed = decayed;
  2609. }
  2610. public void endDecayTask()
  2611. {
  2612. if (!isDecayed())
  2613. {
  2614. DecayTaskManager.getInstance().cancelDecayTask(this);
  2615. onDecay();
  2616. }
  2617. }
  2618. public boolean isMob() // rather delete this check
  2619. {
  2620. return false; // This means we use MAX_NPC_ANIMATION instead of MAX_MONSTER_ANIMATION
  2621. }
  2622. // Two functions to change the appearance of the equipped weapons on the NPC
  2623. // This is only useful for a few NPCs and is most likely going to be called from AI
  2624. public void setLHandId(int newWeaponId)
  2625. {
  2626. _currentLHandId = newWeaponId;
  2627. updateAbnormalEffect();
  2628. }
  2629. public void setRHandId(int newWeaponId)
  2630. {
  2631. _currentRHandId = newWeaponId;
  2632. updateAbnormalEffect();
  2633. }
  2634. public void setLRHandId(int newLWeaponId, int newRWeaponId)
  2635. {
  2636. _currentRHandId = newRWeaponId;
  2637. _currentLHandId = newLWeaponId;
  2638. updateAbnormalEffect();
  2639. }
  2640. public void setEnchant(int newEnchantValue)
  2641. {
  2642. _currentEnchant = newEnchantValue;
  2643. updateAbnormalEffect();
  2644. }
  2645. public void setCollisionHeight(double height)
  2646. {
  2647. _currentCollisionHeight = height;
  2648. }
  2649. public void setCollisionRadius(double radius)
  2650. {
  2651. _currentCollisionRadius = radius;
  2652. }
  2653. public double getCollisionHeight()
  2654. {
  2655. return _currentCollisionHeight;
  2656. }
  2657. public double getCollisionRadius()
  2658. {
  2659. return _currentCollisionRadius;
  2660. }
  2661. @Override
  2662. public void sendInfo(L2PcInstance activeChar)
  2663. {
  2664. if (Config.CHECK_KNOWN)
  2665. activeChar.sendMessage("Added NPC: "+getName());
  2666. if (getRunSpeed() == 0)
  2667. activeChar.sendPacket(new ServerObjectInfo(this, activeChar));
  2668. else
  2669. activeChar.sendPacket(new AbstractNpcInfo.NpcInfo(this, activeChar));
  2670. }
  2671. public void showNoTeachHtml(L2PcInstance player)
  2672. {
  2673. int npcId = getNpcId();
  2674. String html = "";
  2675. if (this instanceof L2WarehouseInstance)
  2676. html = HtmCache.getInstance().getHtm("data/html/warehouse/" + npcId + "-noteach.htm");
  2677. else if (this instanceof L2TrainerInstance)
  2678. html = HtmCache.getInstance().getHtm("data/html/trainer/" + npcId + "-noteach.htm");
  2679. if (html == null)
  2680. {
  2681. _log.warning("Npc " + npcId + " missing noTeach html!");
  2682. NpcHtmlMessage msg = new NpcHtmlMessage(getObjectId());
  2683. final String sb = StringUtil.concat(
  2684. "<html><body>" +
  2685. "I cannot teach you any skills.<br>You must find your current class teachers.",
  2686. "</body></html>"
  2687. );
  2688. msg.setHtml(sb);
  2689. player.sendPacket(msg);
  2690. return;
  2691. }
  2692. else
  2693. {
  2694. NpcHtmlMessage noTeachMsg = new NpcHtmlMessage(getObjectId());
  2695. noTeachMsg.setHtml(html);
  2696. noTeachMsg.replace("%objectId%", String.valueOf(getObjectId()));
  2697. player.sendPacket(noTeachMsg);
  2698. }
  2699. }
  2700. public L2Npc scheduleDespawn(long delay)
  2701. {
  2702. ThreadPoolManager.getInstance().scheduleGeneral(this.new DespawnTask(this), delay);
  2703. return this;
  2704. }
  2705. public class DespawnTask implements Runnable
  2706. {
  2707. L2Npc _npc;
  2708. public DespawnTask(L2Npc npc)
  2709. {
  2710. _npc = npc;
  2711. }
  2712. @Override
  2713. public void run()
  2714. {
  2715. if (_npc != null)
  2716. _npc.deleteMe();
  2717. }
  2718. }
  2719. @Override
  2720. protected final void notifyQuestEventSkillFinished(L2Skill skill, L2Object target)
  2721. {
  2722. try
  2723. {
  2724. if (getTemplate().getEventQuests(Quest.QuestEventType.ON_SPELL_FINISHED) != null)
  2725. {
  2726. L2PcInstance player = target.getActingPlayer();
  2727. for (Quest quest : getTemplate().getEventQuests(Quest.QuestEventType.ON_SPELL_FINISHED))
  2728. {
  2729. quest.notifySpellFinished(((L2Npc) this), player, skill);
  2730. }
  2731. }
  2732. }
  2733. catch (Exception e)
  2734. {
  2735. _log.log(Level.SEVERE, "", e);
  2736. }
  2737. }
  2738. }