1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2, or (at your option)
5 * any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
15 * 02111-1307, USA.
16 *
17 * http://www.gnu.org/copyleft/gpl.html
18 */
19 package net.sf.l2j.gameserver.model.actor.instance;
20
21 import static net.sf.l2j.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
22
23 import java.text.DateFormat;
24 import java.util.List;
25
26 import javolution.text.TextBuilder;
27 import javolution.util.FastList;
28 import net.sf.l2j.Config;
29 import net.sf.l2j.gameserver.Olympiad;
30 import net.sf.l2j.gameserver.SevenSigns;
31 import net.sf.l2j.gameserver.SevenSignsFestival;
32 import net.sf.l2j.gameserver.ThreadPoolManager;
33 import net.sf.l2j.gameserver.ai.CtrlIntention;
34 import net.sf.l2j.gameserver.cache.HtmCache;
35 import net.sf.l2j.gameserver.datatables.BuffTemplateTable;
36 import net.sf.l2j.gameserver.datatables.ClanTable;
37 import net.sf.l2j.gameserver.datatables.HelperBuffTable;
38 import net.sf.l2j.gameserver.datatables.ItemTable;
39 import net.sf.l2j.gameserver.datatables.SkillTable;
40 import net.sf.l2j.gameserver.datatables.SpawnTable;
41 import net.sf.l2j.gameserver.idfactory.IdFactory;
42 import net.sf.l2j.gameserver.instancemanager.CastleManager;
43 import net.sf.l2j.gameserver.instancemanager.DimensionalRiftManager;
44 import net.sf.l2j.gameserver.instancemanager.QuestManager;
45 import net.sf.l2j.gameserver.instancemanager.TownManager;
46 import net.sf.l2j.gameserver.instancemanager.games.Lottery;
47 import net.sf.l2j.gameserver.model.L2Attackable;
48 import net.sf.l2j.gameserver.model.L2Character;
49 import net.sf.l2j.gameserver.model.L2Clan;
50 import net.sf.l2j.gameserver.model.L2DropCategory;
51 import net.sf.l2j.gameserver.model.L2DropData;
52 import net.sf.l2j.gameserver.model.L2ItemInstance;
53 import net.sf.l2j.gameserver.model.L2Multisell;
54 import net.sf.l2j.gameserver.model.L2Object;
55 import net.sf.l2j.gameserver.model.L2Skill;
56 import net.sf.l2j.gameserver.model.L2Spawn;
57 import net.sf.l2j.gameserver.model.L2Summon;
58 import net.sf.l2j.gameserver.model.L2World;
59 import net.sf.l2j.gameserver.model.MobGroupTable;
60 import net.sf.l2j.gameserver.model.L2Skill.SkillType;
61 import net.sf.l2j.gameserver.model.actor.knownlist.NpcKnownList;
62 import net.sf.l2j.gameserver.model.actor.stat.NpcStat;
63 import net.sf.l2j.gameserver.model.actor.status.NpcStatus;
64 import net.sf.l2j.gameserver.model.entity.Castle;
65 import net.sf.l2j.gameserver.model.entity.L2Event;
66 import net.sf.l2j.gameserver.model.entity.L2JOneoEvents.CTF;
67 import net.sf.l2j.gameserver.model.entity.L2JOneoEvents.VIP;
68 import net.sf.l2j.gameserver.model.quest.Quest;
69 import net.sf.l2j.gameserver.model.quest.QuestState;
70 import net.sf.l2j.gameserver.model.zone.type.L2TownZone;
71 import net.sf.l2j.gameserver.network.L2GameClient;
72 import net.sf.l2j.gameserver.network.SystemMessageId;
73 import net.sf.l2j.gameserver.serverpackets.ActionFailed;
74 import net.sf.l2j.gameserver.serverpackets.ExShowVariationCancelWindow;
75 import net.sf.l2j.gameserver.serverpackets.ExShowVariationMakeWindow;
76 import net.sf.l2j.gameserver.serverpackets.InventoryUpdate;
77 import net.sf.l2j.gameserver.serverpackets.MyTargetSelected;
78 import net.sf.l2j.gameserver.serverpackets.NpcHtmlMessage;
79 import net.sf.l2j.gameserver.serverpackets.NpcInfo;
80 import net.sf.l2j.gameserver.serverpackets.RadarControl;
81 import net.sf.l2j.gameserver.serverpackets.SocialAction;
82 import net.sf.l2j.gameserver.serverpackets.StatusUpdate;
83 import net.sf.l2j.gameserver.serverpackets.SystemMessage;
84 import net.sf.l2j.gameserver.serverpackets.ValidateLocation;
85 import net.sf.l2j.gameserver.skills.Stats;
86 import net.sf.l2j.gameserver.taskmanager.DecayTaskManager;
87 import net.sf.l2j.gameserver.templates.L2HelperBuff;
88 import net.sf.l2j.gameserver.templates.L2Item;
89 import net.sf.l2j.gameserver.templates.L2NpcTemplate;
90 import net.sf.l2j.gameserver.templates.L2Weapon;
91 import net.sf.l2j.util.Rnd;
92
93 /**
94 * This class represents a Non-Player-Character in the world. It can be a
95 * monster or a friendly character. It also uses a template to fetch some static
96 * values. The templates are hardcoded in the client, so we can rely on them.
97 *
98 *
99 * L2Character :
100 *
101 *
L2Attackable
102 *
L2BoxInstance
103 *
L2FolkInstance
104 *
105 * @version $Revision: 1.32.2.7.2.24 $ $Date: 2005/04/11 10:06:09 $
106 */
107 public class L2NpcInstance extends L2Character
108 {
109 // private static Logger _log =
110 // Logger.getLogger(L2NpcInstance.class.getName());
111
112 /**
113 * The interaction distance of the L2NpcInstance(is used as offset in
114 * MovetoLocation method)
115 */
116 public static final int INTERACTION_DISTANCE = 150;
117
118 /** The L2Spawn object that manage this L2NpcInstance */
119 private L2Spawn _spawn;
120
121 /** The flag to specify if this L2NpcInstance is busy */
122 private boolean _isBusy = false;
123
124 /** The busy message for this L2NpcInstance */
125 private String _busyMessage = "";
126
127 /** true if endDecayTask has already been called */
128 volatile boolean _isDecayed = false;
129
130 /** true if a Dwarf has used Spoil on this L2NpcInstance */
131 private boolean _isSpoil = false;
132
133 /**
134 * The castle index in the array of L2Castle this L2NpcInstance belongs
135 * to
136 */
137 private int _castleIndex = -2;
138
139 public boolean isEventMob = false, _isEventVIPNPC = false,
140 _isEventVIPNPCEnd = false;
141
142 public boolean _isEventMobCTF = false;
143
144 public boolean isPrivateEventMob = false;
145
146 private boolean _isInTown = false;
147
148 private int _isSpoiledBy = 0;
149
150 protected RandomAnimationTask _rAniTask = null;
151
152 /** Task launching the function onRandomAnimation() */
153 protected class RandomAnimationTask implements Runnable
154 {
155 public void run()
156 {
157 try
158 {
159 if (this != _rAniTask)
160 {
161 return; // Shouldn't happen, but who knows... just to
162 // make
163 // sure every active npc has only one timer.
164 }
165 if (isMob())
166 {
167 // Cancel further animation timers until intention is
168 // changed to ACTIVE again.
169 if (getAI().getIntention() != AI_INTENTION_ACTIVE)
170 {
171 return;
172 }
173 } else
174 {
175 if (!isInActiveRegion())
176 {
177 return;
178 }
179 // update knownlist to remove playable which aren't in
180 // range
181 // any more
182 getKnownList().updateKnownObjects();
183 }
184
185 if (!(isDead() || isStunned() || isSleeping() || isParalyzed()))
186 {
187 onRandomAnimation();
188 }
189
190 startRandomAnimationTimer();
191 } catch (Throwable t)
192 {
193 }
194 }
195 }
196
197 /**
198 * Send a packet SocialAction to all L2PcInstance in the _KnownPlayers
199 * of the L2NpcInstance and create a new RandomAnimation Task.
200 *
201 */
202 public void onRandomAnimation()
203 {
204 // Send a packet SocialAction to all L2PcInstance in the _KnownPlayers
205 // of the L2NpcInstance
206 SocialAction sa = new SocialAction(getObjectId(), Rnd.get(2, 3));
207 broadcastPacket(sa);
208 }
209
210 /**
211 * Create a RandomAnimation Task that will be launched after the
212 * calculated delay.
213 *
214 */
215 public void startRandomAnimationTimer()
216 {
217 if (!hasRandomAnimation())
218 {
219 return;
220 }
221
222 int minWait = isMob() ? Config.MIN_MONSTER_ANIMATION : Config.MIN_NPC_ANIMATION;
223
224 int maxWait = isMob() ? Config.MAX_MONSTER_ANIMATION : Config.MAX_NPC_ANIMATION;
225
226 // Calculate the delay before the next animation
227 int interval = Rnd.get(minWait, maxWait) * 1000;
228
229 // Create a RandomAnimation Task that will be launched after the
230 // calculated delay
231 _rAniTask = new RandomAnimationTask();
232 ThreadPoolManager.getInstance().scheduleGeneral(_rAniTask, interval);
233 }
234
235 /**
236 * Check if the server allows Random Animation.
237 *
238 */
239 public boolean hasRandomAnimation()
240 {
241 return Config.MAX_NPC_ANIMATION > 0;
242 }
243
244 public class destroyTemporalNPC implements Runnable
245 {
246 private L2Spawn _oldSpawn;
247
248 public destroyTemporalNPC(L2Spawn spawn)
249 {
250 _oldSpawn = spawn;
251 }
252
253 public void run()
254 {
255 try
256 {
257 _oldSpawn.getLastSpawn().deleteMe();
258 _oldSpawn.stopRespawn();
259 SpawnTable.getInstance().deleteSpawn(_oldSpawn, false);
260 } catch (Throwable t)
261 {
262 t.printStackTrace();
263 }
264 }
265 }
266
267 public class destroyTemporalSummon implements Runnable
268 {
269 L2Summon _summon;
270
271 L2PcInstance _player;
272
273 public destroyTemporalSummon(L2Summon summon, L2PcInstance player)
274 {
275 _summon = summon;
276 _player = player;
277 }
278
279 public void run()
280 {
281 _summon.unSummon(_player);
282 }
283 }
284
285 /**
286 * Constructor of L2NpcInstance (use L2Character constructor).
287 *
288 *
289 * Actions :
290 *
291 *
Call the L2Character constructor to set the _template of the
292 * L2Character (copy skills from template to object and link
293 * _calculators to NPC_STD_CALCULATOR)
294 *
Set the name of the L2Character
295 *
Create a RandomAnimation Task that will be launched after the
296 * calculated delay if the server allow it
297 *
298 *
299 *
300 * @param objectId
301 * Identifier of the object to initialized
302 * @param template
303 * The L2NpcTemplate to apply to the NPC
304 *
305 */
306 public L2NpcInstance(int objectId, L2NpcTemplate template)
307 {
308 // Call the L2Character constructor to set the _template of the
309 // L2Character, copy skills from template to object
310 // and link _calculators to NPC_STD_CALCULATOR
311 super(objectId, template);
312 getKnownList(); // init knownlist
313 getStat(); // init stats
314 getStatus(); // init status
315 initCharStatusUpdateValues();
316
317 // initialize the "current" equipment
318 _currentLHandId = getTemplate().lhand;
319 _currentRHandId = getTemplate().rhand;
320
321 if (template == null)
322 {
323 _log.severe("No template for Npc. Please check your datapack is setup correctly.");
324 return;
325 }
326
327 // Set the name of the L2Character
328 setName(template.name);
329 }
330
331 @Override
332 public NpcKnownList getKnownList()
333 {
334 if (super.getKnownList() == null || !(super.getKnownList() instanceof NpcKnownList))
335 {
336 setKnownList(new NpcKnownList(this));
337 }
338 return (NpcKnownList) super.getKnownList();
339 }
340
341 @Override
342 public NpcStat getStat()
343 {
344 if (super.getStat() == null || !(super.getStat() instanceof NpcStat))
345 {
346 setStat(new NpcStat(this));
347 }
348 return (NpcStat) super.getStat();
349 }
350
351 @Override
352 public NpcStatus getStatus()
353 {
354 if (super.getStatus() == null || !(super.getStatus() instanceof NpcStatus))
355 {
356 setStatus(new NpcStatus(this));
357 }
358 return (NpcStatus) super.getStatus();
359 }
360
361 /** Return the L2NpcTemplate of the L2NpcInstance. */
362 @Override
363 public final L2NpcTemplate getTemplate()
364 {
365 return (L2NpcTemplate) super.getTemplate();
366 }
367
368 /**
369 * Return the generic Identifier of this L2NpcInstance contained in the
370 * L2NpcTemplate.
371 *
372 */
373 public int getNpcId()
374 {
375 return getTemplate().npcId;
376 }
377
378 @Override
379 public boolean isAttackable()
380 {
381 return false;
382 }
383
384 /**
385 * Return the faction Identifier of this L2NpcInstance contained in the
386 * L2NpcTemplate.
387 *
388 *
389 * Concept :
390 *
391 * If a NPC belows to a Faction, other NPC of the faction inside the
392 * Faction range will help it if it's attacked
393 *
394 *
395 */
396 public final String getFactionId()
397 {
398 return getTemplate().factionId;
399 }
400
401 /**
402 * Return the Level of this L2NpcInstance contained in the
403 * L2NpcTemplate.
404 *
405 */
406 @Override
407 public final int getLevel()
408 {
409 return getTemplate().level;
410 }
411
412 /**
413 * Return true if the L2NpcInstance is agressive (ex : L2MonsterInstance
414 * in function of aggroRange).
415 *
416 */
417 public boolean isAggressive()
418 {
419 return false;
420 }
421
422 /**
423 * Return the Aggro Range of this L2NpcInstance contained in the
424 * L2NpcTemplate.
425 *
426 */
427 public int getAggroRange()
428 {
429 return getTemplate().aggroRange;
430 }
431
432 /**
433 * Return the Faction Range of this L2NpcInstance contained in the
434 * L2NpcTemplate.
435 *
436 */
437 public int getFactionRange()
438 {
439 return getTemplate().factionRange;
440 }
441
442 /**
443 * Return true if this L2NpcInstance is undead in function of the
444 * L2NpcTemplate.
445 *
446 */
447 @Override
448 public boolean isUndead()
449 {
450 return getTemplate().isUndead;
451 }
452
453 /**
454 * Send a packet NpcInfo with state of abnormal effect to all
455 * L2PcInstance in the _KnownPlayers of the L2NpcInstance.
456 *
457 */
458 @Override
459 public void updateAbnormalEffect()
460 {
461 // NpcInfo info = new NpcInfo(this);
462 // broadcastPacket(info);
463
464 // Send a Server->Client packet NpcInfo with state of abnormal effect to
465 // all L2PcInstance in the _KnownPlayers of the L2NpcInstance
466 for (L2PcInstance player : getKnownList().getKnownPlayers().values())
467 {
468 if (player != null)
469 {
470 player.sendPacket(new NpcInfo(this, player));
471 }
472 }
473 }
474
475 /**
476 * Return the distance under which the object must be add to
477 * _knownObject in function of the object type.
478 *
479 *
480 * Values :
481 *
482 *
object is a L2FolkInstance : 0 (don't remember it)
536 *
537 *
538 *
539 * @param object
540 * The Object to remove from _knownObject
541 *
542 */
543 public int getDistanceToForgetObject(L2Object object)
544 {
545 return 2 * getDistanceToWatchObject(object);
546 }
547
548 /**
549 * Return false.
550 *
551 *
552 * Overriden in :
553 *
554 *
L2MonsterInstance : Check if the attacker is not another
555 * L2MonsterInstance
556 *
L2PcInstance
557 *
558 *
559 */
560 @Override
561 public boolean isAutoAttackable(@SuppressWarnings("unused")
562 L2Character attacker)
563 {
564 return false;
565 }
566
567 /**
568 * Return the Identifier of the item in the left hand of this
569 * L2NpcInstance contained in the L2NpcTemplate.
570 *
571 */
572 public int getLeftHandItem()
573 {
574 return _currentLHandId;
575 }
576
577 /**
578 * Return the Identifier of the item in the right hand of this
579 * L2NpcInstance contained in the L2NpcTemplate.
580 *
581 */
582 public int getRightHandItem()
583 {
584 return _currentRHandId;
585 }
586
587 /**
588 * Return true if this L2NpcInstance has drops that can be sweeped.
589 *
590 */
591 public boolean isSpoil()
592 {
593 return _isSpoil;
594 }
595
596 /**
597 * Set the spoil state of this L2NpcInstance.
598 *
599 */
600 public void setSpoil(boolean isSpoil)
601 {
602 _isSpoil = isSpoil;
603 }
604
605 public final int getIsSpoiledBy()
606 {
607 return _isSpoiledBy;
608 }
609
610 public final void setIsSpoiledBy(int value)
611 {
612 _isSpoiledBy = value;
613 }
614
615 /**
616 * Return the busy status of this L2NpcInstance.
617 *
618 */
619 public final boolean isBusy()
620 {
621 return _isBusy;
622 }
623
624 /**
625 * Set the busy status of this L2NpcInstance.
626 *
627 */
628 public void setBusy(boolean isBusy)
629 {
630 _isBusy = isBusy;
631 }
632
633 /**
634 * Return the busy message of this L2NpcInstance.
635 *
636 */
637 public final String getBusyMessage()
638 {
639 return _busyMessage;
640 }
641
642 /**
643 * Set the busy message of this L2NpcInstance.
644 *
645 */
646 public void setBusyMessage(String message)
647 {
648 _busyMessage = message;
649 }
650
651 /**
652 * Manage actions when a player click on the L2NpcInstance.
653 *
654 *
655 * Actions on first click on the L2NpcInstance (Select it) :
656 *
657 *
Set the L2NpcInstance as target of the L2PcInstance player (if
658 * necessary)
659 *
Send a Server->Client packet MyTargetSelected to the
660 * L2PcInstance player (display the select window)
661 *
If L2NpcInstance is autoAttackable, send a Server->Client packet
662 * StatusUpdate to the L2PcInstance in order to update L2NpcInstance HP
663 * bar
664 *
Send a Server->Client packet ValidateLocation to correct the
665 * L2NpcInstance position and heading on the client
666 *
667 *
668 *
669 * Actions on second click on the L2NpcInstance (Attack
670 * it/Intercat with it) :
671 *
672 *
Send a Server->Client packet MyTargetSelected to the
673 * L2PcInstance player (display the select window)
674 *
If L2NpcInstance is autoAttackable, notify the L2PcInstance AI
675 * with AI_INTENTION_ATTACK (after a height verification)
676 *
If L2NpcInstance is NOT autoAttackable, notify the L2PcInstance
677 * AI with AI_INTENTION_INTERACT (after a distance verification) and
678 * show message
679 *
680 *
681 *
682 * Caution : Each group of
683 * Server->Client packet must be terminated by a ActionFailed packet in
684 * order to avoid that client wait an other packet
685 *
686 *
687 * Example of use :
688 *
689 *
L2ArtefactInstance : Manage only fisrt click to select Artefact
696 *
697 *
698 *
L2GuardInstance :
699 *
700 *
701 *
702 * @param player
703 * The L2PcInstance that start an action on the
704 * L2NpcInstance
705 *
706 */
707 @Override
708 public void onAction(L2PcInstance player)
709 {
710 if (player.isOutOfControl())
711 {
712 player.sendPacket(new ActionFailed());
713 return;
714 }
715 // Check if the L2PcInstance already target the L2NpcInstance
716 if (this != player.getTarget())
717 {
718 if (Config.DEBUG)
719 {
720 _log.fine("new target selected:" + getObjectId());
721 }
722
723 // Set the target of the L2PcInstance player
724 player.setTarget(this);
725
726 // Send a Server->Client packet MyTargetSelected to the
727 // L2PcInstance
728 // player
729 // The player.getLevel() - getLevel() permit to display the
730 // correct
731 // color in the select window
732 MyTargetSelected my = new MyTargetSelected(getObjectId(), player.getLevel() - getLevel());
733 player.sendPacket(my);
734
735 // Check if the player is attackable (without a forced attack)
736 if (isAutoAttackable(player))
737 {
738 // Send a Server->Client packet StatusUpdate of the
739 // L2NpcInstance to the L2PcInstance to update its HP bar
740 StatusUpdate su = new StatusUpdate(getObjectId());
741 su.addAttribute(StatusUpdate.CUR_HP, (int) getCurrentHp());
742 su.addAttribute(StatusUpdate.MAX_HP, getMaxHp());
743 player.sendPacket(su);
744 }
745
746 // Send a Server->Client packet ValidateLocation to correct the
747 // L2NpcInstance position and heading on the client
748 player.sendPacket(new ValidateLocation(this));
749 } else
750 {
751 player.sendPacket(new ValidateLocation(this));
752
753 // Check if the player is attackable (without a forced attack)
754 // and
755 // isn't dead
756 if (isAutoAttackable(player) && !isAlikeDead())
757 {
758 // Check the height difference
759 if (Math.abs(player.getZ() - getZ()) < 400) // this max
760 // heigth
761 // difference might
762 // need some
763 // tweaking
764 {
765 // Set the L2PcInstance Intention to AI_INTENTION_ATTACK
766 player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
767 // player.startAttack(this);
768 } else
769 {
770 // Send a Server->Client packet ActionFailed (target is
771 // out
772 // of attack range) to the L2PcInstance player
773 player.sendPacket(new ActionFailed());
774 }
775 } else if (!isAutoAttackable(player))
776 {
777 // Calculate the distance between the L2PcInstance and the
778 // L2NpcInstance
779 if (!isInsideRadius(player, INTERACTION_DISTANCE, false, false))
780 {
781 // player.setCurrentState(L2Character.STATE_INTERACT);
782 // player.setInteractTarget(this);
783 // player.moveTo(this.getX(), this.getY(), this.getZ(),
784 // INTERACTION_DISTANCE);
785
786 // Notify the L2PcInstance AI with AI_INTENTION_INTERACT
787 player.getAI().setIntention(CtrlIntention.AI_INTENTION_INTERACT, this);
788
789 } else
790 {
791 // Send a Server->Client packet SocialAction to the all
792 // L2PcInstance on the _knownPlayer of the L2NpcInstance
793 // to display a social action of the L2NpcInstance on
794 // their
795 // client
796 SocialAction sa = new SocialAction(getObjectId(), Rnd.get(8));
797 broadcastPacket(sa);
798
799 // Open a chat window on client with the text of the
800 // L2NpcInstance
801 if (isEventMob)
802 {
803 L2Event.showEventHtml(player, String.valueOf(getObjectId()));
804 } else if (_isEventVIPNPCEnd)
805 {
806 VIP.showEndHTML(player, String.valueOf(getObjectId()));
807 } else if (_isEventMobCTF)
808 {
809 CTF.showEventHtml(player, String.valueOf(getObjectId()));
810 } else
811 {
812 Quest[] qlst = getTemplate().getEventQuests(Quest.QuestEventType.NPC_FIRST_TALK);
813 if (qlst != null && qlst.length == 1)
814 {
815 qlst[0].notifyFirstTalk(this, player);
816 } else
817 {
818 showChatWindow(player, 0);
819 }
820 }
821 }
822 } else
823 player.sendPacket(new ActionFailed());
824 }
825 }
826
827 /**
828 * Manage and Display the GM console to modify the L2NpcInstance (GM
829 * only).
830 *
831 *
832 * Actions (If the L2PcInstance is a GM only) :
833 *
834 *
Set the L2NpcInstance as target of the L2PcInstance player (if
835 * necessary)
836 *
Send a Server->Client packet MyTargetSelected to the
837 * L2PcInstance player (display the select window)
838 *
If L2NpcInstance is autoAttackable, send a Server->Client packet
839 * StatusUpdate to the L2PcInstance in order to update L2NpcInstance HP
840 * bar
841 *
Send a Server->Client NpcHtmlMessage() containing the GM console
842 * about this L2NpcInstance
843 *
844 *
845 *
846 * Caution : Each group of
847 * Server->Client packet must be terminated by a ActionFailed packet in
848 * order to avoid that client wait an other packet
849 *
850 *
851 * Example of use :
852 *
853 *
Client packet : Action
854 *
855 *
856 *
857 * @param client
858 * The thread that manage the player that pessed Shift
859 * and click on the L2NpcInstance
860 *
861 */
862 @Override
863 public void onActionShift(L2GameClient client)
864 {
865 // Get the L2PcInstance corresponding to the thread
866 L2PcInstance player = client.getActiveChar();
867 if (player == null)
868 {
869 return;
870 }
871
872 // Check if the L2PcInstance is a GM
873 if (player.getAccessLevel() >= Config.GM_ACCESSLEVEL)
874 {
875 // Set the target of the L2PcInstance player
876 player.setTarget(this);
877
878 // Send a Server->Client packet MyTargetSelected to the
879 // L2PcInstance
880 // player
881 // The player.getLevel() - getLevel() permit to display the
882 // correct
883 // color in the select window
884 MyTargetSelected my = new MyTargetSelected(getObjectId(), player.getLevel() - getLevel());
885 player.sendPacket(my);
886
887 // Check if the player is attackable (without a forced attack)
888 if (isAutoAttackable(player))
889 {
890 // Send a Server->Client packet StatusUpdate of the
891 // L2NpcInstance to the L2PcInstance to update its HP bar
892 StatusUpdate su = new StatusUpdate(getObjectId());
893 su.addAttribute(StatusUpdate.CUR_HP, (int) getCurrentHp());
894 su.addAttribute(StatusUpdate.MAX_HP, getMaxHp());
895 player.sendPacket(su);
896 }
897
898 // Send a Server->Client NpcHtmlMessage() containing the GM
899 // console
900 // about this L2NpcInstance
901 NpcHtmlMessage html = new NpcHtmlMessage(0);
902 TextBuilder html1 = new TextBuilder("
");
944 html1.append("");
945
946 html.setHtml(html1.toString());
947 player.sendPacket(html);
948 } else if (Config.GAME_VIEWNPC || Config.GAME_VIEWNPC_COMBAT || Config.GAME_VIEWNPC_BASIC || Config.GAME_VIEWNPC_DROP)
949 {
950 // Set the target of the L2PcInstance player
951 player.setTarget(this);
952
953 // Send a Server->Client packet MyTargetSelected to the
954 // L2PcInstance player
955 // The player.getLevel() - getLevel() permit to display the
956 // correct color in the select window
957 MyTargetSelected my = new MyTargetSelected(getObjectId(), player.getLevel() - getLevel());
958 player.sendPacket(my);
959
960 // Check if the player is attackable (without a forced attack)
961 if (isAutoAttackable(player))
962 {
963 // Send a Server->Client packet StatusUpdate of the
964 // L2NpcInstance to the L2PcInstance to update its HP bar
965 StatusUpdate su = new StatusUpdate(getObjectId());
966 su.addAttribute(StatusUpdate.CUR_HP, (int) getCurrentHp());
967 su.addAttribute(StatusUpdate.MAX_HP, getMaxHp());
968 player.sendPacket(su);
969 }
970
971 NpcHtmlMessage html = new NpcHtmlMessage(0);
972 TextBuilder html1 = new TextBuilder("");
973
974 // npc name
975 html1.append("
L2GuardInstance : Set the pathfile to
1603 * data/html/guard/12006-1.htm (npcId-page number)
1604 *
1605 *
1606 *
1607 * @param npcId
1608 * The Identifier of the L2NpcInstance whose text must be
1609 * display
1610 * @param val
1611 * The number of the page to display
1612 *
1613 */
1614 public String getHtmlPath(int npcId, int val)
1615 {
1616 String pom = "";
1617
1618 if (val == 0)
1619 {
1620 pom = "" + npcId;
1621 } else
1622 {
1623 pom = npcId + "-" + val;
1624 }
1625
1626 String temp = "data/html/default/" + pom + ".htm";
1627
1628 if (!Config.LAZY_CACHE)
1629 {
1630 // If not running lazy cache the file must be in the cache or it
1631 // doesnt exist
1632 if (HtmCache.getInstance().contains(temp))
1633 {
1634 return temp;
1635 }
1636 } else
1637 {
1638 if (HtmCache.getInstance().isLoadable(temp))
1639 {
1640 return temp;
1641 }
1642 }
1643
1644 // If the file is not found, the standard message "I have nothing to say
1645 // to you" is returned
1646 return "data/html/npcdefault.htm";
1647 }
1648
1649 /**
1650 * Open a choose quest window on client with all quests available of the
1651 * L2NpcInstance.
1652 *
1653 *
1654 * Actions :
1655 *
1656 *
Send a Server->Client NpcHtmlMessage containing the text of the
1657 * L2NpcInstance to the L2PcInstance
1658 *
1659 *
1660 *
1661 * @param player
1662 * The L2PcInstance that talk with the L2NpcInstance
1663 * @param quests
1664 * The table containing quests of the L2NpcInstance
1665 *
1666 */
1667 public void showQuestChooseWindow(L2PcInstance player, Quest[] quests)
1668 {
1669 TextBuilder sb = new TextBuilder();
1670
1671 sb.append("Talk about: ");
1672
1673 for (Quest q : quests)
1674 {
1675 sb.append("").append(q.getDescr()).append(" ");
1676 }
1677
1678 sb.append("");
1679
1680 // Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in
1681 // order to display the message of the L2NpcInstance
1682 insertObjectIdAndShowChatWindow(player, sb.toString());
1683 }
1684
1685 /**
1686 * Open a quest window on client with the text of the L2NpcInstance.
1687 *
1688 *
1689 * Actions :
1690 *
1691 *
Get the text of the quest state in the folder
1692 * data/jscript/quests/questId/stateId.htm
1693 *
Send a Server->Client NpcHtmlMessage containing the text of the
1694 * L2NpcInstance to the L2PcInstance
1695 *
Send a Server->Client ActionFailed to the L2PcInstance in order
1696 * to avoid that the client wait another packet
1697 *
1698 *
1699 *
1700 * @param player
1701 * The L2PcInstance that talk with the L2NpcInstance
1702 * @param questId
1703 * The Identifier of the quest to display the message
1704 *
1705 */
1706 public void showQuestWindow(L2PcInstance player, String questId)
1707 {
1708 String content;
1709
1710 if (player.getWeightPenalty() >= 3)
1711 {
1712 player.sendPacket(new SystemMessage(SystemMessageId.INVENTORY_LESS_THAN_80_PERCENT));
1713 return;
1714 }
1715
1716 // FileInputStream fis = null;
1717
1718 // Get the state of the selected quest
1719 QuestState qs = player.getQuestState(questId);
1720
1721 if (qs != null)
1722 {
1723 // If the quest is alreday started, no need to show a window
1724 if (!qs.getQuest().notifyTalk(this, qs))
1725 {
1726 return;
1727 }
1728 } else
1729 {
1730 Quest q = QuestManager.getInstance().getQuest(questId);
1731 if (q != null)
1732 {
1733 // check for start point
1734 Quest[] qlst = getTemplate().getEventQuests(Quest.QuestEventType.QUEST_START);
1735
1736 if (qlst != null && qlst.length > 0)
1737 {
1738 for (int i = 0; i < qlst.length; i++)
1739 {
1740 if (qlst[i] == q)
1741 {
1742 qs = q.newQuestState(player);
1743 // disabled by mr. becouse quest dialog only
1744 // show on
1745 // second click.
1746 // if(qs.getState().getName().equalsIgnoreCase("completed"))
1747 // {
1748 if (!qs.getQuest().notifyTalk(this, qs))
1749 {
1750 return; // no need to show a window
1751 }
1752 // }
1753 break;
1754 }
1755 }
1756 }
1757 }
1758 }
1759
1760 if (qs == null)
1761 {
1762 // no quests found
1763 content = "You are either not carrying out your quest or don't meet the criteria.";
1764 } else
1765 {
1766 questId = qs.getQuest().getName();
1767 String stateId = qs.getStateId();
1768 String path = "data/jscript/quests/" + questId + "/" + stateId + ".htm";
1769 content = HtmCache.getInstance().getHtm(path); // TODO path for
1770 // quests html
1771
1772 if (Config.DEBUG)
1773 {
1774 if (content != null)
1775 {
1776 _log.fine("Showing quest window for quest " + questId + " html path: " + path);
1777 } else
1778 {
1779 _log.fine("File not exists for quest " + questId + " html path: " + path);
1780 }
1781 }
1782 }
1783
1784 // Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in
1785 // order to display the message of the L2NpcInstance
1786 if (content != null)
1787 {
1788 insertObjectIdAndShowChatWindow(player, content);
1789 }
1790
1791 // Send a Server->Client ActionFailed to the L2PcInstance in order to
1792 // avoid that the client wait another packet
1793 player.sendPacket(new ActionFailed());
1794 }
1795
1796 /**
1797 * Collect awaiting quests/start points and display a QuestChooseWindow
1798 * (if several available) or QuestWindow.
1799 *
1800 *
1801 * @param player
1802 * The L2PcInstance that talk with the L2NpcInstance
1803 *
1804 */
1805 public void showQuestWindow(L2PcInstance player)
1806 {
1807 // collect awaiting quests and start points
1808 List options = new FastList();
1809
1810 QuestState[] awaits = player.getQuestsForTalk(getTemplate().npcId);
1811 Quest[] starts = getTemplate().getEventQuests(Quest.QuestEventType.QUEST_START);
1812
1813 // Quests are limited between 1 and 999 because those are the quests
1814 // that are supported by the client.
1815 // By limitting them there, we are allowed to create custom quests at
1816 // higher IDs without interfering
1817 if (awaits != null)
1818 {
1819 for (QuestState x : awaits)
1820 {
1821 if (!options.contains(x))
1822 {
1823 if (x.getQuest().getQuestIntId() > 0 && x.getQuest().getQuestIntId() < 1000)
1824 {
1825 options.add(x.getQuest());
1826 }
1827 }
1828 }
1829 }
1830
1831 if (starts != null)
1832 {
1833 for (Quest x : starts)
1834 {
1835 if (!options.contains(x))
1836 {
1837 if (x.getQuestIntId() > 0 && x.getQuestIntId() < 1000)
1838 {
1839 options.add(x);
1840 }
1841 }
1842 }
1843 }
1844
1845 // Display a QuestChooseWindow (if several quests are available) or
1846 // QuestWindow
1847 if (options.size() > 1)
1848 {
1849 showQuestChooseWindow(player, options.toArray(new Quest[options.size()]));
1850 } else if (options.size() == 1)
1851 {
1852 showQuestWindow(player, options.get(0).getName());
1853 } else
1854 {
1855 showQuestWindow(player, "");
1856 }
1857 }
1858
1859 /**
1860 * Open a Loto window on client with the text of the L2NpcInstance.
1861 *
1862 *
1863 * Actions :
1864 *
1865 *
Get the text of the selected HTML file in function of the npcId
1866 * and of the page number
1867 *
Send a Server->Client NpcHtmlMessage containing the text of the
1868 * L2NpcInstance to the L2PcInstance
1869 *
Send a Server->Client ActionFailed to the L2PcInstance in order
1870 * to avoid that the client wait another packet
1871 *
1872 *
1873 * @param player
1874 * The L2PcInstance that talk with the L2NpcInstance
1875 * @param val
1876 * The number of the page of the L2NpcInstance to display
1877 *
1878 */
1879 // 0 - first buy lottery ticket window
1880 // 1-20 - buttons
1881 // 21 - second buy lottery ticket window
1882 // 22 - selected ticket with 5 numbers
1883 // 23 - current lottery jackpot
1884 // 24 - Previous winning numbers/Prize claim
1885 // >24 - check lottery ticket by item object id
1886 public void showLotoWindow(L2PcInstance player, int val)
1887 {
1888 int npcId = getTemplate().npcId;
1889 String filename;
1890 SystemMessage sm;
1891 NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
1892
1893 if (val == 0) // 0 - first buy lottery ticket window
1894 {
1895 filename = getHtmlPath(npcId, 1);
1896 html.setFile(filename);
1897 } else if (val >= 1 && val <= 21) // 1-20 - buttons, 21 - second
1898 // buy
1899 // lottery ticket window
1900 {
1901 if (!Lottery.getInstance().isStarted())
1902 {
1903 // tickets can't be sold
1904 player.sendPacket(new SystemMessage(SystemMessageId.NO_LOTTERY_TICKETS_CURRENT_SOLD));
1905 return;
1906 }
1907 if (!Lottery.getInstance().isSellableTickets())
1908 {
1909 // tickets can't be sold
1910 player.sendPacket(new SystemMessage(SystemMessageId.NO_LOTTERY_TICKETS_AVAILABLE));
1911 return;
1912 }
1913
1914 filename = getHtmlPath(npcId, 5);
1915 html.setFile(filename);
1916
1917 int count = 0;
1918 int found = 0;
1919 // counting buttons and unsetting button if found
1920 for (int i = 0; i < 5; i++)
1921 {
1922 if (player.getLoto(i) == val)
1923 {
1924 // unsetting button
1925 player.setLoto(i, 0);
1926 found = 1;
1927 } else if (player.getLoto(i) > 0)
1928 {
1929 count++;
1930 }
1931 }
1932
1933 // if not rearched limit 5 and not unseted value
1934 if (count < 5 && found == 0 && val <= 20)
1935 {
1936 for (int i = 0; i < 5; i++)
1937 {
1938 if (player.getLoto(i) == 0)
1939 {
1940 player.setLoto(i, val);
1941 break;
1942 }
1943 }
1944 }
1945
1946 // setting pusshed buttons
1947 count = 0;
1948 for (int i = 0; i < 5; i++)
1949 {
1950 if (player.getLoto(i) > 0)
1951 {
1952 count++;
1953 String button = String.valueOf(player.getLoto(i));
1954 if (player.getLoto(i) < 10)
1955 {
1956 button = "0" + button;
1957 }
1958 String search = "fore=\"L2UI.lottoNum" + button + "\" back=\"L2UI.lottoNum" + button + "a_check\"";
1959 String replace = "fore=\"L2UI.lottoNum" + button + "a_check\" back=\"L2UI.lottoNum" + button + "\"";
1960 html.replace(search, replace);
1961 }
1962 }
1963
1964 if (count == 5)
1965 {
1966 String search = "0\">Return";
1967 String replace = "22\">The winner selected the numbers above.";
1968 html.replace(search, replace);
1969 }
1970 } else if (val == 22) // 22 - selected ticket with 5 numbers
1971 {
1972 if (!Lottery.getInstance().isStarted())
1973 {
1974 // tickets can't be sold
1975 player.sendPacket(new SystemMessage(SystemMessageId.NO_LOTTERY_TICKETS_CURRENT_SOLD));
1976 return;
1977 }
1978 if (!Lottery.getInstance().isSellableTickets())
1979 {
1980 // tickets can't be sold
1981 player.sendPacket(new SystemMessage(SystemMessageId.NO_LOTTERY_TICKETS_AVAILABLE));
1982 return;
1983 }
1984
1985 int price = Config.ALT_LOTTERY_TICKET_PRICE;
1986 int lotonumber = Lottery.getInstance().getId();
1987 int enchant = 0;
1988 int type2 = 0;
1989
1990 for (int i = 0; i < 5; i++)
1991 {
1992 if (player.getLoto(i) == 0)
1993 {
1994 return;
1995 }
1996
1997 if (player.getLoto(i) < 17)
1998 {
1999 enchant += Math.pow(2, player.getLoto(i) - 1);
2000 } else
2001 {
2002 type2 += Math.pow(2, player.getLoto(i) - 17);
2003 }
2004 }
2005 if (player.getAdena() < price)
2006 {
2007 sm = new SystemMessage(SystemMessageId.YOU_NOT_ENOUGH_ADENA);
2008 player.sendPacket(sm);
2009 return;
2010 }
2011 if (!player.reduceAdena("Loto", price, this, true))
2012 {
2013 return;
2014 }
2015 Lottery.getInstance().increasePrize(price);
2016
2017 sm = new SystemMessage(SystemMessageId.ACQUIRED);
2018 sm.addNumber(lotonumber);
2019 sm.addItemName(4442);
2020 player.sendPacket(sm);
2021
2022 L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), 4442);
2023 item.setCount(1);
2024 item.setCustomType1(lotonumber);
2025 item.setEnchantLevel(enchant);
2026 item.setCustomType2(type2);
2027 player.getInventory().addItem("Loto", item, player, this);
2028
2029 InventoryUpdate iu = new InventoryUpdate();
2030 iu.addItem(item);
2031 L2ItemInstance adenaupdate = player.getInventory().getItemByItemId(57);
2032 iu.addModifiedItem(adenaupdate);
2033 player.sendPacket(iu);
2034
2035 filename = getHtmlPath(npcId, 3);
2036 html.setFile(filename);
2037 } else if (val == 23) // 23 - current lottery jackpot
2038 {
2039 filename = getHtmlPath(npcId, 3);
2040 html.setFile(filename);
2041 } else if (val == 24) // 24 - Previous winning numbers/Prize
2042 // claim
2043 {
2044 filename = getHtmlPath(npcId, 4);
2045 html.setFile(filename);
2046
2047 int lotonumber = Lottery.getInstance().getId();
2048 String message = "";
2049 for (L2ItemInstance item : player.getInventory().getItems())
2050 {
2051 if (item == null)
2052 {
2053 continue;
2054 }
2055 if (item.getItemId() == 4442 && item.getCustomType1() < lotonumber)
2056 {
2057 message = message + "" + item.getCustomType1() + " Event Number ";
2058 int[] numbers = Lottery.getInstance().decodeNumbers(item.getEnchantLevel(), item.getCustomType2());
2059 for (int i = 0; i < 5; i++)
2060 {
2061 message += numbers[i] + " ";
2062 }
2063 int[] check = Lottery.getInstance().checkTicket(item);
2064 if (check[0] > 0)
2065 {
2066 switch (check[0])
2067 {
2068 case 1:
2069 message += "- 1st Prize";
2070 break;
2071 case 2:
2072 message += "- 2nd Prize";
2073 break;
2074 case 3:
2075 message += "- 3th Prize";
2076 break;
2077 case 4:
2078 message += "- 4th Prize";
2079 break;
2080 }
2081 message += " " + check[1] + "a.";
2082 }
2083 message += " ";
2084 }
2085 }
2086 if (message == "")
2087 {
2088 message += "There is no winning lottery ticket... ";
2089 }
2090 html.replace("%result%", message);
2091 } else if (val > 24) // >24 - check lottery ticket by
2092 // item object id
2093 {
2094 int lotonumber = Lottery.getInstance().getId();
2095 L2ItemInstance item = player.getInventory().getItemByObjectId(val);
2096 if (item == null || item.getItemId() != 4442 || item.getCustomType1() >= lotonumber)
2097 {
2098 return;
2099 }
2100 int[] check = Lottery.getInstance().checkTicket(item);
2101
2102 sm = new SystemMessage(SystemMessageId.DISSAPEARED_ITEM);
2103 sm.addItemName(4442);
2104 player.sendPacket(sm);
2105
2106 int adena = check[1];
2107 if (adena > 0)
2108 {
2109 player.addAdena("Loto", adena, this, true);
2110 }
2111 player.destroyItem("Loto", item, this, false);
2112 return;
2113 }
2114 html.replace("%objectId%", String.valueOf(getObjectId()));
2115 html.replace("%race%", "" + Lottery.getInstance().getId());
2116 html.replace("%adena%", "" + Lottery.getInstance().getPrize());
2117 html.replace("%ticket_price%", "" + Config.ALT_LOTTERY_TICKET_PRICE);
2118 html.replace("%prize5%", "" + Config.ALT_LOTTERY_5_NUMBER_RATE * 100);
2119 html.replace("%prize4%", "" + Config.ALT_LOTTERY_4_NUMBER_RATE * 100);
2120 html.replace("%prize3%", "" + Config.ALT_LOTTERY_3_NUMBER_RATE * 100);
2121 html.replace("%prize2%", "" + Config.ALT_LOTTERY_2_AND_1_NUMBER_PRIZE);
2122 html.replace("%enddate%", "" + DateFormat.getDateInstance().format(Lottery.getInstance().getEndDate()));
2123 player.sendPacket(html);
2124
2125 // Send a Server->Client ActionFailed to the L2PcInstance in order to
2126 // avoid that the client wait another packet
2127 player.sendPacket(new ActionFailed());
2128 }
2129
2130 public void makeCPRecovery(L2PcInstance player)
2131 {
2132 if (getNpcId() != 31225 && getNpcId() != 31226)
2133 {
2134 return;
2135 }
2136 if (player.isCursedWeaponEquiped())
2137 {
2138 player.sendMessage("Go away, you're not welcome here.");
2139 return;
2140 }
2141
2142 int neededmoney = 100;
2143 SystemMessage sm;
2144 if (!player.reduceAdena("RestoreCP", neededmoney, player.getLastFolkNPC(), true))
2145 {
2146 return;
2147 }
2148 player.setCurrentCp(getCurrentCp() + 5000);
2149 // cp restored
2150 sm = new SystemMessage(SystemMessageId.S1_CP_WILL_BE_RESTORED);
2151 sm.addString(player.getName());
2152 player.sendPacket(sm);
2153 }
2154
2155 /**
2156 * Add Newbie helper buffs to L2Player according to its level.
2157 *
2158 *
2159 * Actions :
2160 *
2161 *
Get the range level in wich player must be to obtain buff
2162 *
If player level is out of range, display a message and return
2163 *
2164 *
According to player level cast buff
2165 *
2166 *
2167 *
2168 * Newbie Helper Buff list is define in sql
2169 * table helper_buff_list
2170 *
2171 *
2172 * @param player
2173 * The L2PcInstance that talk with the L2NpcInstance
2174 *
2175 */
2176 public void makeSupportMagic(L2PcInstance player)
2177 {
2178 if (player == null)
2179 {
2180 return;
2181 }
2182
2183 // Prevent a cursed weapon weilder of being buffed
2184 if (player.isCursedWeaponEquiped())
2185 {
2186 return;
2187 }
2188
2189 int player_level = player.getLevel();
2190 int lowestLevel = 0;
2191 int higestLevel = 0;
2192
2193 // Select the player
2194 setTarget(player);
2195
2196 // Calculate the min and max level between wich the player must be to
2197 // obtain buff
2198 if (player.isMageClass())
2199 {
2200 lowestLevel = HelperBuffTable.getInstance().getMagicClassLowestLevel();
2201 higestLevel = HelperBuffTable.getInstance().getMagicClassHighestLevel();
2202 } else
2203 {
2204 lowestLevel = HelperBuffTable.getInstance().getPhysicClassLowestLevel();
2205 higestLevel = HelperBuffTable.getInstance().getPhysicClassHighestLevel();
2206 }
2207
2208 // If the player is too high level, display a message and return
2209 if (player_level > higestLevel || !player.isNewbie())
2210 {
2211 String content = "Newbie Guide: Only a novice character of level " + higestLevel + " or less can receive my support magic. Your novice character is the first one that you created and raised in this world.";
2212 insertObjectIdAndShowChatWindow(player, content);
2213 return;
2214 }
2215
2216 // If the player is too low level, display a message and return
2217 if (player_level < lowestLevel)
2218 {
2219 String content = "Come back here when you have reached level " + lowestLevel + ". I will give you support magic then.";
2220 insertObjectIdAndShowChatWindow(player, content);
2221 return;
2222 }
2223
2224 L2Skill skill = null;
2225 // Go through the Helper Buff list define in sql table helper_buff_list
2226 // and cast skill
2227 for (L2HelperBuff helperBuffItem : HelperBuffTable.getInstance().getHelperBuffTable())
2228 {
2229 if (helperBuffItem.isMagicClassBuff() == player.isMageClass())
2230 {
2231 if (player_level >= helperBuffItem.getLowerLevel() && player_level <= helperBuffItem.getUpperLevel())
2232 {
2233 skill = SkillTable.getInstance().getInfo(helperBuffItem.getSkillID(), helperBuffItem.getSkillLevel());
2234 if (skill.getSkillType() == SkillType.SUMMON)
2235 {
2236 player.doCast(skill);
2237 } else
2238 {
2239 doCast(skill);
2240 }
2241 }
2242 }
2243 }
2244
2245 }
2246
2247 public void showChatWindow(L2PcInstance player)
2248 {
2249 showChatWindow(player, 0);
2250 }
2251
2252 /**
2253 * Returns true if html exists
2254 *
2255 * @param player
2256 * @param type
2257 * @return boolean
2258 */
2259 private boolean showPkDenyChatWindow(L2PcInstance player, String type)
2260 {
2261 String html = HtmCache.getInstance().getHtm("data/html/" + type + "/" + getNpcId() + "-pk.htm");
2262
2263 if (html != null)
2264 {
2265 NpcHtmlMessage pkDenyMsg = new NpcHtmlMessage(getObjectId());
2266 pkDenyMsg.setHtml(html);
2267 player.sendPacket(pkDenyMsg);
2268 player.sendPacket(new ActionFailed());
2269 return true;
2270 }
2271
2272 return false;
2273 }
2274
2275 /**
2276 * Open a chat window on client with the text of the L2NpcInstance.
2277 *
2278 *
2279 * Actions :
2280 *
2281 *
Get the text of the selected HTML file in function of the npcId
2282 * and of the page number
2283 *
Send a Server->Client NpcHtmlMessage containing the text of the
2284 * L2NpcInstance to the L2PcInstance
2285 *
Send a Server->Client ActionFailed to the L2PcInstance in order
2286 * to avoid that the client wait another packet
2287 *
2288 *
2289 * @param player
2290 * The L2PcInstance that talk with the L2NpcInstance
2291 * @param val
2292 * The number of the page of the L2NpcInstance to display
2293 *
2294 */
2295 public void showChatWindow(L2PcInstance player, int val)
2296 {
2297 if (player.getKarma() > 0)
2298 {
2299 if (!Config.ALT_GAME_KARMA_PLAYER_CAN_SHOP && this instanceof L2MerchantInstance)
2300 {
2301 if (showPkDenyChatWindow(player, "merchant"))
2302 {
2303 return;
2304 }
2305 } else if (!Config.ALT_GAME_KARMA_PLAYER_CAN_USE_GK && this instanceof L2TeleporterInstance)
2306 {
2307 if (showPkDenyChatWindow(player, "teleporter"))
2308 {
2309 return;
2310 }
2311 } else if (!Config.ALT_GAME_KARMA_PLAYER_CAN_USE_WAREHOUSE && this instanceof L2WarehouseInstance)
2312 {
2313 if (showPkDenyChatWindow(player, "warehouse"))
2314 {
2315 return;
2316 }
2317 } else if (!Config.ALT_GAME_KARMA_PLAYER_CAN_SHOP && this instanceof L2FishermanInstance)
2318 {
2319 if (showPkDenyChatWindow(player, "fisherman"))
2320 {
2321 return;
2322 }
2323 }
2324 }
2325
2326 if (getTemplate().type == "L2Auctioneer" && val == 0)
2327 {
2328 return;
2329 }
2330
2331 int npcId = getTemplate().npcId;
2332
2333 /* For use with Seven Signs implementation */
2334 String filename = SevenSigns.SEVEN_SIGNS_HTML_PATH;
2335 int sealAvariceOwner = SevenSigns.getInstance().getSealOwner(SevenSigns.SEAL_AVARICE);
2336 int sealGnosisOwner = SevenSigns.getInstance().getSealOwner(SevenSigns.SEAL_GNOSIS);
2337 int playerCabal = SevenSigns.getInstance().getPlayerCabal(player);
2338 boolean isSealValidationPeriod = SevenSigns.getInstance().isSealValidationPeriod();
2339 int compWinner = SevenSigns.getInstance().getCabalHighestScore();
2340
2341 switch (npcId)
2342 {
2343 case 31078:
2344 case 31079:
2345 case 31080:
2346 case 31081:
2347 case 31082: // Dawn Priests
2348 case 31083:
2349 case 31084:
2350 case 31168:
2351 case 31692:
2352 case 31694:
2353 case 31997:
2354 switch (playerCabal)
2355 {
2356 case SevenSigns.CABAL_DAWN:
2357 if (isSealValidationPeriod)
2358 {
2359 if (compWinner == SevenSigns.CABAL_DAWN)
2360 {
2361 if (compWinner != sealGnosisOwner)
2362 {
2363 filename += "dawn_priest_2c.htm";
2364 } else
2365 {
2366 filename += "dawn_priest_2a.htm";
2367 }
2368 } else
2369 {
2370 filename += "dawn_priest_2b.htm";
2371 }
2372 } else
2373 {
2374 filename += "dawn_priest_1b.htm";
2375 }
2376 break;
2377 case SevenSigns.CABAL_DUSK:
2378 if (isSealValidationPeriod)
2379 {
2380 filename += "dawn_priest_3b.htm";
2381 } else
2382 {
2383 filename += "dawn_priest_3a.htm";
2384 }
2385 break;
2386 default:
2387 if (isSealValidationPeriod)
2388 {
2389 if (compWinner == SevenSigns.CABAL_DAWN)
2390 {
2391 filename += "dawn_priest_4.htm";
2392 } else
2393 {
2394 filename += "dawn_priest_2b.htm";
2395 }
2396 } else
2397 {
2398 filename += "dawn_priest_1a.htm";
2399 }
2400 break;
2401 }
2402 break;
2403 case 31085:
2404 case 31086:
2405 case 31087:
2406 case 31088: // Dusk Priest
2407 case 31089:
2408 case 31090:
2409 case 31091:
2410 case 31169:
2411 case 31693:
2412 case 31695:
2413 case 31998:
2414 switch (playerCabal)
2415 {
2416 case SevenSigns.CABAL_DUSK:
2417 if (isSealValidationPeriod)
2418 {
2419 if (compWinner == SevenSigns.CABAL_DUSK)
2420 {
2421 if (compWinner != sealGnosisOwner)
2422 {
2423 filename += "dusk_priest_2c.htm";
2424 } else
2425 {
2426 filename += "dusk_priest_2a.htm";
2427 }
2428 } else
2429 {
2430 filename += "dusk_priest_2b.htm";
2431 }
2432 } else
2433 {
2434 filename += "dusk_priest_1b.htm";
2435 }
2436 break;
2437 case SevenSigns.CABAL_DAWN:
2438 if (isSealValidationPeriod)
2439 {
2440 filename += "dusk_priest_3b.htm";
2441 } else
2442 {
2443 filename += "dusk_priest_3a.htm";
2444 }
2445 break;
2446 default:
2447 if (isSealValidationPeriod)
2448 {
2449 if (compWinner == SevenSigns.CABAL_DUSK)
2450 {
2451 filename += "dusk_priest_4.htm";
2452 } else
2453 {
2454 filename += "dusk_priest_2b.htm";
2455 }
2456 } else
2457 {
2458 filename += "dusk_priest_1a.htm";
2459 }
2460 break;
2461 }
2462 break;
2463 case 31095: //
2464 case 31096: //
2465 case 31097: //
2466 case 31098: // Enter Necropolises
2467 case 31099: //
2468 case 31100: //
2469 case 31101: //
2470 case 31102: //
2471 if (isSealValidationPeriod)
2472 {
2473 if (playerCabal != compWinner || sealAvariceOwner != compWinner)
2474 {
2475 switch (compWinner)
2476 {
2477 case SevenSigns.CABAL_DAWN:
2478 player.sendPacket(new SystemMessage(SystemMessageId.CAN_BE_USED_BY_DAWN));
2479 filename += "necro_no.htm";
2480 break;
2481 case SevenSigns.CABAL_DUSK:
2482 player.sendPacket(new SystemMessage(SystemMessageId.CAN_BE_USED_BY_DUSK));
2483 filename += "necro_no.htm";
2484 break;
2485 case SevenSigns.CABAL_NULL:
2486 filename = getHtmlPath(npcId, val); // do
2487 // the
2488 // default!
2489 break;
2490 }
2491 } else
2492 {
2493 filename = getHtmlPath(npcId, val); // do the
2494 // default!
2495 }
2496 } else
2497 {
2498 if (playerCabal == SevenSigns.CABAL_NULL)
2499 {
2500 filename += "necro_no.htm";
2501 } else
2502 {
2503 filename = getHtmlPath(npcId, val); // do the
2504 // default!
2505 }
2506 }
2507 break;
2508 case 31114: //
2509 case 31115: //
2510 case 31116: // Enter Catacombs
2511 case 31117: //
2512 case 31118: //
2513 case 31119: //
2514 if (isSealValidationPeriod)
2515 {
2516 if (playerCabal != compWinner || sealGnosisOwner != compWinner)
2517 {
2518 switch (compWinner)
2519 {
2520 case SevenSigns.CABAL_DAWN:
2521 player.sendPacket(new SystemMessage(SystemMessageId.CAN_BE_USED_BY_DAWN));
2522 filename += "cata_no.htm";
2523 break;
2524 case SevenSigns.CABAL_DUSK:
2525 player.sendPacket(new SystemMessage(SystemMessageId.CAN_BE_USED_BY_DUSK));
2526 filename += "cata_no.htm";
2527 break;
2528 case SevenSigns.CABAL_NULL:
2529 filename = getHtmlPath(npcId, val); // do
2530 // the
2531 // default!
2532 break;
2533 }
2534 } else
2535 {
2536 filename = getHtmlPath(npcId, val); // do the
2537 // default!
2538 }
2539 } else
2540 {
2541 if (playerCabal == SevenSigns.CABAL_NULL)
2542 {
2543 filename += "cata_no.htm";
2544 } else
2545 {
2546 filename = getHtmlPath(npcId, val); // do the
2547 // default!
2548 }
2549 }
2550 break;
2551 case 31111: // Gatekeeper Spirit (Disciples)
2552 if (playerCabal == sealAvariceOwner && playerCabal == compWinner)
2553 {
2554 switch (sealAvariceOwner)
2555 {
2556 case SevenSigns.CABAL_DAWN:
2557 filename += "spirit_dawn.htm";
2558 break;
2559 case SevenSigns.CABAL_DUSK:
2560 filename += "spirit_dusk.htm";
2561 break;
2562 case SevenSigns.CABAL_NULL:
2563 filename += "spirit_null.htm";
2564 break;
2565 }
2566 } else
2567 {
2568 filename += "spirit_null.htm";
2569 }
2570 break;
2571 case 31112: // Gatekeeper Spirit (Disciples)
2572 filename += "spirit_exit.htm";
2573 break;
2574 case 31127: //
2575 case 31128: //
2576 case 31129: // Dawn Festival Guides
2577 case 31130: //
2578 case 31131: //
2579 filename += "festival/dawn_guide.htm";
2580 break;
2581 case 31137: //
2582 case 31138: //
2583 case 31139: // Dusk Festival Guides
2584 case 31140: //
2585 case 31141: //
2586 filename += "festival/dusk_guide.htm";
2587 break;
2588 case 31092: // Black Marketeer of Mammon
2589 filename += "blkmrkt_1.htm";
2590 break;
2591 case 31113: // Merchant of Mammon
2592 switch (compWinner)
2593 {
2594 case SevenSigns.CABAL_DAWN:
2595 if (playerCabal != compWinner || playerCabal != sealAvariceOwner)
2596 {
2597 player.sendPacket(new SystemMessage(SystemMessageId.CAN_BE_USED_BY_DAWN));
2598 return;
2599 }
2600 break;
2601 case SevenSigns.CABAL_DUSK:
2602 if (playerCabal != compWinner || playerCabal != sealAvariceOwner)
2603 {
2604 player.sendPacket(new SystemMessage(SystemMessageId.CAN_BE_USED_BY_DUSK));
2605 return;
2606 }
2607 break;
2608 }
2609 filename += "mammmerch_1.htm";
2610 break;
2611 case 31126: // Blacksmith of Mammon
2612 switch (compWinner)
2613 {
2614 case SevenSigns.CABAL_DAWN:
2615 if (playerCabal != compWinner || playerCabal != sealGnosisOwner)
2616 {
2617 player.sendPacket(new SystemMessage(SystemMessageId.CAN_BE_USED_BY_DAWN));
2618 return;
2619 }
2620 break;
2621 case SevenSigns.CABAL_DUSK:
2622 if (playerCabal != compWinner || playerCabal != sealGnosisOwner)
2623 {
2624 player.sendPacket(new SystemMessage(SystemMessageId.CAN_BE_USED_BY_DUSK));
2625 return;
2626 }
2627 break;
2628 }
2629 filename += "mammblack_1.htm";
2630 break;
2631 case 31132:
2632 case 31133:
2633 case 31134:
2634 case 31135:
2635 case 31136: // Festival Witches
2636 case 31142:
2637 case 31143:
2638 case 31144:
2639 case 31145:
2640 case 31146:
2641 filename += "festival/festival_witch.htm";
2642 break;
2643 case 31688:
2644 if (player.isNoble())
2645 {
2646 filename = Olympiad.OLYMPIAD_HTML_FILE + "noble_main.htm";
2647 } else
2648 {
2649 filename = getHtmlPath(npcId, val);
2650 }
2651 break;
2652 case 31690:
2653 case 31769:
2654 case 31770:
2655 case 31771:
2656 case 31772:
2657 if (player.isHero())
2658 {
2659 filename = Olympiad.OLYMPIAD_HTML_FILE + "hero_main.htm";
2660 } else
2661 {
2662 filename = getHtmlPath(npcId, val);
2663 }
2664 break;
2665 default:
2666 if (npcId >= 31865 && npcId <= 31918)
2667 {
2668 filename += "rift/GuardianOfBorder.htm";
2669 break;
2670 }
2671 if (npcId >= 31093 && npcId <= 31094 || npcId >= 31172 && npcId <= 31201 || npcId >= 31239 && npcId <= 31254)
2672 {
2673 return;
2674 }
2675 // Get the text of the selected HTML file in function of the
2676 // npcId and of the page number
2677 filename = getHtmlPath(npcId, val);
2678 break;
2679 }
2680
2681 // Send a Server->Client NpcHtmlMessage containing the text of the
2682 // L2NpcInstance to the L2PcInstance
2683 NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
2684 html.setFile(filename);
2685
2686 // String word = "npc-"+npcId+(val>0 ? "-"+val : "" )+"-dialog-append";
2687
2688 if (this instanceof L2MerchantInstance)
2689 {
2690 if (Config.LIST_PET_RENT_NPC.contains(npcId))
2691 {
2692 html.replace("_Quest", "_RentPet\">Rent Pet Client ActionFailed to the L2PcInstance in order to
2701 // avoid that the client wait another packet
2702 player.sendPacket(new ActionFailed());
2703 }
2704
2705 /**
2706 * Open a chat window on client with the text specified by the given
2707 * file name and path,
2708 * relative to the datapack root.
2709 *
2710 * Added by Tempy
2711 *
2712 * @param player
2713 * The L2PcInstance that talk with the L2NpcInstance
2714 * @param filename
2715 * The filename that contains the text to send
2716 *
2717 */
2718 public void showChatWindow(L2PcInstance player, String filename)
2719 {
2720 // Send a Server->Client NpcHtmlMessage containing the text of the
2721 // L2NpcInstance to the L2PcInstance
2722 NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
2723 html.setFile(filename);
2724 html.replace("%objectId%", String.valueOf(getObjectId()));
2725 player.sendPacket(html);
2726
2727 // Send a Server->Client ActionFailed to the L2PcInstance in order to
2728 // avoid that the client wait another packet
2729 player.sendPacket(new ActionFailed());
2730 }
2731
2732 /**
2733 * Return the Exp Reward of this L2NpcInstance contained in the
2734 * L2NpcTemplate (modified by RATE_XP).
2735 *
2736 */
2737 public int getExpReward()
2738 {
2739 double rateXp = getStat().calcStat(Stats.MAX_HP, 1, this, null);
2740 return (int) (getTemplate().rewardExp * rateXp * Config.RATE_XP);
2741 }
2742
2743 /**
2744 * Return the SP Reward of this L2NpcInstance contained in the
2745 * L2NpcTemplate (modified by RATE_SP).
2746 *
2747 */
2748 public int getSpReward()
2749 {
2750 double rateSp = getStat().calcStat(Stats.MAX_HP, 1, this, null);
2751 return (int) (getTemplate().rewardSp * rateSp * Config.RATE_SP);
2752 }
2753
2754 /**
2755 * Kill the L2NpcInstance (the corpse disappeared after 7 seconds).
2756 *
2757 *
2758 * Actions :
2759 *
2760 *