1 /*2 * This program is free software; you can redistribute it and/or modify3 * it under the terms of the GNU General Public License as published by4 * 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 of9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the10 * GNU General Public License for more details.11 *12 * You should have received a copy of the GNU General Public License13 * along with this program; if not, write to the Free Software14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA15 * 02111-1307, USA.16 *17 * http://www.gnu.org/copyleft/gpl.html18 */19 package net.sf.l2j.gameserver.model.actor.instance;2021 import static net.sf.l2j.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;2223 import java.text.DateFormat;24 import java.util.List;2526 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;9293 /**94 * This class represents a Non-Player-Character in the world. It can be a95 * monster or a friendly character. It also uses a template to fetch some static96 * values. The templates are hardcoded in the client, so we can rely on them.<BR>97 * <BR>98 *99 * L2Character :<BR>100 * <BR>101 * <li>L2Attackable</li>102 * <li>L2BoxInstance</li>103 * <li>L2FolkInstance</li>104 *105 * @version $Revision: 1.32.2.7.2.24 $ $Date: 2005/04/11 10:06:09 $106 */107 public class L2NpcInstance extends L2Character108 {109 // private static Logger _log =110 // Logger.getLogger(L2NpcInstance.class.getName());111112 /**113 * The interaction distance of the L2NpcInstance(is used as offset in114 * MovetoLocation method)115 */116 public static final int INTERACTION_DISTANCE = 150;117118 /** The L2Spawn object that manage this L2NpcInstance */119 private L2Spawn _spawn;120121 /** The flag to specify if this L2NpcInstance is busy */122 private boolean _isBusy = false;123124 /** The busy message for this L2NpcInstance */125 private String _busyMessage = "";126127 /** true if endDecayTask has already been called */128 volatile boolean _isDecayed = false;129130 /** true if a Dwarf has used Spoil on this L2NpcInstance */131 private boolean _isSpoil = false;132133 /**134 * The castle index in the array of L2Castle this L2NpcInstance belongs135 * to136 */137 private int _castleIndex = -2;138139 public boolean isEventMob = false, _isEventVIPNPC = false,140 _isEventVIPNPCEnd = false;141142 public boolean _isEventMobCTF = false;143144 public boolean isPrivateEventMob = false;145146 private boolean _isInTown = false;147148 private int _isSpoiledBy = 0;149150 protected RandomAnimationTask _rAniTask = null;151152 /** Task launching the function onRandomAnimation() */153 protected class RandomAnimationTask implements Runnable154 {155 public void run()156 {157 try158 {159 if (this != _rAniTask)160 {161 return; // Shouldn't happen, but who knows... just to162 // make163 // sure every active npc has only one timer.164 }165 if (isMob())166 {167 // Cancel further animation timers until intention is168 // changed to ACTIVE again.169 if (getAI().getIntention() != AI_INTENTION_ACTIVE)170 {171 return;172 }173 } else174 {175 if (!isInActiveRegion())176 {177 return;178 }179 // update knownlist to remove playable which aren't in180 // range181 // any more182 getKnownList().updateKnownObjects();183 }184185 if (!(isDead() || isStunned() || isSleeping() || isParalyzed()))186 {187 onRandomAnimation();188 }189190 startRandomAnimationTimer();191 } catch (Throwable t)192 {193 }194 }195 }196 197 /**198 * Send a packet SocialAction to all L2PcInstance in the _KnownPlayers199 * of the L2NpcInstance and create a new RandomAnimation Task.<BR>200 * <BR>201 */202 public void onRandomAnimation()203 {204 // Send a packet SocialAction to all L2PcInstance in the _KnownPlayers205 // of the L2NpcInstance206 SocialAction sa = new SocialAction(getObjectId(), Rnd.get(2, 3));207 broadcastPacket(sa);208 }209210 /**211 * Create a RandomAnimation Task that will be launched after the212 * calculated delay.<BR>213 * <BR>214 */215 public void startRandomAnimationTimer()216 {217 if (!hasRandomAnimation())218 {219 return;220 }221222 int minWait = isMob() ? Config.MIN_MONSTER_ANIMATION : Config.MIN_NPC_ANIMATION;223224 int maxWait = isMob() ? Config.MAX_MONSTER_ANIMATION : Config.MAX_NPC_ANIMATION;225226 // Calculate the delay before the next animation227 int interval = Rnd.get(minWait, maxWait) * 1000;228229 // Create a RandomAnimation Task that will be launched after the230 // calculated delay231 _rAniTask = new RandomAnimationTask();232 ThreadPoolManager.getInstance().scheduleGeneral(_rAniTask, interval);233 }234235 /**236 * Check if the server allows Random Animation.<BR>237 * <BR>238 */239 public boolean hasRandomAnimation()240 {241 return Config.MAX_NPC_ANIMATION > 0;242 }243244 public class destroyTemporalNPC implements Runnable245 {246 private L2Spawn _oldSpawn;247248 public destroyTemporalNPC(L2Spawn spawn)249 {250 _oldSpawn = spawn;251 }252253 public void run()254 {255 try256 {257 _oldSpawn.getLastSpawn().deleteMe();258 _oldSpawn.stopRespawn();259 SpawnTable.getInstance().deleteSpawn(_oldSpawn, false);260 } catch (Throwable t)261 {262 t.printStackTrace();263 }264 }265 }266267 public class destroyTemporalSummon implements Runnable268 {269 L2Summon _summon;270271 L2PcInstance _player;272273 public destroyTemporalSummon(L2Summon summon, L2PcInstance player)274 {275 _summon = summon;276 _player = player;277 }278279 public void run()280 {281 _summon.unSummon(_player);282 }283 }284285 /**286 * Constructor of L2NpcInstance (use L2Character constructor).<BR>287 * <BR>288 *289 * <B><U> Actions</U> :</B><BR>290 * <BR>291 * <li>Call the L2Character constructor to set the _template of the292 * L2Character (copy skills from template to object and link293 * _calculators to NPC_STD_CALCULATOR) </li>294 * <li>Set the name of the L2Character</li>295 * <li>Create a RandomAnimation Task that will be launched after the296 * calculated delay if the server allow it </li>297 * <BR>298 * <BR>299 *300 * @param objectId301 * Identifier of the object to initialized302 * @param template303 * The L2NpcTemplate to apply to the NPC304 *305 */306 public L2NpcInstance(int objectId, L2NpcTemplate template)307 {308 // Call the L2Character constructor to set the _template of the309 // L2Character, copy skills from template to object310 // and link _calculators to NPC_STD_CALCULATOR311 super(objectId, template);312 getKnownList(); // init knownlist313 getStat(); // init stats314 getStatus(); // init status315 initCharStatusUpdateValues();316317 // initialize the "current" equipment318 _currentLHandId = getTemplate().lhand;319 _currentRHandId = getTemplate().rhand;320321 if (template == null)322 {323 _log.severe("No template for Npc. Please check your datapack is setup correctly.");324 return;325 }326327 // Set the name of the L2Character328 setName(template.name);329 }330331 @Override332 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 }340341 @Override342 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 }350351 @Override352 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 }360361 /** Return the L2NpcTemplate of the L2NpcInstance. */362 @Override363 public final L2NpcTemplate getTemplate()364 {365 return (L2NpcTemplate) super.getTemplate();366 }367368 /**369 * Return the generic Identifier of this L2NpcInstance contained in the370 * L2NpcTemplate.<BR>371 * <BR>372 */373 public int getNpcId()374 {375 return getTemplate().npcId;376 }377378 @Override379 public boolean isAttackable()380 {381 return false;382 }383384 /**385 * Return the faction Identifier of this L2NpcInstance contained in the386 * L2NpcTemplate.<BR>387 * <BR>388 *389 * <B><U> Concept</U> :</B><BR>390 * <BR>391 * If a NPC belows to a Faction, other NPC of the faction inside the392 * Faction range will help it if it's attacked<BR>393 * <BR>394 *395 */396 public final String getFactionId()397 {398 return getTemplate().factionId;399 }400401 /**402 * Return the Level of this L2NpcInstance contained in the403 * L2NpcTemplate.<BR>404 * <BR>405 */406 @Override407 public final int getLevel()408 {409 return getTemplate().level;410 }411412 /**413 * Return true if the L2NpcInstance is agressive (ex : L2MonsterInstance414 * in function of aggroRange).<BR>415 * <BR>416 */417 public boolean isAggressive()418 {419 return false;420 }421422 /**423 * Return the Aggro Range of this L2NpcInstance contained in the424 * L2NpcTemplate.<BR>425 * <BR>426 */427 public int getAggroRange()428 {429 return getTemplate().aggroRange;430 }431432 /**433 * Return the Faction Range of this L2NpcInstance contained in the434 * L2NpcTemplate.<BR>435 * <BR>436 */437 public int getFactionRange()438 {439 return getTemplate().factionRange;440 }441442 /**443 * Return true if this L2NpcInstance is undead in function of the444 * L2NpcTemplate.<BR>445 * <BR>446 */447 @Override448 public boolean isUndead()449 {450 return getTemplate().isUndead;451 }452453 /**454 * Send a packet NpcInfo with state of abnormal effect to all455 * L2PcInstance in the _KnownPlayers of the L2NpcInstance.<BR>456 * <BR>457 */458 @Override459 public void updateAbnormalEffect()460 {461 // NpcInfo info = new NpcInfo(this);462 // broadcastPacket(info);463464 // Send a Server->Client packet NpcInfo with state of abnormal effect to465 // all L2PcInstance in the _KnownPlayers of the L2NpcInstance466 for (L2PcInstance player : getKnownList().getKnownPlayers().values())467 {468 if (player != null)469 {470 player.sendPacket(new NpcInfo(this, player));471 }472 }473 }474475 /**476 * Return the distance under which the object must be add to477 * _knownObject in function of the object type.<BR>478 * <BR>479 *480 * <B><U> Values </U> :</B><BR>481 * <BR>482 * <li> object is a L2FolkInstance : 0 (don't remember it) </li>483 * <li> object is a L2Character : 0 (don't remember it) </li>484 * <li> object is a L2PlayableInstance : 1500 </li>485 * <li> others : 500 </li>486 * <BR>487 * <BR>488 *489 * <B><U> Overriden in </U> :</B><BR>490 * <BR>491 * <li> L2Attackable</li>492 * <BR>493 * <BR>494 *495 * @param object496 * The Object to add to _knownObject497 *498 */499 public int getDistanceToWatchObject(L2Object object)500 {501 if (object instanceof L2FestivalGuideInstance)502 {503 return 10000;504 }505506 if (object instanceof L2FolkInstance || !(object instanceof L2Character))507 {508 return 0;509 }510511 if (object instanceof L2PlayableInstance)512 {513 return 1500;514 }515516 return 500;517 }518519 /**520 * Return the distance after which the object must be remove from521 * _knownObject in function of the object type.<BR>522 * <BR>523 *524 * <B><U> Values </U> :</B><BR>525 * <BR>526 * <li> object is not a L2Character : 0 (don't remember it) </li>527 * <li> object is a L2FolkInstance : 0 (don't remember it)</li>528 * <li> object is a L2PlayableInstance : 3000 </li>529 * <li> others : 1000 </li>530 * <BR>531 * <BR>532 *533 * <B><U> Overriden in </U> :</B><BR>534 * <BR>535 * <li> L2Attackable</li>536 * <BR>537 * <BR>538 *539 * @param object540 * The Object to remove from _knownObject541 *542 */543 public int getDistanceToForgetObject(L2Object object)544 {545 return 2 * getDistanceToWatchObject(object);546 }547548 /**549 * Return false.<BR>550 * <BR>551 *552 * <B><U> Overriden in </U> :</B><BR>553 * <BR>554 * <li> L2MonsterInstance : Check if the attacker is not another555 * L2MonsterInstance</li>556 * <li> L2PcInstance</li>557 * <BR>558 * <BR>559 */560 @Override561 public boolean isAutoAttackable(@SuppressWarnings("unused")562 L2Character attacker)563 {564 return false;565 }566567 /**568 * Return the Identifier of the item in the left hand of this569 * L2NpcInstance contained in the L2NpcTemplate.<BR>570 * <BR>571 */572 public int getLeftHandItem()573 {574 return _currentLHandId;575 }576577 /**578 * Return the Identifier of the item in the right hand of this579 * L2NpcInstance contained in the L2NpcTemplate.<BR>580 * <BR>581 */582 public int getRightHandItem()583 {584 return _currentRHandId;585 }586587 /**588 * Return true if this L2NpcInstance has drops that can be sweeped.<BR>589 * <BR>590 */591 public boolean isSpoil()592 {593 return _isSpoil;594 }595596 /**597 * Set the spoil state of this L2NpcInstance.<BR>598 * <BR>599 */600 public void setSpoil(boolean isSpoil)601 {602 _isSpoil = isSpoil;603 }604605 public final int getIsSpoiledBy()606 {607 return _isSpoiledBy;608 }609610 public final void setIsSpoiledBy(int value)611 {612 _isSpoiledBy = value;613 }614615 /**616 * Return the busy status of this L2NpcInstance.<BR>617 * <BR>618 */619 public final boolean isBusy()620 {621 return _isBusy;622 }623624 /**625 * Set the busy status of this L2NpcInstance.<BR>626 * <BR>627 */628 public void setBusy(boolean isBusy)629 {630 _isBusy = isBusy;631 }632633 /**634 * Return the busy message of this L2NpcInstance.<BR>635 * <BR>636 */637 public final String getBusyMessage()638 {639 return _busyMessage;640 }641642 /**643 * Set the busy message of this L2NpcInstance.<BR>644 * <BR>645 */646 public void setBusyMessage(String message)647 {648 _busyMessage = message;649 }650651 /**652 * Manage actions when a player click on the L2NpcInstance.<BR>653 * <BR>654 *655 * <B><U> Actions on first click on the L2NpcInstance (Select it)</U> :</B><BR>656 * <BR>657 * <li>Set the L2NpcInstance as target of the L2PcInstance player (if658 * necessary)</li>659 * <li>Send a Server->Client packet MyTargetSelected to the660 * L2PcInstance player (display the select window)</li>661 * <li>If L2NpcInstance is autoAttackable, send a Server->Client packet662 * StatusUpdate to the L2PcInstance in order to update L2NpcInstance HP663 * bar </li>664 * <li>Send a Server->Client packet ValidateLocation to correct the665 * L2NpcInstance position and heading on the client </li>666 * <BR>667 * <BR>668 *669 * <B><U> Actions on second click on the L2NpcInstance (Attack670 * it/Intercat with it)</U> :</B><BR>671 * <BR>672 * <li>Send a Server->Client packet MyTargetSelected to the673 * L2PcInstance player (display the select window)</li>674 * <li>If L2NpcInstance is autoAttackable, notify the L2PcInstance AI675 * with AI_INTENTION_ATTACK (after a height verification)</li>676 * <li>If L2NpcInstance is NOT autoAttackable, notify the L2PcInstance677 * AI with AI_INTENTION_INTERACT (after a distance verification) and678 * show message</li>679 * <BR>680 * <BR>681 *682 * <FONT COLOR=#FF0000><B> <U>Caution</U> : Each group of683 * Server->Client packet must be terminated by a ActionFailed packet in684 * order to avoid that client wait an other packet</B></FONT><BR>685 * <BR>686 *687 * <B><U> Example of use </U> :</B><BR>688 * <BR>689 * <li> Client packet : Action, AttackRequest</li>690 * <BR>691 * <BR>692 *693 * <B><U> Overriden in </U> :</B><BR>694 * <BR>695 * <li> L2ArtefactInstance : Manage only fisrt click to select Artefact</li>696 * <BR>697 * <BR>698 * <li> L2GuardInstance : </li>699 * <BR>700 * <BR>701 *702 * @param player703 * The L2PcInstance that start an action on the704 * L2NpcInstance705 *706 */707 @Override708 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 L2NpcInstance716 if (this != player.getTarget())717 {718 if (Config.DEBUG)719 {720 _log.fine("new target selected:" + getObjectId());721 }722723 // Set the target of the L2PcInstance player724 player.setTarget(this);725726 // Send a Server->Client packet MyTargetSelected to the727 // L2PcInstance728 // player729 // The player.getLevel() - getLevel() permit to display the730 // correct731 // color in the select window732 MyTargetSelected my = new MyTargetSelected(getObjectId(), player.getLevel() - getLevel());733 player.sendPacket(my);734735 // Check if the player is attackable (without a forced attack)736 if (isAutoAttackable(player))737 {738 // Send a Server->Client packet StatusUpdate of the739 // L2NpcInstance to the L2PcInstance to update its HP bar740 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 }745746 // Send a Server->Client packet ValidateLocation to correct the747 // L2NpcInstance position and heading on the client748 player.sendPacket(new ValidateLocation(this));749 } else750 {751 player.sendPacket(new ValidateLocation(this));752753 // Check if the player is attackable (without a forced attack)754 // and755 // isn't dead756 if (isAutoAttackable(player) && !isAlikeDead())757 {758 // Check the height difference759 if (Math.abs(player.getZ() - getZ()) < 400) // this max760 // heigth761 // difference might762 // need some763 // tweaking764 {765 // Set the L2PcInstance Intention to AI_INTENTION_ATTACK766 player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);767 // player.startAttack(this);768 } else769 {770 // Send a Server->Client packet ActionFailed (target is771 // out772 // of attack range) to the L2PcInstance player773 player.sendPacket(new ActionFailed());774 }775 } else if (!isAutoAttackable(player))776 {777 // Calculate the distance between the L2PcInstance and the778 // L2NpcInstance779 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);785786 // Notify the L2PcInstance AI with AI_INTENTION_INTERACT787 player.getAI().setIntention(CtrlIntention.AI_INTENTION_INTERACT, this);788789 } else790 {791 // Send a Server->Client packet SocialAction to the all792 // L2PcInstance on the _knownPlayer of the L2NpcInstance793 // to display a social action of the L2NpcInstance on794 // their795 // client796 SocialAction sa = new SocialAction(getObjectId(), Rnd.get(8));797 broadcastPacket(sa);798799 // Open a chat window on client with the text of the800 // L2NpcInstance801 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 } else811 {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 } else817 {818 showChatWindow(player, 0);819 }820 }821 }822 } else823 player.sendPacket(new ActionFailed());824 }825 }826827 /**828 * Manage and Display the GM console to modify the L2NpcInstance (GM829 * only).<BR>830 * <BR>831 *832 * <B><U> Actions (If the L2PcInstance is a GM only)</U> :</B><BR>833 * <BR>834 * <li>Set the L2NpcInstance as target of the L2PcInstance player (if835 * necessary)</li>836 * <li>Send a Server->Client packet MyTargetSelected to the837 * L2PcInstance player (display the select window)</li>838 * <li>If L2NpcInstance is autoAttackable, send a Server->Client packet839 * StatusUpdate to the L2PcInstance in order to update L2NpcInstance HP840 * bar </li>841 * <li>Send a Server->Client NpcHtmlMessage() containing the GM console842 * about this L2NpcInstance </li>843 * <BR>844 * <BR>845 *846 * <FONT COLOR=#FF0000><B> <U>Caution</U> : Each group of847 * Server->Client packet must be terminated by a ActionFailed packet in848 * order to avoid that client wait an other packet</B></FONT><BR>849 * <BR>850 *851 * <B><U> Example of use </U> :</B><BR>852 * <BR>853 * <li> Client packet : Action</li>854 * <BR>855 * <BR>856 *857 * @param client858 * The thread that manage the player that pessed Shift859 * and click on the L2NpcInstance860 *861 */862 @Override863 public void onActionShift(L2GameClient client)864 {865 // Get the L2PcInstance corresponding to the thread866 L2PcInstance player = client.getActiveChar();867 if (player == null)868 {869 return;870 }871872 // Check if the L2PcInstance is a GM873 if (player.getAccessLevel() >= Config.GM_ACCESSLEVEL)874 {875 // Set the target of the L2PcInstance player876 player.setTarget(this);877878 // Send a Server->Client packet MyTargetSelected to the879 // L2PcInstance880 // player881 // The player.getLevel() - getLevel() permit to display the882 // correct883 // color in the select window884 MyTargetSelected my = new MyTargetSelected(getObjectId(), player.getLevel() - getLevel());885 player.sendPacket(my);886887 // Check if the player is attackable (without a forced attack)888 if (isAutoAttackable(player))889 {890 // Send a Server->Client packet StatusUpdate of the891 // L2NpcInstance to the L2PcInstance to update its HP bar892 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 }897898 // Send a Server->Client NpcHtmlMessage() containing the GM899 // console900 // about this L2NpcInstance901 NpcHtmlMessage html = new NpcHtmlMessage(0);902 TextBuilder html1 = new TextBuilder("<html><body><center><font color=\"LEVEL\">NPC Information</font></center>");903 String className = getClass().getName().substring(43);904 html1.append("<br>");905906 html1.append("Instance Type: " + className + "<br1>Faction: " + getFactionId() + "<br1>Location ID: " + (getSpawn() != null ? getSpawn().getLocation() : 0) + "<br1>");907908 if (this instanceof L2ControllableMobInstance)909 {910 html1.append("Mob Group: " + MobGroupTable.getInstance().getGroupForMob((L2ControllableMobInstance) this).getGroupId() + "<br>");911 } else912 {913 html1.append("Respawn Time: " + (getSpawn() != null ? getSpawn().getRespawnDelay() / 1000 + " Seconds<br>" : "? Seconds<br>"));914 }915916 html1.append("<table border=\"0\" width=\"100%\">");917 html1.append("<tr><td>Object ID</td><td>" + getObjectId() + "</td><td>NPC ID</td><td>" + getTemplate().npcId + "</td></tr>");918 html1.append("<tr><td>Castle</td><td>" + getCastle().getCastleId() + "</td><td>Coords</td><td>" + getX() + "," + getY() + "," + getZ() + "</td></tr>");919 html1.append("<tr><td>Level</td><td>" + getLevel() + "</td><td>Aggro</td><td>" + (this instanceof L2Attackable ? ((L2Attackable) this).getAggroRange() : 0) + "</td></tr>");920 html1.append("</table><br>");921922 html1.append("<font color=\"LEVEL\">Combat</font>");923 html1.append("<table border=\"0\" width=\"100%\">");924 html1.append("<tr><td>Current HP</td><td>" + getCurrentHp() + "</td><td>Current MP</td><td>" + getCurrentMp() + "</td></tr>");925 html1.append("<tr><td>Max.HP</td><td>" + (int) (getMaxHp() / getStat().calcStat(Stats.MAX_HP, 1, this, null)) + "*" + getStat().calcStat(Stats.MAX_HP, 1, this, null) + "</td><td>Max.MP</td><td>" + getMaxMp() + "</td></tr>");926 html1.append("<tr><td>P.Atk.</td><td>" + getPAtk(null) + "</td><td>M.Atk.</td><td>" + getMAtk(null, null) + "</td></tr>");927 html1.append("<tr><td>P.Def.</td><td>" + getPDef(null) + "</td><td>M.Def.</td><td>" + getMDef(null, null) + "</td></tr>");928 html1.append("<tr><td>Accuracy</td><td>" + getAccuracy() + "</td><td>Evasion</td><td>" + getEvasionRate(null) + "</td></tr>");929 html1.append("<tr><td>Critical</td><td>" + getCriticalHit(null, null) + "</td><td>Speed</td><td>" + getRunSpeed() + "</td></tr>");930 html1.append("<tr><td>Atk.Speed</td><td>" + getPAtkSpd() + "</td><td>Cast.Speed</td><td>" + getMAtkSpd() + "</td></tr>");931 html1.append("</table><br>");932933 html1.append("<font color=\"LEVEL\">Basic Stats</font>");934 html1.append("<table border=\"0\" width=\"100%\">");935 html1.append("<tr><td>STR</td><td>" + getSTR() + "</td><td>DEX</td><td>" + getDEX() + "</td><td>CON</td><td>" + getCON() + "</td></tr>");936 html1.append("<tr><td>INT</td><td>" + getINT() + "</td><td>WIT</td><td>" + getWIT() + "</td><td>MEN</td><td>" + getMEN() + "</td></tr>");937 html1.append("</table>");938939 html1.append("<br><center><table><tr><td><button value=\"Edit NPC\" action=\"bypass -h admin_edit_npc " + getTemplate().npcId + "\" width=100 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"><br1></td>");940 html1.append("<td><button value=\"Kill\" action=\"bypass -h admin_kill\" width=40 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"></td><br1></tr>");941 html1.append("<tr><td><button value=\"Show DropList\" action=\"bypass -h admin_show_droplist " + getTemplate().npcId + "\" width=100 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"></td></tr>");942 html1.append("<td><button value=\"Delete\" action=\"bypass -h admin_delete\" width=40 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"></td></tr>");943 html1.append("</table></center><br>");944 html1.append("</body></html>");945946 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 player951 player.setTarget(this);952953 // Send a Server->Client packet MyTargetSelected to the954 // L2PcInstance player955 // The player.getLevel() - getLevel() permit to display the956 // correct color in the select window957 MyTargetSelected my = new MyTargetSelected(getObjectId(), player.getLevel() - getLevel());958 player.sendPacket(my);959960 // Check if the player is attackable (without a forced attack)961 if (isAutoAttackable(player))962 {963 // Send a Server->Client packet StatusUpdate of the964 // L2NpcInstance to the L2PcInstance to update its HP bar965 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 }970971 NpcHtmlMessage html = new NpcHtmlMessage(0);972 TextBuilder html1 = new TextBuilder("<html><body>");973974 // npc name975 html1.append("<center><font color=\"LEVEL\">[Npc]</font></center><br>");976 html1.append(getName());977978 // shows npc combat stats979 if (Config.GAME_VIEWNPC_COMBAT)980 {981 html1.append("<br><center><font color=\"LEVEL\">[Combat Stats]</font></center>");982 html1.append("<table border=0 width=\"100%\">");983 html1.append("<tr><td>Max.HP</td><td>" + (int) (getMaxHp() / getStat().calcStat(Stats.MAX_HP, 1, this, null)) + "*" + (int) getStat().calcStat(Stats.MAX_HP, 1, this, null) + "</td><td>Max.MP</td><td>" + getMaxMp() + "</td></tr>");984 html1.append("<tr><td>P.Atk.</td><td>" + getPAtk(null) + "</td><td>M.Atk.</td><td>" + getMAtk(null, null) + "</td></tr>");985 html1.append("<tr><td>P.Def.</td><td>" + getPDef(null) + "</td><td>M.Def.</td><td>" + getMDef(null, null) + "</td></tr>");986 html1.append("<tr><td>Accuracy</td><td>" + getAccuracy() + "</td><td>Evasion</td><td>" + getEvasionRate(null) + "</td></tr>");987 html1.append("<tr><td>Critical</td><td>" + getCriticalHit(null, null) + "</td><td>Speed</td><td>" + getRunSpeed() + "</td></tr>");988 html1.append("<tr><td>Atk.Speed</td><td>" + getPAtkSpd() + "</td><td>Cast.Speed</td><td>" + getMAtkSpd() + "</td></tr>");989 html1.append("<tr><td>Race</td><td>" + getTemplate().race + "</td><td></td><td></td></tr>");990 html1.append("</table>");991 }992993 // shows basic stats994 if (Config.GAME_VIEWNPC_BASIC)995 {996 html1.append("<br><center><font color=\"LEVEL\">[Basic Stats]</font></center>");997 html1.append("<table border=0 width=\"100%\">");998 html1.append("<tr><td>STR</td><td>" + getSTR() + "</td><td>DEX</td><td>" + getDEX() + "</td><td>CON</td><td>" + getCON() + "</td></tr>");999 html1.append("<tr><td>INT</td><td>" + getINT() + "</td><td>WIT</td><td>" + getWIT() + "</td><td>MEN</td><td>" + getMEN() + "</td></tr>");1000 html1.append("</table>");1001 }10021003 // shows drop stats1004 if (Config.GAME_VIEWNPC_DROP)1005 {1006 html1.append("<br><center><font color=\"LEVEL\">[Drop Info]</font></center>");1007 html1.append("<br>");10081009 for (L2DropCategory cat : getTemplate().getDropData())1010 {1011 for (L2DropData drop : cat.getAllDrops())1012 {1013 if (!Config.GAME_VIEWNPC_QUESTDROP)1014 {1015 // default info about drop item1016 String name = ItemTable.getInstance().getTemplate(drop.getItemId()).getName();1017 int chance = drop.getChance(); // drop chance1018 int min_qty = drop.getMinDrop(); // min. q-ty1019 // of items1020 int max_qty = drop.getMaxDrop(); // max. q-ty1021 // of items10221023 // calculating stats using drop-config1024 if (drop.getItemId() == 57)1025 {1026 chance *= Config.RATE_DROP_ADENA;1027 min_qty *= Config.RATE_DROP_ADENA; // temporary1028 // calculation1029 max_qty *= Config.RATE_DROP_ADENA; // temporary1030 // calculation1031 } else if (cat.isSweep())1032 {1033 chance *= Config.RATE_DROP_SPOIL;1034 } else1035 {1036 chance *= Config.RATE_DROP_ITEMS;1037 }10381039 // chance in percents1040 if (chance > drop.MAX_CHANCE)1041 {1042 chance = drop.getChance();1043 }1044 double percentChance = chance * 0.0001;10451046 // output line (if min. q-ty = max. q-ty shows1047 // only min.)1048 html1.append((drop.isQuestDrop() ? "Quest: " : cat.isSweep() ? "Spoil: " : "Drop: ") + name + " " + percentChance + "%" + " [" + min_qty + (min_qty == max_qty ? "" : " - " + max_qty) + "]<br1>");1049 }1050 }1051 }10521053 html1.append("</body></html>");1054 }10551056 html.setHtml(html1.toString());1057 player.sendPacket(html);1058 }10591060 // Send a Server->Client ActionFailed to the L2PcInstance in order to1061 // avoid that the client wait another packet1062 player.sendPacket(new ActionFailed());1063 }10641065 /** Return the L2Castle this L2NpcInstance belongs to. */1066 public final Castle getCastle()1067 {1068 // Get castle this NPC belongs to (excluding L2Attackable)1069 if (_castleIndex < 0)1070 {1071 L2TownZone town = TownManager.getInstance().getTown(getX(), getY(), getZ());10721073 if (town != null)1074 {1075 _castleIndex = CastleManager.getInstance().getCastleIndex(town.getTaxById());1076 }10771078 if (_castleIndex < 0)1079 {1080 _castleIndex = CastleManager.getInstance().findNearestCastleIndex(this);1081 } else1082 {1083 _isInTown = true; // Npc was spawned in town1084 }1085 }10861087 if (_castleIndex < 0)1088 {1089 return null;1090 }10911092 return CastleManager.getInstance().getCastles().get(_castleIndex);1093 }10941095 public final boolean getIsInTown()1096 {1097 if (_castleIndex < 0)1098 {1099 getCastle();1100 }1101 return _isInTown;1102 }11031104 /**1105 * Open a quest or chat window on client with the text of the1106 * L2NpcInstance in function of the command.<BR>1107 * <BR>1108 *1109 * <B><U> Example of use </U> :</B><BR>1110 * <BR>1111 * <li> Client packet : RequestBypassToServer</li>1112 * <BR>1113 * <BR>1114 *1115 * @param command1116 * The command string received from client1117 *1118 */1119 public void onBypassFeedback(L2PcInstance player, String command)1120 {1121 // Get the distance between the L2PcInstance and the L2NpcInstance1122 if (!isInsideRadius(player, INTERACTION_DISTANCE, false, false))1123 {1124 player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);1125 // player.moveTo(this.getX(), this.getY(), this.getZ(),1126 // INTERACTION_DISTANCE);1127 } else1128 {1129 if (isBusy() && getBusyMessage().length() > 0)1130 {1131 player.sendPacket(new ActionFailed());11321133 NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());1134 html.setFile("data/html/npcbusy.htm");1135 html.replace("%busymessage%", getBusyMessage());1136 html.replace("%npcname%", getName());1137 html.replace("%playername%", player.getName());1138 player.sendPacket(html);1139 } else if (command.equalsIgnoreCase("TerritoryStatus"))1140 {1141 NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());1142 {1143 if (getCastle().getOwnerId() > 0)1144 {1145 html.setFile("data/html/territorystatus.htm");1146 L2Clan clan = ClanTable.getInstance().getClan(getCastle().getOwnerId());1147 html.replace("%clanname%", clan.getName());1148 html.replace("%clanleadername%", clan.getLeaderName());1149 } else1150 {1151 html.setFile("data/html/territorynoclan.htm");1152 }1153 }1154 html.replace("%castlename%", getCastle().getName());1155 html.replace("%taxpercent%", "" + getCastle().getTaxPercent());1156 html.replace("%objectId%", String.valueOf(getObjectId()));1157 {1158 if (getCastle().getCastleId() > 6)1159 {1160 html.replace("%territory%", "The Kingdom of Elmore");1161 } else1162 {1163 html.replace("%territory%", "The Kingdom of Aden");1164 }1165 }1166 player.sendPacket(html);1167 } else if (command.startsWith("Quest"))1168 {1169 String quest = "";1170 try1171 {1172 quest = command.substring(5).trim();1173 } catch (IndexOutOfBoundsException ioobe)1174 {1175 }1176 if (quest.length() == 0)1177 {1178 showQuestWindow(player);1179 } else1180 {1181 showQuestWindow(player, quest);1182 }1183 } else if (command.startsWith("Chat"))1184 {1185 int val = 0;1186 try1187 {1188 val = Integer.parseInt(command.substring(5));1189 } catch (IndexOutOfBoundsException ioobe)1190 {1191 } catch (NumberFormatException nfe)1192 {1193 }1194 showChatWindow(player, val);1195 } else if (command.startsWith("Link"))1196 {1197 String path = command.substring(5).trim();1198 if (path.indexOf("..") != -1)1199 {1200 return;1201 }1202 String filename = "data/html/" + path;1203 NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());1204 html.setFile(filename);1205 html.replace("%objectId%", String.valueOf(getObjectId()));1206 player.sendPacket(html);1207 } else if (command.startsWith("NobleTeleport"))1208 {1209 if (!player.isNoble())1210 {1211 String filename = "data/html/teleporter/nobleteleporter-no.htm";1212 NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());1213 html.setFile(filename);1214 html.replace("%objectId%", String.valueOf(getObjectId()));1215 html.replace("%npcname%", getName());1216 player.sendPacket(html);1217 return;1218 }1219 int val = 0;1220 try1221 {1222 val = Integer.parseInt(command.substring(5));1223 } catch (IndexOutOfBoundsException ioobe)1224 {1225 } catch (NumberFormatException nfe)1226 {1227 }1228 showChatWindow(player, val);1229 } else if (command.startsWith("Loto"))1230 {1231 int val = 0;1232 try1233 {1234 val = Integer.parseInt(command.substring(5));1235 } catch (IndexOutOfBoundsException ioobe)1236 {1237 } catch (NumberFormatException nfe)1238 {1239 }1240 if (val == 0)1241 {1242 // new loto ticket1243 for (int i = 0; i < 5; i++)1244 {1245 player.setLoto(i, 0);1246 }1247 }1248 showLotoWindow(player, val);1249 } else if (command.startsWith("CPRecovery"))1250 {1251 makeCPRecovery(player);1252 } else if (command.startsWith("SupportMagic"))1253 {1254 makeSupportMagic(player);1255 } else if (command.startsWith("multisell"))1256 {1257 L2Multisell.getInstance().SeparateAndSend(Integer.parseInt(command.substring(9).trim()), player, false, getCastle().getTaxRate());1258 } else if (command.startsWith("exc_multisell"))1259 {1260 L2Multisell.getInstance().SeparateAndSend(Integer.parseInt(command.substring(13).trim()), player, true, getCastle().getTaxRate());1261 } else if (command.startsWith("Augment"))1262 {1263 int cmdChoice = Integer.parseInt(command.substring(8, 9).trim());1264 switch (cmdChoice)1265 {1266 case 1:1267 player.sendPacket(new SystemMessage(SystemMessageId.SELECT_THE_ITEM_TO_BE_AUGMENTED));1268 player.sendPacket(new ExShowVariationMakeWindow());1269 break;1270 case 2:1271 player.sendPacket(new SystemMessage(SystemMessageId.SELECT_THE_ITEM_FROM_WHICH_YOU_WISH_TO_REMOVE_AUGMENTATION));1272 player.sendPacket(new ExShowVariationCancelWindow());1273 break;1274 }1275 } else if (command.startsWith("MakeBuffs"))1276 {1277 makeBuffs(player, command.substring(9).trim());1278 } else if (command.startsWith("npcfind_byid"))1279 {1280 try1281 {1282 L2Spawn spawn = SpawnTable.getInstance().getTemplate(Integer.parseInt(command.substring(12).trim()));12831284 if (spawn != null)1285 {1286 player.sendPacket(new RadarControl(0, 1, spawn.getLocx(), spawn.getLocy(), spawn.getLocz()));1287 }1288 } catch (NumberFormatException nfe)1289 {1290 player.sendMessage("Wrong command parameters");1291 }1292 } else if (command.startsWith("newbie_give_coupon"))1293 {1294 try1295 {1296 NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());1297 if (player.getLevel() > 25 || player.getLevel() < 6 || !player.isNewbie())1298 {1299 html.setFile("data/html/adventurers_guide/31760-3.htm");1300 player.sendPacket(html);1301 } else if (player.getCoupon(0))1302 {1303 html.setFile("data/html/adventurers_guide/31760-1.htm");1304 player.sendPacket(html);1305 } else1306 {1307 player.getInventory().addItem("Weapon Coupon", 7832, 1, player, this);1308 player.addCoupon(1);1309 html.setFile("data/html/adventurers_guide/31760-2.htm");1310 player.sendPacket(html);1311 }1312 } catch (NumberFormatException nfe)1313 {1314 player.sendMessage("Wrong command parameters");1315 }1316 } else if (command.startsWith("newbie_give_weapon"))1317 {1318 try1319 {1320 NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());1321 if (player.getLevel() > 25 || player.getLevel() < 6 || !player.isNewbie())1322 {1323 html.setFile("data/html/adventurers_guide/31760-3.htm");1324 player.sendPacket(html);1325 } else1326 /*1327 * if (player.getCoupon(0)) {1328 * html.setFile("data/html/adventurers_guide/31760-1.htm");1329 * player.sendPacket(html); } else1330 */{1331 L2Multisell.getInstance().SeparateAndSend(10010, player, false, getCastle().getTaxRate());1332 }1333 } catch (NumberFormatException nfe)1334 {1335 player.sendMessage("Wrong command parameters");1336 }1337 } else if (command.startsWith("newbie_return_weapon"))1338 {1339 try1340 {1341 NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());1342 if (player.getLevel() > 25 || player.getLevel() < 6 || !player.isNewbie())1343 {1344 html.setFile("data/html/adventurers_guide/31760-3.htm");1345 player.sendPacket(html);1346 } else1347 /*1348 * if (player.getCoupon(0) || !player.isNewbie()) {1349 * html.setFile("data/html/adventurers_guide/31760-1.htm");1350 * player.sendPacket(html); } else1351 */{1352 L2Multisell.getInstance().SeparateAndSend(10011, player, false, getCastle().getTaxRate());1353 }1354 } catch (NumberFormatException nfe)1355 {1356 player.sendMessage("Wrong command parameters");1357 }1358 } else if (command.startsWith("traveller_give_coupon"))1359 {1360 try1361 {1362 NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());1363 if (player.getLevel() > 25 || player.getClassId().level() != 1 || !player.isNewbie())1364 {1365 html.setFile("data/html/adventurers_guide/31760-6.htm");1366 player.sendPacket(html);1367 } else if (player.getCoupon(1))1368 {1369 html.setFile("data/html/adventurers_guide/31760-4.htm");1370 player.sendPacket(html);1371 } else1372 {1373 player.getInventory().addItem("Weapon Coupon", 7833, 1, player, this);1374 player.addCoupon(2);1375 html.setFile("data/html/adventurers_guide/31760-5.htm");1376 player.sendPacket(html);1377 }1378 } catch (NumberFormatException nfe)1379 {1380 player.sendMessage("Wrong command parameters");1381 }1382 } else if (command.startsWith("traveller_give_weapon"))1383 {1384 try1385 {1386 NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());1387 if (player.getLevel() > 25 || player.getClassId().level() != 1 || !player.isNewbie())1388 {1389 html.setFile("data/html/adventurers_guide/31760-6.htm");1390 player.sendPacket(html);1391 } else1392 /*1393 * if (player.getCoupon(1)) {1394 * html.setFile("data/html/adventurers_guide/31760-4.htm");1395 * player.sendPacket(html); } else1396 */{1397 L2Multisell.getInstance().SeparateAndSend(10012, player, false, getCastle().getTaxRate());1398 }1399 } catch (NumberFormatException nfe)1400 {1401 player.sendMessage("Wrong command parameters");1402 }1403 } else if (command.startsWith("traveller_return_weapon"))1404 {1405 try1406 {1407 NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());1408 if (player.getLevel() > 25 || player.getClassId().level() != 1 || !player.isNewbie())1409 {1410 html.setFile("data/html/adventurers_guide/31760-6.htm");1411 player.sendPacket(html);1412 } else1413 /*1414 * if (player.getCoupon(1)) {1415 * html.setFile("data/html/adventurers_guide/31760-4.htm");1416 * player.sendPacket(html); } else1417 */{1418 L2Multisell.getInstance().SeparateAndSend(10013, player, false, getCastle().getTaxRate());1419 }1420 } catch (NumberFormatException nfe)1421 {1422 player.sendMessage("Wrong command parameters");1423 }1424 } else if (command.startsWith("EnterRift"))1425 {1426 try1427 {1428 Byte b1 = Byte.parseByte(command.substring(10)); // Selected1429 // Area:1430 // Recruit,1431 // Soldier1432 // etc1433 DimensionalRiftManager.getInstance().start(player, b1, this);1434 } catch (Exception e)1435 {1436 }1437 } else if (command.startsWith("ChangeRiftRoom"))1438 {1439 if (player.isInParty() && player.getParty().isInDimensionalRift())1440 {1441 player.getParty().getDimensionalRift().manualTeleport(player, this);1442 } else1443 {1444 DimensionalRiftManager.getInstance().handleCheat(player, this);1445 }1446 } else if (command.startsWith("ExitRift"))1447 {1448 if (player.isInParty() && player.getParty().isInDimensionalRift())1449 {1450 player.getParty().getDimensionalRift().manualExitRift(player, this);1451 } else1452 {1453 DimensionalRiftManager.getInstance().handleCheat(player, this);1454 }1455 }1456 }1457 }14581459 /**1460 * Throws an action command to L2BufferInstance.<br>1461 *1462 * @param player1463 * --> Target player1464 * @param buffTemplate1465 * --> Name of the Buff Template to Add1466 */1467 public void makeBuffs(L2PcInstance player, String buffTemplate)1468 {1469 int _templateId = 0;14701471 try1472 {1473 _templateId = Integer.parseInt(buffTemplate);1474 } catch (NumberFormatException e)1475 {1476 _templateId = BuffTemplateTable.getInstance().getTemplateIdByName(buffTemplate);1477 }1478 if (_templateId > 0)1479 {1480 L2BufferInstance.makeBuffs(player, _templateId, this, true);1481 }1482 }14831484 /**1485 * Return null (regular NPCs don't have weapons instancies).<BR>1486 * <BR>1487 */1488 @Override1489 public L2ItemInstance getActiveWeaponInstance()1490 {1491 // regular NPCs dont have weapons instancies1492 return null;1493 }14941495 /**1496 * Return the weapon item equiped in the right hand of the L2NpcInstance1497 * or null.<BR>1498 * <BR>1499 */1500 @Override1501 public L2Weapon getActiveWeaponItem()1502 {1503 // Get the weapon identifier equiped in the right hand of the1504 // L2NpcInstance1505 int weaponId = getTemplate().rhand;15061507 if (weaponId < 1)1508 {1509 return null;1510 }15111512 // Get the weapon item equiped in the right hand of the L2NpcInstance1513 L2Item item = ItemTable.getInstance().getTemplate(getTemplate().rhand);15141515 if (!(item instanceof L2Weapon))1516 {1517 return null;1518 }15191520 return (L2Weapon) item;1521 }15221523 /**1524 * Return null (regular NPCs don't have weapons instancies).<BR>1525 * <BR>1526 */1527 @Override1528 public L2ItemInstance getSecondaryWeaponInstance()1529 {1530 // regular NPCs dont have weapons instancies1531 return null;1532 }15331534 /**1535 * Return the weapon item equiped in the left hand of the L2NpcInstance1536 * or null.<BR>1537 * <BR>1538 */1539 @Override1540 public L2Weapon getSecondaryWeaponItem()1541 {1542 // Get the weapon identifier equiped in the right hand of the1543 // L2NpcInstance1544 int weaponId = getTemplate().lhand;15451546 if (weaponId < 1)1547 {1548 return null;1549 }15501551 // Get the weapon item equiped in the right hand of the L2NpcInstance1552 L2Item item = ItemTable.getInstance().getTemplate(getTemplate().lhand);15531554 if (!(item instanceof L2Weapon))1555 {1556 return null;1557 }15581559 return (L2Weapon) item;1560 }15611562 /**1563 * Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in1564 * order to display the message of the L2NpcInstance.<BR>1565 * <BR>1566 *1567 * @param player1568 * The L2PcInstance who talks with the L2NpcInstance1569 * @param content1570 * The text of the L2NpcMessage1571 *1572 */1573 public void insertObjectIdAndShowChatWindow(L2PcInstance player, String content)1574 {1575 // Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in1576 // order to display the message of the L2NpcInstance1577 content = content.replaceAll("%objectId%", String.valueOf(getObjectId()));1578 NpcHtmlMessage npcReply = new NpcHtmlMessage(getObjectId());1579 npcReply.setHtml(content);1580 player.sendPacket(npcReply);1581 }15821583 /**1584 * Return the pathfile of the selected HTML file in function of the1585 * npcId and of the page number.<BR>1586 * <BR>1587 *1588 * <B><U> Format of the pathfile </U> :</B><BR>1589 * <BR>1590 * <li> if the file exists on the server (page number = 0) :1591 * <B>data/html/default/12006.htm</B> (npcId-page number)</li>1592 * <li> if the file exists on the server (page number > 0) :1593 * <B>data/html/default/12006-1.htm</B> (npcId-page number)</li>1594 * <li> if the file doesn't exist on the server :1595 * <B>data/html/npcdefault.htm</B> (message : "I have nothing to say to1596 * you")</li>1597 * <BR>1598 * <BR>1599 *1600 * <B><U> Overriden in </U> :</B><BR>1601 * <BR>1602 * <li> L2GuardInstance : Set the pathfile to1603 * data/html/guard/12006-1.htm (npcId-page number)</li>1604 * <BR>1605 * <BR>1606 *1607 * @param npcId1608 * The Identifier of the L2NpcInstance whose text must be1609 * display1610 * @param val1611 * The number of the page to display1612 *1613 */1614 public String getHtmlPath(int npcId, int val)1615 {1616 String pom = "";16171618 if (val == 0)1619 {1620 pom = "" + npcId;1621 } else1622 {1623 pom = npcId + "-" + val;1624 }16251626 String temp = "data/html/default/" + pom + ".htm";16271628 if (!Config.LAZY_CACHE)1629 {1630 // If not running lazy cache the file must be in the cache or it1631 // doesnt exist1632 if (HtmCache.getInstance().contains(temp))1633 {1634 return temp;1635 }1636 } else1637 {1638 if (HtmCache.getInstance().isLoadable(temp))1639 {1640 return temp;1641 }1642 }16431644 // If the file is not found, the standard message "I have nothing to say1645 // to you" is returned1646 return "data/html/npcdefault.htm";1647 }16481649 /**1650 * Open a choose quest window on client with all quests available of the1651 * L2NpcInstance.<BR>1652 * <BR>1653 *1654 * <B><U> Actions</U> :</B><BR>1655 * <BR>1656 * <li>Send a Server->Client NpcHtmlMessage containing the text of the1657 * L2NpcInstance to the L2PcInstance </li>1658 * <BR>1659 * <BR>1660 *1661 * @param player1662 * The L2PcInstance that talk with the L2NpcInstance1663 * @param quests1664 * The table containing quests of the L2NpcInstance1665 *1666 */1667 public void showQuestChooseWindow(L2PcInstance player, Quest[] quests)1668 {1669 TextBuilder sb = new TextBuilder();16701671 sb.append("<html><body><title>Talk about:</title><br>");16721673 for (Quest q : quests)1674 {1675 sb.append("<a action=\"bypass -h npc_").append(getObjectId()).append("_Quest ").append(q.getName()).append("\">").append(q.getDescr()).append("</a><br>");1676 }16771678 sb.append("</body></html>");16791680 // Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in1681 // order to display the message of the L2NpcInstance1682 insertObjectIdAndShowChatWindow(player, sb.toString());1683 }16841685 /**1686 * Open a quest window on client with the text of the L2NpcInstance.<BR>1687 * <BR>1688 *1689 * <B><U> Actions</U> :</B><BR>1690 * <BR>1691 * <li>Get the text of the quest state in the folder1692 * data/jscript/quests/questId/stateId.htm </li>1693 * <li>Send a Server->Client NpcHtmlMessage containing the text of the1694 * L2NpcInstance to the L2PcInstance </li>1695 * <li>Send a Server->Client ActionFailed to the L2PcInstance in order1696 * to avoid that the client wait another packet </li>1697 * <BR>1698 * <BR>1699 *1700 * @param player1701 * The L2PcInstance that talk with the L2NpcInstance1702 * @param questId1703 * The Identifier of the quest to display the message1704 *1705 */1706 public void showQuestWindow(L2PcInstance player, String questId)1707 {1708 String content;17091710 if (player.getWeightPenalty() >= 3)1711 {1712 player.sendPacket(new SystemMessage(SystemMessageId.INVENTORY_LESS_THAN_80_PERCENT));1713 return;1714 }17151716 // FileInputStream fis = null;17171718 // Get the state of the selected quest1719 QuestState qs = player.getQuestState(questId);17201721 if (qs != null)1722 {1723 // If the quest is alreday started, no need to show a window1724 if (!qs.getQuest().notifyTalk(this, qs))1725 {1726 return;1727 }1728 } else1729 {1730 Quest q = QuestManager.getInstance().getQuest(questId);1731 if (q != null)1732 {1733 // check for start point1734 Quest[] qlst = getTemplate().getEventQuests(Quest.QuestEventType.QUEST_START);17351736 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 only1744 // show on1745 // 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 window1751 }1752 // }1753 break;1754 }1755 }1756 }1757 }1758 }17591760 if (qs == null)1761 {1762 // no quests found1763 content = "<html><body>You are either not carrying out your quest or don't meet the criteria.</body></html>";1764 } else1765 {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 for1770 // quests html17711772 if (Config.DEBUG)1773 {1774 if (content != null)1775 {1776 _log.fine("Showing quest window for quest " + questId + " html path: " + path);1777 } else1778 {1779 _log.fine("File not exists for quest " + questId + " html path: " + path);1780 }1781 }1782 }17831784 // Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in1785 // order to display the message of the L2NpcInstance1786 if (content != null)1787 {1788 insertObjectIdAndShowChatWindow(player, content);1789 }17901791 // Send a Server->Client ActionFailed to the L2PcInstance in order to1792 // avoid that the client wait another packet1793 player.sendPacket(new ActionFailed());1794 }17951796 /**1797 * Collect awaiting quests/start points and display a QuestChooseWindow1798 * (if several available) or QuestWindow.<BR>1799 * <BR>1800 *1801 * @param player1802 * The L2PcInstance that talk with the L2NpcInstance1803 *1804 */1805 public void showQuestWindow(L2PcInstance player)1806 {1807 // collect awaiting quests and start points1808 List<Quest> options = new FastList<Quest>();18091810 QuestState[] awaits = player.getQuestsForTalk(getTemplate().npcId);1811 Quest[] starts = getTemplate().getEventQuests(Quest.QuestEventType.QUEST_START);18121813 // Quests are limited between 1 and 999 because those are the quests1814 // that are supported by the client.1815 // By limitting them there, we are allowed to create custom quests at1816 // higher IDs without interfering1817 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 }18301831 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 }18441845 // Display a QuestChooseWindow (if several quests are available) or1846 // QuestWindow1847 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 } else1854 {1855 showQuestWindow(player, "");1856 }1857 }18581859 /**1860 * Open a Loto window on client with the text of the L2NpcInstance.<BR>1861 * <BR>1862 *1863 * <B><U> Actions</U> :</B><BR>1864 * <BR>1865 * <li>Get the text of the selected HTML file in function of the npcId1866 * and of the page number </li>1867 * <li>Send a Server->Client NpcHtmlMessage containing the text of the1868 * L2NpcInstance to the L2PcInstance </li>1869 * <li>Send a Server->Client ActionFailed to the L2PcInstance in order1870 * to avoid that the client wait another packet </li>1871 * <BR>1872 *1873 * @param player1874 * The L2PcInstance that talk with the L2NpcInstance1875 * @param val1876 * The number of the page of the L2NpcInstance to display1877 *1878 */1879 // 0 - first buy lottery ticket window1880 // 1-20 - buttons1881 // 21 - second buy lottery ticket window1882 // 22 - selected ticket with 5 numbers1883 // 23 - current lottery jackpot1884 // 24 - Previous winning numbers/Prize claim1885 // >24 - check lottery ticket by item object id1886 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());18921893 if (val == 0) // 0 - first buy lottery ticket window1894 {1895 filename = getHtmlPath(npcId, 1);1896 html.setFile(filename);1897 } else if (val >= 1 && val <= 21) // 1-20 - buttons, 21 - second1898 // buy1899 // lottery ticket window1900 {1901 if (!Lottery.getInstance().isStarted())1902 {1903 // tickets can't be sold1904 player.sendPacket(new SystemMessage(SystemMessageId.NO_LOTTERY_TICKETS_CURRENT_SOLD));1905 return;1906 }1907 if (!Lottery.getInstance().isSellableTickets())1908 {1909 // tickets can't be sold1910 player.sendPacket(new SystemMessage(SystemMessageId.NO_LOTTERY_TICKETS_AVAILABLE));1911 return;1912 }19131914 filename = getHtmlPath(npcId, 5);1915 html.setFile(filename);19161917 int count = 0;1918 int found = 0;1919 // counting buttons and unsetting button if found1920 for (int i = 0; i < 5; i++)1921 {1922 if (player.getLoto(i) == val)1923 {1924 // unsetting button1925 player.setLoto(i, 0);1926 found = 1;1927 } else if (player.getLoto(i) > 0)1928 {1929 count++;1930 }1931 }19321933 // if not rearched limit 5 and not unseted value1934 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 }19451946 // setting pusshed buttons1947 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 }19631964 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 numbers1971 {1972 if (!Lottery.getInstance().isStarted())1973 {1974 // tickets can't be sold1975 player.sendPacket(new SystemMessage(SystemMessageId.NO_LOTTERY_TICKETS_CURRENT_SOLD));1976 return;1977 }1978 if (!Lottery.getInstance().isSellableTickets())1979 {1980 // tickets can't be sold1981 player.sendPacket(new SystemMessage(SystemMessageId.NO_LOTTERY_TICKETS_AVAILABLE));1982 return;1983 }19841985 int price = Config.ALT_LOTTERY_TICKET_PRICE;1986 int lotonumber = Lottery.getInstance().getId();1987 int enchant = 0;1988 int type2 = 0;19891990 for (int i = 0; i < 5; i++)1991 {1992 if (player.getLoto(i) == 0)1993 {1994 return;1995 }19961997 if (player.getLoto(i) < 17)1998 {1999 enchant += Math.pow(2, player.getLoto(i) - 1);2000 } else2001 {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);20162017 sm = new SystemMessage(SystemMessageId.ACQUIRED);2018 sm.addNumber(lotonumber);2019 sm.addItemName(4442);2020 player.sendPacket(sm);20212022 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);20282029 InventoryUpdate iu = new InventoryUpdate();2030 iu.addItem(item);2031 L2ItemInstance adenaupdate = player.getInventory().getItemByItemId(57);2032 iu.addModifiedItem(adenaupdate);2033 player.sendPacket(iu);20342035 filename = getHtmlPath(npcId, 3);2036 html.setFile(filename);2037 } else if (val == 23) // 23 - current lottery jackpot2038 {2039 filename = getHtmlPath(npcId, 3);2040 html.setFile(filename);2041 } else if (val == 24) // 24 - Previous winning numbers/Prize2042 // claim2043 {2044 filename = getHtmlPath(npcId, 4);2045 html.setFile(filename);20462047 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 + "<a action=\"bypass -h npc_%objectId%_Loto " + item.getObjectId() + "\">" + 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 += "</a><br>";2084 }2085 }2086 if (message == "")2087 {2088 message += "There is no winning lottery ticket...<br>";2089 }2090 html.replace("%result%", message);2091 } else if (val > 24) // >24 - check lottery ticket by2092 // item object id2093 {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);21012102 sm = new SystemMessage(SystemMessageId.DISSAPEARED_ITEM);2103 sm.addItemName(4442);2104 player.sendPacket(sm);21052106 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);21242125 // Send a Server->Client ActionFailed to the L2PcInstance in order to2126 // avoid that the client wait another packet2127 player.sendPacket(new ActionFailed());2128 }21292130 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 }21412142 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 restored2150 sm = new SystemMessage(SystemMessageId.S1_CP_WILL_BE_RESTORED);2151 sm.addString(player.getName());2152 player.sendPacket(sm);2153 }21542155 /**2156 * Add Newbie helper buffs to L2Player according to its level.<BR>2157 * <BR>2158 *2159 * <B><U> Actions</U> :</B><BR>2160 * <BR>2161 * <li>Get the range level in wich player must be to obtain buff </li>2162 * <li>If player level is out of range, display a message and return2163 * </li>2164 * <li>According to player level cast buff </li>2165 * <BR>2166 * <BR>2167 *2168 * <FONT COLOR=#FF0000><B> Newbie Helper Buff list is define in sql2169 * table helper_buff_list</B></FONT><BR>2170 * <BR>2171 *2172 * @param player2173 * The L2PcInstance that talk with the L2NpcInstance2174 *2175 */2176 public void makeSupportMagic(L2PcInstance player)2177 {2178 if (player == null)2179 {2180 return;2181 }21822183 // Prevent a cursed weapon weilder of being buffed2184 if (player.isCursedWeaponEquiped())2185 {2186 return;2187 }21882189 int player_level = player.getLevel();2190 int lowestLevel = 0;2191 int higestLevel = 0;21922193 // Select the player2194 setTarget(player);21952196 // Calculate the min and max level between wich the player must be to2197 // obtain buff2198 if (player.isMageClass())2199 {2200 lowestLevel = HelperBuffTable.getInstance().getMagicClassLowestLevel();2201 higestLevel = HelperBuffTable.getInstance().getMagicClassHighestLevel();2202 } else2203 {2204 lowestLevel = HelperBuffTable.getInstance().getPhysicClassLowestLevel();2205 higestLevel = HelperBuffTable.getInstance().getPhysicClassHighestLevel();2206 }22072208 // If the player is too high level, display a message and return2209 if (player_level > higestLevel || !player.isNewbie())2210 {2211 String content = "<html><body>Newbie Guide:<br>Only a <font color=\"LEVEL\">novice character of level " + higestLevel + " 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>";2212 insertObjectIdAndShowChatWindow(player, content);2213 return;2214 }22152216 // If the player is too low level, display a message and return2217 if (player_level < lowestLevel)2218 {2219 String content = "<html><body>Come back here when you have reached level " + lowestLevel + ". I will give you support magic then.</body></html>";2220 insertObjectIdAndShowChatWindow(player, content);2221 return;2222 }22232224 L2Skill skill = null;2225 // Go through the Helper Buff list define in sql table helper_buff_list2226 // and cast skill2227 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 } else2238 {2239 doCast(skill);2240 }2241 }2242 }2243 }22442245 }22462247 public void showChatWindow(L2PcInstance player)2248 {2249 showChatWindow(player, 0);2250 }22512252 /**2253 * Returns true if html exists2254 *2255 * @param player2256 * @param type2257 * @return boolean2258 */2259 private boolean showPkDenyChatWindow(L2PcInstance player, String type)2260 {2261 String html = HtmCache.getInstance().getHtm("data/html/" + type + "/" + getNpcId() + "-pk.htm");22622263 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 }22712272 return false;2273 }22742275 /**2276 * Open a chat window on client with the text of the L2NpcInstance.<BR>2277 * <BR>2278 *2279 * <B><U> Actions</U> :</B><BR>2280 * <BR>2281 * <li>Get the text of the selected HTML file in function of the npcId2282 * and of the page number </li>2283 * <li>Send a Server->Client NpcHtmlMessage containing the text of the2284 * L2NpcInstance to the L2PcInstance </li>2285 * <li>Send a Server->Client ActionFailed to the L2PcInstance in order2286 * to avoid that the client wait another packet </li>2287 * <BR>2288 *2289 * @param player2290 * The L2PcInstance that talk with the L2NpcInstance2291 * @param val2292 * The number of the page of the L2NpcInstance to display2293 *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 }23252326 if (getTemplate().type == "L2Auctioneer" && val == 0)2327 {2328 return;2329 }23302331 int npcId = getTemplate().npcId;23322333 /* 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();23402341 switch (npcId)2342 {2343 case 31078:2344 case 31079:2345 case 31080:2346 case 31081:2347 case 31082: // Dawn Priests2348 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 } else2365 {2366 filename += "dawn_priest_2a.htm";2367 }2368 } else2369 {2370 filename += "dawn_priest_2b.htm";2371 }2372 } else2373 {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 } else2382 {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 } else2393 {2394 filename += "dawn_priest_2b.htm";2395 }2396 } else2397 {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 Priest2407 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 } else2425 {2426 filename += "dusk_priest_2a.htm";2427 }2428 } else2429 {2430 filename += "dusk_priest_2b.htm";2431 }2432 } else2433 {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 } else2442 {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 } else2453 {2454 filename += "dusk_priest_2b.htm";2455 }2456 } else2457 {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 Necropolises2467 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); // do2487 // the2488 // default!2489 break;2490 }2491 } else2492 {2493 filename = getHtmlPath(npcId, val); // do the2494 // default!2495 }2496 } else2497 {2498 if (playerCabal == SevenSigns.CABAL_NULL)2499 {2500 filename += "necro_no.htm";2501 } else2502 {2503 filename = getHtmlPath(npcId, val); // do the2504 // default!2505 }2506 }2507 break;2508 case 31114: //2509 case 31115: //2510 case 31116: // Enter Catacombs2511 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); // do2530 // the2531 // default!2532 break;2533 }2534 } else2535 {2536 filename = getHtmlPath(npcId, val); // do the2537 // default!2538 }2539 } else2540 {2541 if (playerCabal == SevenSigns.CABAL_NULL)2542 {2543 filename += "cata_no.htm";2544 } else2545 {2546 filename = getHtmlPath(npcId, val); // do the2547 // 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 } else2567 {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 Guides2577 case 31130: //2578 case 31131: //2579 filename += "festival/dawn_guide.htm";2580 break;2581 case 31137: //2582 case 31138: //2583 case 31139: // Dusk Festival Guides2584 case 31140: //2585 case 31141: //2586 filename += "festival/dusk_guide.htm";2587 break;2588 case 31092: // Black Marketeer of Mammon2589 filename += "blkmrkt_1.htm";2590 break;2591 case 31113: // Merchant of Mammon2592 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 Mammon2612 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 Witches2636 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 } else2648 {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 } else2661 {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 the2676 // npcId and of the page number2677 filename = getHtmlPath(npcId, val);2678 break;2679 }26802681 // Send a Server->Client NpcHtmlMessage containing the text of the2682 // L2NpcInstance to the L2PcInstance2683 NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());2684 html.setFile(filename);26852686 // String word = "npc-"+npcId+(val>0 ? "-"+val : "" )+"-dialog-append";26872688 if (this instanceof L2MerchantInstance)2689 {2690 if (Config.LIST_PET_RENT_NPC.contains(npcId))2691 {2692 html.replace("_Quest", "_RentPet\">Rent Pet</a><br><a action=\"bypass -h npc_%objectId%_Quest");2693 }2694 }26952696 html.replace("%objectId%", String.valueOf(getObjectId()));2697 html.replace("%festivalMins%", SevenSignsFestival.getInstance().getTimeToNextFestivalStr());2698 player.sendPacket(html);26992700 // Send a Server->Client ActionFailed to the L2PcInstance in order to2701 // avoid that the client wait another packet2702 player.sendPacket(new ActionFailed());2703 }27042705 /**2706 * Open a chat window on client with the text specified by the given2707 * file name and path,<BR>2708 * relative to the datapack root. <BR>2709 * <BR>2710 * Added by Tempy2711 *2712 * @param player2713 * The L2PcInstance that talk with the L2NpcInstance2714 * @param filename2715 * The filename that contains the text to send2716 *2717 */2718 public void showChatWindow(L2PcInstance player, String filename)2719 {2720 // Send a Server->Client NpcHtmlMessage containing the text of the2721 // L2NpcInstance to the L2PcInstance2722 NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());2723 html.setFile(filename);2724 html.replace("%objectId%", String.valueOf(getObjectId()));2725 player.sendPacket(html);27262727 // Send a Server->Client ActionFailed to the L2PcInstance in order to2728 // avoid that the client wait another packet2729 player.sendPacket(new ActionFailed());2730 }27312732 /**2733 * Return the Exp Reward of this L2NpcInstance contained in the2734 * L2NpcTemplate (modified by RATE_XP).<BR>2735 * <BR>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 }27422743 /**2744 * Return the SP Reward of this L2NpcInstance contained in the2745 * L2NpcTemplate (modified by RATE_SP).<BR>2746 * <BR>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 }27532754 /**2755 * Kill the L2NpcInstance (the corpse disappeared after 7 seconds).<BR>2756 * <BR>2757 *2758 * <B><U> Actions</U> :</B><BR>2759 * <BR>2760 * <li>Create a DecayTask to remove the corpse of the L2NpcInstance2761 * after 7 seconds </li>2762 * <li>Set target to null and cancel Attack or Cast </li>2763 * <li>Stop movement </li>2764 * <li>Stop HP/MP/CP Regeneration task </li>2765 * <li>Stop all active skills effects in progress on the L2Character2766 * </li>2767 * <li>Send the Server->Client packet StatusUpdate with current HP and2768 * MP to all other L2PcInstance to inform </li>2769 * <li>Notify L2Character AI </li>2770 * <BR>2771 * <BR>2772 *2773 * <B><U> Overriden in </U> :</B><BR>2774 * <BR>2775 * <li> L2Attackable </li>2776 * <BR>2777 * <BR>2778 *2779 * @param killer2780 * The L2Character who killed it2781 *2782 */2783 @Override2784 public boolean doDie(L2Character killer)2785 {2786 if (!super.doDie(killer))2787 {2788 return false;2789 }27902791 // normally this wouldn't really be needed, but for those few exceptions,2792 // we do need to reset the weapons back to the initial templated weapon.2793 _currentLHandId = getTemplate().lhand;2794 _currentRHandId = getTemplate().rhand;279527962797 DecayTaskManager.getInstance().addDecayTask(this);2798 return true;2799 }28002801 /**2802 * Set the spawn of the L2NpcInstance.<BR>2803 * <BR>2804 *2805 * @param spawn2806 * The L2Spawn that manage the L2NpcInstance2807 *2808 */2809 public void setSpawn(L2Spawn spawn)2810 {2811 _spawn = spawn;2812 }28132814 @Override2815 public void onSpawn()2816 {2817 super.onSpawn();2818 }28192820 /**2821 * Remove the L2NpcInstance from the world and update its spawn object2822 * (for a complete removal use the deleteMe method).<BR>2823 * <BR>2824 *2825 * <B><U> Actions</U> :</B><BR>2826 * <BR>2827 * <li>Remove the L2NpcInstance from the world when the decay task is2828 * launched </li>2829 * <li>Decrease its spawn counter </li>2830 * <li>Manage Siege task (killFlag, killCT) </li>2831 * <BR>2832 * <BR>2833 *2834 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T REMOVE2835 * the object from _allObjects of L2World </B></FONT><BR>2836 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND2837 * Server->Client packets to players</B></FONT><BR>2838 * <BR>2839 *2840 */2841 @Override2842 public void onDecay()2843 {2844 if (isDecayed())2845 {2846 return;2847 }2848 setDecayed(true);28492850 // Manage Life Control Tower2851 if (this instanceof L2ControlTowerInstance)2852 {2853 ((L2ControlTowerInstance) this).onDeath();2854 }28552856 // Remove the L2NpcInstance from the world when the decay task is2857 // launched2858 super.onDecay();28592860 // Decrease its spawn counter2861 if (_spawn != null)2862 {2863 _spawn.decreaseCount(this);2864 }2865 }28662867 /**2868 * Remove PROPERLY the L2NpcInstance from the world.<BR>2869 * <BR>2870 *2871 * <B><U> Actions</U> :</B><BR>2872 * <BR>2873 * <li>Remove the L2NpcInstance from the world and update its spawn2874 * object </li>2875 * <li>Remove all L2Object from _knownObjects and _knownPlayer of the2876 * L2NpcInstance then cancel Attak or Cast and notify AI </li>2877 * <li>Remove L2Object object from _allObjects of L2World </li>2878 * <BR>2879 * <BR>2880 *2881 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND2882 * Server->Client packets to players</B></FONT><BR>2883 * <BR>2884 *2885 */2886 public void deleteMe()2887 {2888 if (getWorldRegion() != null)2889 {2890 getWorldRegion().removeFromZones(this);2891 // FIXME this is just a temp hack, we should find a better2892 // solution2893 }28942895 try2896 {2897 decayMe();2898 } catch (Throwable t)2899 {2900 _log.severe("deletedMe(): " + t);2901 }29022903 // Remove all L2Object from _knownObjects and _knownPlayer of the2904 // L2Character then cancel Attak or Cast and notify AI2905 try2906 {2907 getKnownList().removeAllKnownObjects();2908 } catch (Throwable t)2909 {2910 _log.severe("deletedMe(): " + t);2911 }29122913 // Remove L2Object object from _allObjects of L2World2914 L2World.getInstance().removeObject(this);2915 }29162917 /**2918 * Return the L2Spawn object that manage this L2NpcInstance.<BR>2919 * <BR>2920 */2921 public L2Spawn getSpawn()2922 {2923 return _spawn;2924 }29252926 @Override2927 public String toString()2928 {2929 return getTemplate().name;2930 }29312932 public boolean isDecayed()2933 {2934 return _isDecayed;2935 }29362937 public void setDecayed(boolean decayed)2938 {2939 _isDecayed = decayed;2940 }29412942 public void endDecayTask()2943 {2944 if (!isDecayed())2945 {2946 DecayTaskManager.getInstance().cancelDecayTask(this);2947 onDecay();2948 }2949 }29502951 public boolean isMob() // rather delete this check2952 {2953 return false; // This means we use MAX_NPC_ANIMATION instead of2954 // MAX_MONSTER_ANIMATION2955 } 29562957 // Two functions to change the appearance of the equipped weapons on the NPC2958 // This is only useful for a few NPCs and is most likely going to be called from AI2959 public void setLHandId(int newWeaponId)2960 {2961 _currentLHandId = newWeaponId;2962 }2963 public void setRHandId(int newWeaponId)2964 {2965 _currentRHandId = newWeaponId;2966 } 2967 }