Advertisement
Guest User

Untitled

a guest
Mar 5th, 2015
245
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 48.26 KB | None | 0 0
  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.quest;
  20.  
  21. import java.io.PrintWriter;
  22. import java.io.StringWriter;
  23. import java.sql.PreparedStatement;
  24. import java.sql.ResultSet;
  25. import java.util.Collection;
  26. import java.util.List;
  27. import java.util.Map;
  28. import java.util.logging.Level;
  29. import java.util.logging.Logger;
  30.  
  31. import javolution.util.FastList;
  32. import javolution.util.FastMap;
  33.  
  34. import net.sf.l2j.Config;
  35. import net.sf.l2j.L2DatabaseFactory;
  36. import net.sf.l2j.gameserver.ThreadPoolManager;
  37. import net.sf.l2j.gameserver.cache.HtmCache;
  38. import net.sf.l2j.gameserver.datatables.NpcTable;
  39. import net.sf.l2j.gameserver.idfactory.IdFactory;
  40. import net.sf.l2j.gameserver.instancemanager.QuestManager;
  41. import net.sf.l2j.gameserver.lib.Rnd;
  42. import net.sf.l2j.gameserver.model.L2Character;
  43. import net.sf.l2j.gameserver.model.L2Object;
  44. import net.sf.l2j.gameserver.model.L2Party;
  45. import net.sf.l2j.gameserver.model.L2Skill;
  46. import net.sf.l2j.gameserver.model.L2Spawn;
  47. import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
  48. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  49. import net.sf.l2j.gameserver.scripting.ManagedScript;
  50. import net.sf.l2j.gameserver.scripting.ScriptManager;
  51. import net.sf.l2j.gameserver.serverpackets.ActionFailed;
  52. import net.sf.l2j.gameserver.serverpackets.NpcHtmlMessage;
  53. import net.sf.l2j.gameserver.serverpackets.SystemMessage;
  54. import net.sf.l2j.gameserver.templates.L2NpcTemplate;
  55.  
  56. /**
  57.  * @author Luis Arias
  58.  *
  59.  */
  60. public class Quest extends ManagedScript
  61. {
  62.     protected static Logger _log = Logger.getLogger(Quest.class.getName());
  63.  
  64.     /** HashMap containing events from String value of the event */
  65.     private static Map<String, Quest> allEventsS = new FastMap<>();
  66.     /** HashMap containing lists of timers from the name of the timer */
  67.     private static Map<String, FastList<QuestTimer>> allEventTimers = new FastMap<>();
  68.  
  69.     private final int _questId;
  70.     private final String _name;
  71.     private final String _descr;
  72.     private State initialState;
  73.     private Map<String, State> states;
  74.  
  75.     public static enum QuestEventType
  76.     {
  77.         NPC_FIRST_TALK(false),
  78.         QUEST_START(true),
  79.         QUEST_TALK(true),
  80.         MOBGOTATTACKED(true),
  81.         MOBKILLED(true),
  82.         MOB_TARGETED_BY_SKILL(true),
  83.         MOB_AGGRO_RANGE_ENTER(true);
  84.  
  85.         // control whether this event type is allowed for the same npc template in multiple quests
  86.         // or if the npc must be registered in at most one quest for the specified event
  87.         private boolean _allowMultipleRegistration;
  88.  
  89.         QuestEventType(boolean allowMultipleRegistration)
  90.         {
  91.             _allowMultipleRegistration = allowMultipleRegistration;
  92.         }
  93.  
  94.         public boolean isMultipleRegistrationAllowed()
  95.         {
  96.             return _allowMultipleRegistration;
  97.         }
  98.     }
  99.  
  100.     /**
  101.      * Return collection view of the values contains in the allEventS
  102.      * @return Collection<Quest>
  103.      */
  104.     public static Collection<Quest> findAllEvents()
  105.     {
  106.         return allEventsS.values();
  107.     }
  108.  
  109.     /**
  110.      * (Constructor)Add values to class variables and put the quest in HashMaps.
  111.      * @param questId : int pointing out the ID of the quest
  112.      * @param name : String corresponding to the name of the quest
  113.      * @param descr : String for the description of the quest
  114.      */
  115.     public Quest(int questId, String name, String descr)
  116.     {
  117.  
  118.         _questId = questId;
  119.         _name = name;
  120.         _descr = descr;
  121.  
  122.         states = new FastMap<>();
  123.  
  124.         if (questId != 0)
  125.             QuestManager.getInstance().addQuest(Quest.this);
  126.         else
  127.             allEventsS.put(name, this);
  128.  
  129.         init_LoadGlobalData();
  130.     }
  131.  
  132.     /**
  133.      *
  134.      * The function init_LoadGlobalData is, by default, called by the constructor of all quests.
  135.      * Children of this class can implement this function in order to define what variables
  136.      * to load and what structures to save them in.  By default, nothing is loaded.
  137.      */
  138.     protected void init_LoadGlobalData()
  139.     {
  140.     }
  141.  
  142.     /**
  143.      * The function saveGlobalData is, by default, called at shutdown, for all quests, by the QuestManager.
  144.      * Children of this class can implement this function in order to convert their structures
  145.      * into <var, value> tuples and make calls to save them to the database, if needed.
  146.      * By default, nothing is saved.
  147.      */
  148.     public void saveGlobalData()
  149.     {
  150.     }
  151.  
  152.     /**
  153.      * Return ID of the quest
  154.      * @return int
  155.      */
  156.     public int getQuestIntId()
  157.     {
  158.         return _questId;
  159.     }
  160.  
  161.     /**
  162.      * Set the initial state of the quest with parameter "state"
  163.      * @param state
  164.      */
  165.     public void setInitialState(State state)
  166.     {
  167.         initialState = state;
  168.     }
  169.  
  170.     /**
  171.      * Add a new QuestState to the database and return it.
  172.      * @param player
  173.      * @return QuestState : QuestState created
  174.      */
  175.     public QuestState newQuestState(L2PcInstance player)
  176.     {
  177.         QuestState qs = new QuestState(this, player, getInitialState(), false);
  178.         Quest.createQuestInDb(qs);
  179.         return qs;
  180.     }
  181.  
  182.     /**
  183.      * Return initial state of the quest
  184.      * @return State
  185.      */
  186.     public State getInitialState()
  187.     {
  188.         return initialState;
  189.     }
  190.  
  191.     /**
  192.      * Return name of the quest
  193.      * @return String
  194.      */
  195.     public String getName()
  196.     {
  197.         return _name;
  198.     }
  199.  
  200.     /**
  201.      * Return description of the quest
  202.      * @return String
  203.      */
  204.     public String getDescr()
  205.     {
  206.         return _descr;
  207.     }
  208.  
  209.     /**
  210.      * Add a state to the quest
  211.      * @param state
  212.      * @return state added
  213.      */
  214.     public State addState(State state)
  215.     {
  216.         states.put(state.getName(), state);
  217.         return state;
  218.     }
  219.  
  220.     /**
  221.      * Add a timer to the quest, if it doesn't exist already
  222.      * @param name: name of the timer (also passed back as "event" in onAdvEvent)
  223.      * @param time: time in ms for when to fire the timer
  224.      * @param npc:  npc associated with this timer (can be null)
  225.      * @param player: player associated with this timer (can be null)
  226.      */
  227.     public void startQuestTimer(String name, long time, L2NpcInstance npc, L2PcInstance player)
  228.     {
  229.         startQuestTimer(name, time, npc, player, false);
  230.     }
  231.  
  232.     /**
  233.      * Add a timer to the quest, if it doesn't exist already.  If the timer is repeatable,
  234.      * it will auto-fire automatically, at a fixed rate, until explicitly cancelled.
  235.      * @param name: name of the timer (also passed back as "event" in onAdvEvent)
  236.      * @param time: time in ms for when to fire the timer
  237.      * @param npc:  npc associated with this timer (can be null)
  238.      * @param player: player associated with this timer (can be null)
  239.      * @param repeatable: indicates if the timer is repeatable or one-time.
  240.      */
  241.     public void startQuestTimer(String name, long time, L2NpcInstance npc, L2PcInstance player, boolean repeating)
  242.     {
  243.         // Add quest timer if timer doesn't already exist
  244.         FastList<QuestTimer> timers = getQuestTimers(name);
  245.         // no timer exists with the same name, at all
  246.         if (timers == null)
  247.         {
  248.             timers = new FastList<>();
  249.             timers.add(new QuestTimer(this, name, time, npc, player, repeating));
  250.             allEventTimers.put(name, timers);
  251.         }
  252.         else
  253.         {
  254.             // if there exists a timer with this name, allow the timer only if the [npc, player] set is unique
  255.             // nulls act as wildcards
  256.             if (getQuestTimer(name, npc, player) == null)
  257.                 timers.add(new QuestTimer(this, name, time, npc, player, repeating));
  258.         }
  259.         // ignore the startQuestTimer in all other cases (timer is already started)
  260.     }
  261.  
  262.     public QuestTimer getQuestTimer(String name, L2NpcInstance npc, L2PcInstance player)
  263.     {
  264.         if (allEventTimers.get(name) == null)
  265.             return null;
  266.         for (QuestTimer timer : allEventTimers.get(name))
  267.         {
  268.             if (timer.isMatch(this, name, npc, player))
  269.                 return timer;
  270.         }
  271.         return null;
  272.     }
  273.  
  274.     public FastList<QuestTimer> getQuestTimers(String name)
  275.     {
  276.         return allEventTimers.get(name);
  277.     }
  278.  
  279.     public void cancelQuestTimer(String name, L2NpcInstance npc, L2PcInstance player)
  280.     {
  281.         QuestTimer timer = getQuestTimer(name, npc, player);
  282.         if (timer != null)
  283.             timer.cancel();
  284.     }
  285.  
  286.     public void removeQuestTimer(QuestTimer timer)
  287.     {
  288.         if (timer == null)
  289.             return;
  290.         FastList<QuestTimer> timers = getQuestTimers(timer.getName());
  291.         if (timers == null)
  292.             return;
  293.         timers.remove(timer);
  294.     }
  295.  
  296.     // these are methods to call from java
  297.     public final boolean notifyAttack(L2NpcInstance npc, L2PcInstance attacker, int damage, boolean isPet)
  298.     {
  299.         String res = null;
  300.         try
  301.         {
  302.             res = onAttack(npc, attacker, damage, isPet);
  303.         }
  304.         catch (Exception e)
  305.         {
  306.             return showError(attacker, e);
  307.         }
  308.         return showResult(attacker, res);
  309.     }
  310.  
  311.     public final boolean notifyDeath(L2Character killer, L2Character victim, QuestState qs)
  312.     {
  313.         String res = null;
  314.         try
  315.         {
  316.             res = onDeath(killer, victim, qs);
  317.         }
  318.         catch (Exception e)
  319.         {
  320.             return showError(qs.getPlayer(), e);
  321.         }
  322.         return showResult(qs.getPlayer(), res);
  323.     }
  324.  
  325.     public final boolean notifyEvent(String event, L2NpcInstance npc, L2PcInstance player)
  326.     {
  327.         String res = null;
  328.         try
  329.         {
  330.             res = onAdvEvent(event, npc, player);
  331.         }
  332.         catch (Exception e)
  333.         {
  334.             return showError(player, e);
  335.         }
  336.         return showResult(player, res);
  337.     }
  338.  
  339.     public final boolean notifyKill(L2NpcInstance npc, L2PcInstance killer, boolean isPet)
  340.     {
  341.         String res = null;
  342.         try
  343.         {
  344.             res = onKill(npc, killer, isPet);
  345.         }
  346.         catch (Exception e)
  347.         {
  348.             return showError(killer, e);
  349.         }
  350.         return showResult(killer, res);
  351.     }
  352.  
  353.     public final boolean notifyTalk (L2NpcInstance npc, QuestState qs)
  354.     {
  355.         String res = null;
  356.         try
  357.         {
  358.             res = onTalk(npc, qs);
  359.         }
  360.         catch (Exception e)
  361.         {
  362.             return showError(qs.getPlayer(), e);
  363.         }
  364.  
  365.         qs.getPlayer().setLastQuestNpcObject(npc.getObjectId());
  366.         return showResult(qs.getPlayer(), res);
  367.     }
  368.  
  369.     // override the default NPC dialogs when a quest defines this for the given NPC
  370.     public final boolean notifyFirstTalk (L2NpcInstance npc, L2PcInstance player)
  371.     {
  372.         String res = null;
  373.         try
  374.         {
  375.             res = onFirstTalk(npc, player);
  376.         }
  377.         catch (Exception e)
  378.         {
  379.             return showError(player, e);
  380.         }
  381.  
  382.         player.setLastQuestNpcObject(npc.getObjectId());
  383.  
  384.         // if the quest returns text to display, display it.  Otherwise, use the default npc text.
  385.         if (res != null && res.length() > 0)
  386.             return showResult(player, res);
  387.  
  388.         // note: if the default html for this npc needs to be shown, onFirstTalk should
  389.         // call npc.showChatWindow(player) and then return null.
  390.         return true;
  391.     }
  392.  
  393.     public final boolean notifySkillUse(L2NpcInstance npc, L2PcInstance caster, L2Skill skill, boolean isPet)
  394.     {
  395.         String res = null;
  396.         try
  397.         {
  398.             res = onSkillUse(npc, caster, skill, isPet);
  399.         }
  400.         catch (Exception e)
  401.         {
  402.             return showError(caster, e);
  403.         }
  404.         return showResult(caster, res);
  405.     }
  406.  
  407.     public class tmpOnAggroEnter implements Runnable
  408.     {
  409.         private L2NpcInstance _npc;
  410.         private L2PcInstance _pc;
  411.         private boolean _isPet;
  412.  
  413.         public tmpOnAggroEnter(L2NpcInstance npc, L2PcInstance pc, boolean isPet)
  414.         {
  415.             _npc = npc;
  416.             _pc = pc;
  417.             _isPet = isPet;
  418.         }
  419.  
  420.         public void run()
  421.         {
  422.             String res = null;
  423.             try
  424.             {
  425.                 res = onAggroRangeEnter(_npc, _pc, _isPet);
  426.             }
  427.             catch (Exception e)
  428.             {
  429.                 showError(_pc, e);
  430.             }
  431.             showResult(_pc, res);
  432.         }
  433.     }
  434.  
  435.     public final boolean notifyAggroRangeEnter(L2NpcInstance npc, L2PcInstance player, boolean isPet)
  436.     {
  437.         ThreadPoolManager.getInstance().executeAi(new tmpOnAggroEnter(npc, player, isPet));
  438.         return true;
  439.     }
  440.  
  441.     // these are methods that java calls to invoke scripts
  442.     @SuppressWarnings("unused")
  443.     public String onAttack(L2NpcInstance npc, L2PcInstance attacker, int damage, boolean isPet)
  444.     {
  445.         return null;
  446.     }
  447.  
  448.     @SuppressWarnings("unused")
  449.     public String onDeath(L2Character killer, L2Character victim, QuestState qs)
  450.     {
  451.         if (killer instanceof L2NpcInstance)
  452.             return onAdvEvent("", (L2NpcInstance)killer, qs.getPlayer());
  453.         else
  454.             return onAdvEvent("", null, qs.getPlayer());
  455.     }
  456.  
  457.     @SuppressWarnings("unused")
  458.     public String onAdvEvent(String event, L2NpcInstance npc, L2PcInstance player)
  459.     {
  460.         // if not overriden by a subclass, then default to the returned value of the simpler (and older) onEvent override
  461.         // if the player has a state, use it as parameter in the next call, else return null
  462.         QuestState qs = player.getQuestState(getName());
  463.         if (qs != null)
  464.             return onEvent(event, qs);
  465.  
  466.         return null;
  467.     }
  468.  
  469.     @SuppressWarnings("unused")
  470.     public String onEvent(String event, QuestState qs)
  471.     {
  472.         return null;
  473.     }
  474.  
  475.     @SuppressWarnings("unused")
  476.     public String onKill(L2NpcInstance npc, L2PcInstance killer, boolean isPet)
  477.     {
  478.         return null;
  479.     }
  480.  
  481.     @SuppressWarnings("unused")
  482.     public String onTalk(L2NpcInstance npc, QuestState qs)
  483.     {
  484.         return null;
  485.     }
  486.  
  487.     @SuppressWarnings("unused")
  488.     public String onFirstTalk(L2NpcInstance npc, L2PcInstance player)
  489.     {
  490.         return null;
  491.     }
  492.  
  493.     @SuppressWarnings("unused")
  494.     public String onSkillUse(L2NpcInstance npc, L2PcInstance caster, L2Skill skill, boolean isPet)
  495.     {
  496.         return null;
  497.     }
  498.  
  499.     @SuppressWarnings("unused")
  500.     public String onAggroRangeEnter(L2NpcInstance npc, L2PcInstance player, boolean isPet)
  501.     {
  502.         return null;
  503.     }
  504.  
  505.     /**
  506.      * Add this quest to the list of quests that the passed mob will respond to for the specified Event type.<BR><BR>
  507.      * @param npcId : id of the NPC to register
  508.      * @param eventType : type of event being registered
  509.      * @return L2NpcTemplate : Npc Template corresponding to the npcId, or null if the id is invalid
  510.      */
  511.     public L2NpcTemplate addEventId(int npcId, QuestEventType eventType)
  512.     {
  513.         try
  514.         {
  515.             L2NpcTemplate t = NpcTable.getInstance().getTemplate(npcId);
  516.             if (t != null)
  517.                 t.addQuestEvent(eventType, this);
  518.  
  519.             return t;
  520.         }
  521.         catch(Exception e)
  522.         {
  523.             e.printStackTrace();
  524.             return null;
  525.         }
  526.     }
  527.  
  528.     public L2NpcTemplate addStartNpc(int npcId)
  529.     {
  530.         return addEventId(npcId, Quest.QuestEventType.QUEST_START);
  531.     }
  532.  
  533.     /**
  534.      * Show message error to player who has an access level greater than 0
  535.      * @param qs : QuestState
  536.      * @param t : Throwable
  537.      * @return boolean
  538.      */
  539.     private boolean showError(L2PcInstance player, Throwable t)
  540.     {
  541.         _log.log(Level.WARNING, getScriptFile().getAbsolutePath(), t);
  542.         if (player.getAccessLevel() > 0)
  543.         {
  544.             StringWriter sw = new StringWriter();
  545.             PrintWriter pw = new PrintWriter(sw);
  546.             t.printStackTrace(pw);
  547.             pw.close();
  548.             String res = "<html><body><title>Script error</title>"+sw.toString()+"</body></html>";
  549.             return showResult(player, res);
  550.         }
  551.         return false;
  552.     }
  553.  
  554.     /**
  555.      * Show a message to player.<BR><BR>
  556.      * <U><I>Concept : </I></U><BR>
  557.      * 3 cases are managed according to the value of the parameter "res" :<BR>
  558.      * <LI><U>"res" ends with string ".html" :</U> an HTML is opened in order to be shown in a dialog box</LI>
  559.      * <LI><U>"res" starts with "<html>" :</U> the message hold in "res" is shown in a dialog box</LI>
  560.      * <LI><U>otherwise :</U> the message hold in "res" is shown in chat box</LI>
  561.      * @param qs : QuestState
  562.      * @param res : String pointing out the message to show at the player
  563.      * @return boolean
  564.      */
  565.     private boolean showResult(L2PcInstance player, String res)
  566.     {
  567.         if (res == null || res.isEmpty())
  568.             return true;
  569.  
  570.         if (res.endsWith(".htm"))
  571.             showHtmlFile(player, res);
  572.         else if (res.startsWith("<html>"))
  573.         {
  574.             NpcHtmlMessage npcReply = new NpcHtmlMessage(5);
  575.             npcReply.setHtml(res);
  576.             npcReply.replace("%playername%", player.getName());
  577.             player.sendPacket(npcReply);
  578.             player.sendPacket(new ActionFailed());
  579.         }
  580.         else
  581.         {
  582.             SystemMessage sm = new SystemMessage(SystemMessage.S1_S2);
  583.             sm.addString(res);
  584.             player.sendPacket(sm);
  585.         }
  586.         return false;
  587.     }
  588.  
  589.     /**
  590.      * Add quests to the L2PCInstance of the player.<BR><BR>
  591.      * <U><I>Action : </U></I><BR>
  592.      * Add state of quests, drops and variables for quests in the HashMap _quest of L2PcInstance
  593.      * @param player : Player who is entering the world
  594.      */
  595.     public final static void playerEnter(L2PcInstance player)
  596.     {
  597.         java.sql.Connection con = null;
  598.         try
  599.         {
  600.         // Get list of quests owned by the player from database
  601.             con = L2DatabaseFactory.getInstance().getConnection();
  602.             PreparedStatement statement;
  603.  
  604.             PreparedStatement invalidQuestData      = con.prepareStatement("DELETE FROM character_quests WHERE char_id=? and name=?");
  605.             PreparedStatement invalidQuestDataVar   = con.prepareStatement("delete FROM character_quests WHERE char_id=? and name=? and var=?");
  606.  
  607.             statement = con.prepareStatement("SELECT name,value FROM character_quests WHERE char_id=? AND var=?");
  608.             statement.setInt(1, player.getObjectId());
  609.             statement.setString(2, "<state>");
  610.             ResultSet rs = statement.executeQuery();
  611.             while (rs.next())
  612.             {
  613.                 // Get ID of the quest and ID of its state
  614.                 String questId = rs.getString("name");
  615.                 String stateId = rs.getString("value");
  616.  
  617.                 // Search quest associated with the ID
  618.                 Quest q = QuestManager.getInstance().getQuest(questId);
  619.                 if (q == null)
  620.                 {
  621.                     _log.finer("Unknown quest "+questId+" for player "+player.getName());
  622.                     if (Config.AUTODELETE_INVALID_QUEST_DATA)
  623.                     {
  624.                         invalidQuestData.setInt(1, player.getObjectId());
  625.                         invalidQuestData.setString(2, questId);
  626.                         invalidQuestData.executeUpdate();
  627.                     }
  628.                     continue;
  629.                 }
  630.  
  631.                 // Identify the state of the quest for the player
  632.                 boolean completed = false;
  633.                 if (stateId.length() > 0 && stateId.charAt(0) == '*')
  634.                 {
  635.                     // probably obsolete check
  636.                     completed = true;
  637.                     stateId = stateId.substring(1);
  638.                 }
  639.  
  640.                 if (stateId.equals("Completed"))
  641.                     completed = true;
  642.  
  643.                 // Create an object State containing the state of the quest
  644.                 State state = q.states.get(stateId);
  645.                 if (state == null)
  646.                 {
  647.                     _log.finer("Unknown state in quest "+questId+" for player "+player.getName());
  648.                     if (Config.AUTODELETE_INVALID_QUEST_DATA)
  649.                     {
  650.                         invalidQuestData.setInt(1, player.getObjectId());
  651.                         invalidQuestData.setString(2, questId);
  652.                         invalidQuestData.executeUpdate();
  653.                     }
  654.                     continue;
  655.                 }
  656.  
  657.                 // Create a new QuestState for the player that will be added to the player's list of quests
  658.                 new QuestState(q, player, state, completed);
  659.             }
  660.  
  661.             rs.close();
  662.             invalidQuestData.close();
  663.             statement.close();
  664.  
  665.             // Get list of quests owned by the player from the DB in order to add variables used in the quest.
  666.             statement = con.prepareStatement("SELECT name,var,value FROM character_quests WHERE char_id=? AND var<>?");
  667.             statement.setInt(1,player.getObjectId());
  668.             statement.setString(2, "<state>");
  669.             rs = statement.executeQuery();
  670.             while (rs.next())
  671.             {
  672.                 String questId = rs.getString("name");
  673.                 String var     = rs.getString("var");
  674.                 String value   = rs.getString("value");
  675.                 // Get the QuestState saved in the loop before
  676.                 QuestState qs = player.getQuestState(questId);
  677.                 if (qs == null)
  678.                 {
  679.                     _log.finer("Lost variable "+var+" in quest "+questId+" for player "+player.getName());
  680.                     if (Config.AUTODELETE_INVALID_QUEST_DATA)
  681.                     {
  682.                         invalidQuestDataVar.setInt(1,player.getObjectId());
  683.                         invalidQuestDataVar.setString(2,questId);
  684.                         invalidQuestDataVar.setString(3,var);
  685.                         invalidQuestDataVar.executeUpdate();
  686.                     }
  687.                     continue;
  688.                 }
  689.  
  690.                 // Add parameter to the quest
  691.                 qs.setInternal(var, value);
  692.             }
  693.  
  694.             rs.close();
  695.             invalidQuestDataVar.close();
  696.             statement.close(); 
  697.         }
  698.         catch (Exception e)
  699.         {
  700.             _log.log(Level.WARNING, "could not insert char quest:", e);
  701.         }
  702.         finally
  703.         {
  704.             try
  705.             {
  706.                 con.close();
  707.             }
  708.             catch (Exception e) {}
  709.         }
  710.  
  711.         // events
  712.         for (String name : allEventsS.keySet())
  713.             player.processQuestEvent(name, "enter");
  714.     }
  715.  
  716.     /**
  717.      * Insert (or Update) in the database variables that need to stay persistant for this quest after a reboot.
  718.      * This function is for storage of values that do not related to a specific player but are
  719.      * global for all characters.  For example, if we need to disable a quest-gatekeeper until
  720.      * a certain time (as is done with some grand-boss gatekeepers), we can save that time in the DB.
  721.      * @param var : String designating the name of the variable for the quest
  722.      * @param value : String designating the value of the variable for the quest
  723.      */
  724.     public final void saveGlobalQuestVar(String var, String value)
  725.     {
  726.         java.sql.Connection con = null;
  727.         try
  728.         {
  729.             con = L2DatabaseFactory.getInstance().getConnection();
  730.             PreparedStatement statement;
  731.             statement = con.prepareStatement("REPLACE INTO quest_global_data (quest_name,var,value) VALUES (?,?,?)");
  732.             statement.setString(1, getName());
  733.             statement.setString(2, var);
  734.             statement.setString(3, value);
  735.             statement.executeUpdate();
  736.             statement.close();
  737.         }
  738.         catch (Exception e)
  739.         {
  740.             _log.log(Level.WARNING, "could not insert global quest variable:", e);
  741.         }
  742.     }
  743.  
  744.     /**
  745.      * Read from the database a previously saved variable for this quest.
  746.      * Due to performance considerations, this function should best be used only when the quest is first loaded.
  747.      * Subclasses of this class can define structures into which these loaded values can be saved.
  748.      * However, on-demand usage of this function throughout the script is not prohibited, only not recommended.
  749.      * Values read from this function were entered by calls to "saveGlobalQuestVar"
  750.      * @param var : String designating the name of the variable for the quest
  751.      * @return String : String representing the loaded value for the passed var, or an empty string if the var was invalid
  752.      */
  753.     public final String loadGlobalQuestVar(String var)
  754.     {
  755.         String result = "";
  756.         java.sql.Connection con = null;
  757.         try
  758.         {
  759.             con = L2DatabaseFactory.getInstance().getConnection();
  760.             PreparedStatement statement;
  761.             statement = con.prepareStatement("SELECT value FROM quest_global_data WHERE quest_name = ? AND var = ?");
  762.             statement.setString(1, getName());
  763.             statement.setString(2, var);
  764.             ResultSet rs = statement.executeQuery();
  765.             if (rs.first())
  766.                 result = rs.getString(1);
  767.             rs.close();
  768.             statement.close();
  769.         }
  770.         catch (Exception e)
  771.         {
  772.             _log.log(Level.WARNING, "could not load global quest variable:", e);
  773.         }
  774.         finally
  775.         {
  776.             try
  777.             {
  778.                 con.close();
  779.             }
  780.             catch (Exception e) {}
  781.         }
  782.         return result;
  783.     }
  784.  
  785.     /**
  786.      * Permanently delete from the database a global quest variable that was previously saved for this quest.
  787.      * @param var : String designating the name of the variable for the quest
  788.      */
  789.     public final void deleteGlobalQuestVar(String var)
  790.     {
  791.         java.sql.Connection con = null;
  792.         try
  793.         {
  794.             con = L2DatabaseFactory.getInstance().getConnection();
  795.             PreparedStatement statement;
  796.             statement = con.prepareStatement("DELETE FROM quest_global_data WHERE quest_name = ? AND var = ?");
  797.             statement.setString(1, getName());
  798.             statement.setString(2, var);
  799.             statement.executeUpdate();
  800.             statement.close();
  801.         }
  802.         catch (Exception e)
  803.         {
  804.             _log.log(Level.WARNING, "could not delete global quest variable:", e);
  805.         }
  806.         finally
  807.         {
  808.             try
  809.             {
  810.                 con.close();
  811.             }
  812.             catch (Exception e) {}
  813.         }
  814.     }
  815.  
  816.     /**
  817.      * Permanently delete from the database all global quest variables that was previously saved for this quest.
  818.      */
  819.     public final void deleteAllGlobalQuestVars()
  820.     {
  821.         java.sql.Connection con = null;
  822.         try
  823.         {
  824.             con = L2DatabaseFactory.getInstance().getConnection();
  825.             PreparedStatement statement;
  826.             statement = con.prepareStatement("DELETE FROM quest_global_data WHERE quest_name = ?");
  827.             statement.setString(1, getName());
  828.             statement.executeUpdate();
  829.             statement.close();
  830.         }
  831.         catch (Exception e)
  832.         {
  833.             _log.log(Level.WARNING, "could not delete global quest variables:", e);
  834.         }
  835.         finally
  836.         {
  837.             try
  838.             {
  839.                 con.close();
  840.             }
  841.             catch (Exception e) {}
  842.         }
  843.     }
  844.  
  845.     /**
  846.      * Insert in the database the quest for the player.
  847.      * @param qs : QuestState pointing out the state of the quest
  848.      * @param var : String designating the name of the variable for the quest
  849.      * @param value : String designating the value of the variable for the quest
  850.      */
  851.     public static void createQuestVarInDb(QuestState qs, String var, String value)
  852.     {
  853.         java.sql.Connection con = null;
  854.         try
  855.         {
  856.             con = L2DatabaseFactory.getInstance().getConnection();
  857.             PreparedStatement statement;
  858.             statement = con.prepareStatement("INSERT INTO character_quests (char_id,name,var,value) VALUES (?,?,?,?)");
  859.             statement.setInt(1, qs.getPlayer().getObjectId());
  860.             statement.setString(2, qs.getQuestName());
  861.             statement.setString(3, var);
  862.             statement.setString(4, value);
  863.         statement.executeUpdate();
  864.             statement.close();
  865.         }
  866.         catch (Exception e)
  867.         {
  868.             _log.log(Level.WARNING, "could not insert char quest:", e);
  869.         }
  870.         finally
  871.         {
  872.             try
  873.             {
  874.                 con.close();
  875.             }
  876.             catch (Exception e) {}
  877.         }
  878.     }
  879.  
  880.     /**
  881.      * Update the value of the variable "var" for the quest.<BR><BR>
  882.      * <U><I>Actions :</I></U><BR>
  883.      * The selection of the right record is made with :
  884.      * <LI>char_id = qs.getPlayer().getObjectID()</LI>
  885.      * <LI>name = qs.getQuestName()</LI>
  886.      * <LI>var = var</LI>
  887.      * <BR><BR>
  888.      * The modification made is :
  889.      * <LI>value = parameter value</LI>
  890.      * @param qs : Quest State
  891.      * @param var : String designating the name of the variable for quest
  892.      * @param value : String designating the value of the variable for quest
  893.      */
  894.     public static void updateQuestVarInDb(QuestState qs, String var, String value)
  895.     {
  896.         java.sql.Connection con = null;
  897.         try
  898.         {
  899.             con = L2DatabaseFactory.getInstance().getConnection();
  900.             PreparedStatement statement;
  901.             statement = con.prepareStatement("UPDATE character_quests SET value=? WHERE char_id=? AND name=? AND var = ?");
  902.             statement.setString(1, value);
  903.             statement.setInt(2, qs.getPlayer().getObjectId());
  904.             statement.setString(3, qs.getQuestName());
  905.             statement.setString(4, var);
  906.             statement.executeUpdate();
  907.             statement.close();
  908.         }
  909.         catch (Exception e)
  910.         {
  911.             _log.log(Level.WARNING, "could not update char quest:", e);
  912.         }
  913.         finally
  914.         {
  915.             try
  916.             {
  917.                 con.close();
  918.             }
  919.             catch (Exception e) {}
  920.         }
  921.     }
  922.  
  923.     /**
  924.      * Delete a variable of player's quest from the database.
  925.      * @param qs : object QuestState pointing out the player's quest
  926.      * @param var : String designating the variable characterizing the quest
  927.      */
  928.     public static void deleteQuestVarInDb(QuestState qs, String var)
  929.     {
  930.         java.sql.Connection con = null;
  931.         try
  932.         {
  933.             con = L2DatabaseFactory.getInstance().getConnection();
  934.             PreparedStatement statement;
  935.             statement = con.prepareStatement("DELETE FROM character_quests WHERE char_id=? AND name=? AND var=?");
  936.             statement.setInt(1, qs.getPlayer().getObjectId());
  937.             statement.setString(2, qs.getQuestName());
  938.             statement.setString(3, var);
  939.         statement.executeUpdate();
  940.             statement.close();
  941.         }
  942.         catch (Exception e)
  943.         {
  944.            _log.log(Level.WARNING, "could not delete char quest:", e);
  945.         }
  946.         finally
  947.         {
  948.             try
  949.             {
  950.                 con.close();
  951.             }
  952.             catch (Exception e) {}
  953.         }
  954.     }
  955.  
  956.     /**
  957.      * Delete the player's quest from database.
  958.      * @param qs : QuestState pointing out the player's quest
  959.      */
  960.     public static void deleteQuestInDb(QuestState qs)
  961.     {
  962.         java.sql.Connection con = null;
  963.         try
  964.         {
  965.             con = L2DatabaseFactory.getInstance().getConnection();
  966.             PreparedStatement statement;
  967.             statement = con.prepareStatement("DELETE FROM character_quests WHERE char_id=? AND name=?");
  968.             statement.setInt   (1, qs.getPlayer().getObjectId());
  969.             statement.setString(2, qs.getQuestName());
  970.             statement.executeUpdate();
  971.             statement.close();
  972.         }
  973.         catch (Exception e)
  974.         {
  975.             _log.log(Level.WARNING, "could not delete char quest:", e);
  976.         }
  977.         finally
  978.         {
  979.             try
  980.             {
  981.                 con.close();
  982.             }
  983.             catch (Exception e) {}
  984.         }
  985.     }
  986.  
  987.     /**
  988.      * Create a record in database for quest.<BR><BR>
  989.      * <U><I>Actions :</I></U><BR>
  990.      * Use fucntion createQuestVarInDb() with following parameters :<BR>
  991.      * <LI>QuestState : parameter sq that puts in fields of database :
  992.      * <UL type="square">
  993.      * <LI>char_id : ID of the player</LI>
  994.      * <LI>name : name of the quest</LI>
  995.      * </UL>
  996.      * </LI>
  997.      * <LI>var : string "&lt;state&gt;" as the name of the variable for the quest</LI>
  998.      * <LI>val : string corresponding at the ID of the state (in fact, initial state)</LI>
  999.      * @param qs : QuestState
  1000.      */
  1001.     public static void createQuestInDb(QuestState qs)
  1002.     {
  1003.         createQuestVarInDb(qs, "<state>", qs.getStateId());
  1004.     }
  1005.  
  1006.     /**
  1007.      * Update informations regarding quest in database.<BR>
  1008.      * <U><I>Actions :</I></U><BR>
  1009.      * <LI>Get ID state of the quest recorded in object qs</LI>
  1010.      * <LI>Test if quest is completed. If true, add a star (*) before the ID state</LI>
  1011.      * <LI>Save in database the ID state (with or without the star) for the variable called "&lt;state&gt;" of the quest</LI>
  1012.      * @param qs : QuestState
  1013.      */
  1014.     public static void updateQuestInDb(QuestState qs)
  1015.     {
  1016.         updateQuestVarInDb(qs, "<state>", qs.getStateId());
  1017.     }
  1018.  
  1019.     /**
  1020.      * Add this quest to the list of quests that the passed mob will respond to for Attack Events.<BR><BR>
  1021.      * @param attackId
  1022.      * @return int : attackId
  1023.      */
  1024.     public L2NpcTemplate addAttackId(int attackId)
  1025.     {
  1026.         return addEventId(attackId, Quest.QuestEventType.MOBGOTATTACKED);
  1027.     }
  1028.  
  1029.     /**
  1030.      * Add this quest to the list of quests that the passed mob will respond to for Kill Events.<BR><BR>
  1031.      * @param killId
  1032.      * @return int : killId
  1033.      */
  1034.     public L2NpcTemplate addKillId(int killId)
  1035.     {
  1036.         return addEventId(killId, Quest.QuestEventType.MOBKILLED);
  1037.     }
  1038.  
  1039.     /**
  1040.      * Add this quest to the list of quests that the passed npc will respond to for Talk Events.<BR><BR>
  1041.      * @param talkId : ID of the NPC
  1042.      * @return int : ID of the NPC
  1043.      */
  1044.     public L2NpcTemplate addTalkId(int talkId)
  1045.     {
  1046.         return addEventId(talkId, Quest.QuestEventType.QUEST_TALK);
  1047.     }
  1048.  
  1049.     /**
  1050.      * Add the quest to the NPC's first-talk (default action dialog)
  1051.      * @param npcId
  1052.      * @return L2NpcTemplate : Start NPC
  1053.      */
  1054.     public L2NpcTemplate addFirstTalkId(int npcId)
  1055.     {
  1056.         return addEventId(npcId, Quest.QuestEventType.NPC_FIRST_TALK);
  1057.     }
  1058.  
  1059.     /**
  1060.      * Add this quest to the list of quests that the passed npc will respond to for Skill-Use Events.<BR><BR>
  1061.      * @param npcId : ID of the NPC
  1062.      * @return int : ID of the NPC
  1063.      */
  1064.     public L2NpcTemplate addSkillUseId(int npcId)
  1065.     {
  1066.         return addEventId(npcId, Quest.QuestEventType.MOB_TARGETED_BY_SKILL);
  1067.     }
  1068.  
  1069.     /**
  1070.      * Add this quest to the list of quests that the passed npc will respond to for Character See Events.<BR><BR>
  1071.      * @param npcId : ID of the NPC
  1072.      * @return int : ID of the NPC
  1073.      */
  1074.     public L2NpcTemplate addAggroRangeEnterId(int npcId)
  1075.     {
  1076.         return addEventId(npcId, Quest.QuestEventType.MOB_AGGRO_RANGE_ENTER);
  1077.     }
  1078.  
  1079.     // returns a random party member's L2PcInstance for the passed player's party
  1080.     // returns the passed player if he has no party.
  1081.     public L2PcInstance getRandomPartyMember(L2PcInstance player)
  1082.     {
  1083.         // NPE prevention. If the player is null, there is nothing to return
  1084.         if (player == null)
  1085.             return null;
  1086.         if ((player.getParty() == null) || (player.getParty().getPartyMembers().size()==0))
  1087.             return player;
  1088.         L2Party party = player.getParty();
  1089.         return party.getPartyMembers().get(Rnd.get(party.getPartyMembers().size()));
  1090.     }
  1091.  
  1092.     /**
  1093.      * Auxilary function for party quests.
  1094.      * Note: This function is only here because of how commonly it may be used by quest developers.
  1095.      * For any variations on this function, the quest script can always handle things on its own
  1096.      * @param player: the instance of a player whose party is to be searched
  1097.      * @param value: the value of the "cond" variable that must be matched
  1098.      * @return L2PcInstance: L2PcInstance for a random party member that matches the specified
  1099.      * condition, or null if no match.
  1100.      */
  1101.     public L2PcInstance getRandomPartyMember(L2PcInstance player, String value)
  1102.     {
  1103.         return getRandomPartyMember(player, "cond", value);
  1104.     }
  1105.  
  1106.     /**
  1107.      * Auxilary function for party quests.
  1108.      * Note: This function is only here because of how commonly it may be used by quest developers.
  1109.      * For any variations on this function, the quest script can always handle things on its own
  1110.      * @param player: the instance of a player whose party is to be searched
  1111.      * @param var/value: a tuple specifying a quest condition that must be satisfied for
  1112.      * a party member to be considered.
  1113.      * @return L2PcInstance: L2PcInstance for a random party member that matches the specified
  1114.      * condition, or null if no match.  If the var is null, any random party
  1115.      * member is returned (i.e. no condition is applied).
  1116.      */
  1117.     public L2PcInstance getRandomPartyMember(L2PcInstance player, String var, String value)
  1118.     {
  1119.         // if no valid player instance is passed, there is nothing to check...
  1120.         if (player == null)
  1121.             return null;
  1122.  
  1123.         // for null var condition, return any random party member.
  1124.         if (var == null)
  1125.             return getRandomPartyMember(player);
  1126.  
  1127.         // normal cases...if the player is not in a partym check the player's state
  1128.         QuestState temp = null;
  1129.         L2Party party = player.getParty();
  1130.         // if this player is not in a party, just check if this player instance matches the conditions itself
  1131.         if ((party == null) || (party.getPartyMembers().size()==0))
  1132.         {
  1133.             temp = player.getQuestState(getName());
  1134.             if ((temp != null) && (temp.get(var)!=null) && temp.get(var).equalsIgnoreCase(value))
  1135.                 return player;  // match
  1136.             return null;
  1137.         }
  1138.  
  1139.         // if the player is in a party, gather a list of all matching party members (possibly
  1140.         // including this player)
  1141.         FastList<L2PcInstance> candidates = new FastList<>();
  1142.  
  1143.         L2Object target = player.getTarget();
  1144.         if (target == null)
  1145.             target = player;
  1146.  
  1147.         for (L2PcInstance partyMember : party.getPartyMembers())
  1148.         {
  1149.             temp = partyMember.getQuestState(getName());
  1150.             if ((temp != null) && (temp.get(var)!=null) && temp.get(var).equalsIgnoreCase(value)
  1151.                     && partyMember.isInsideRadius(target, 1500, true, false))
  1152.                 candidates.add(partyMember);
  1153.         }
  1154.  
  1155.         // if there was no match, return null...
  1156.         if (candidates.size()==0)
  1157.             return null;
  1158.  
  1159.         // if a match was found from the party, return one of them at random.
  1160.         return candidates.get( Rnd.get(candidates.size()));
  1161.     }
  1162.  
  1163.     /**
  1164.      * Auxilary function for party quests.
  1165.      * Note: This function is only here because of how commonly it may be used by quest developers.
  1166.      * For any variations on this function, the quest script can always handle things on its own
  1167.      * @param player: the instance of a player whose party is to be searched
  1168.      * @param state: the state in which the party member's queststate must be in order to be considered.
  1169.      * @return L2PcInstance: L2PcInstance for a random party member that matches the specified
  1170.      * condition, or null if no match.  If the var is null, any random party
  1171.      * member is returned (i.e. no condition is applied).
  1172.      */
  1173.     public L2PcInstance getRandomPartyMemberState(L2PcInstance player, State state)
  1174.     {
  1175.         // if no valid player instance is passed, there is nothing to check...
  1176.         if (player == null)
  1177.             return null;
  1178.  
  1179.         // for null var condition, return any random party member.
  1180.         if (state == null)
  1181.             return getRandomPartyMember(player);
  1182.  
  1183.         // normal cases...if the player is not in a partym check the player's state
  1184.         QuestState temp = null;
  1185.         L2Party party = player.getParty();
  1186.         // if this player is not in a party, just check if this player instance matches the conditions itself
  1187.         if ((party == null) || (party.getPartyMembers().size()==0))
  1188.         {
  1189.             temp = player.getQuestState(getName());
  1190.             if ((temp != null) && (temp.getState() == state))
  1191.                 return player;  // match
  1192.             return null;
  1193.         }
  1194.  
  1195.         // if the player is in a party, gather a list of all matching party members (possibly
  1196.         // including this player)
  1197.         FastList<L2PcInstance> candidates = new FastList<>();
  1198.  
  1199.         L2Object target = player.getTarget();
  1200.         if (target == null)
  1201.             target = player;
  1202.  
  1203.         for (L2PcInstance partyMember : party.getPartyMembers())
  1204.         {
  1205.             temp = partyMember.getQuestState(getName());
  1206.             if ((temp != null) && (temp.getState() == state) && partyMember.isInsideRadius(target, 1500, true, false))
  1207.                 candidates.add(partyMember);
  1208.         }
  1209.  
  1210.         // if there was no match, return null...
  1211.         if (candidates.size()==0)
  1212.             return null;
  1213.  
  1214.         // if a match was found from the party, return one of them at random.
  1215.         return candidates.get( Rnd.get(candidates.size()));
  1216.     }
  1217.  
  1218.     /**
  1219.      * Show HTML file to client
  1220.      * @param fileName
  1221.      * @return String : message sent to client
  1222.      */
  1223.     public String showHtmlFile(L2PcInstance player, String fileName)
  1224.     {
  1225.         String questId = getName();
  1226.  
  1227.         // Create handler to file linked to the quest
  1228.         String directory = getDescr().toLowerCase();
  1229.         String content = HtmCache.getInstance().getHtm("data/scripts/" + directory + "/" + questId + "/"+fileName);
  1230.  
  1231.         if (content == null)
  1232.             content = HtmCache.getInstance().getHtmForce("data/scripts/quests/"+questId+"/"+fileName);
  1233.  
  1234.         if (player != null && player.getTarget() != null)
  1235.             content = content.replaceAll("%objectId%", String.valueOf(player.getTarget().getObjectId()));
  1236.  
  1237.         // Send message to client if message not empty
  1238.         if (content != null)
  1239.         {
  1240.             NpcHtmlMessage npcReply = new NpcHtmlMessage(5);
  1241.             npcReply.setHtml(content);
  1242.             npcReply.replace("%playername%", player.getName());
  1243.             player.sendPacket(npcReply);
  1244.             player.sendPacket(new ActionFailed());
  1245.         }
  1246.  
  1247.         return content;
  1248.     }
  1249.  
  1250.     // =========================================================
  1251.     //  QUEST SPAWNS
  1252.     // =========================================================
  1253.  
  1254.     public class DeSpawnScheduleTimerTask implements Runnable
  1255.     {
  1256.         L2NpcInstance _npc = null;
  1257.         public DeSpawnScheduleTimerTask(L2NpcInstance npc)
  1258.         {
  1259.             _npc = npc;
  1260.         }
  1261.  
  1262.         public void run()
  1263.         {
  1264.             _npc.onDecay();
  1265.         }
  1266.     }
  1267.  
  1268.     /**
  1269.      * Return random value
  1270.      * @param max : max value for randomization
  1271.      * @return int
  1272.      */
  1273.     public int getRandom(int max)
  1274.     {
  1275.         return Rnd.get(max);
  1276.     }
  1277.  
  1278.     /**
  1279.      * Add a temporary (quest) spawn
  1280.      * Return instance of newly spawned npc
  1281.      */
  1282.     public L2NpcInstance addSpawn(int npcId, L2Character cha)
  1283.     {
  1284.         return addSpawn(npcId, cha.getX(), cha.getY(), cha.getZ(), cha.getHeading(), false, 0);
  1285.     }
  1286.  
  1287.     public L2NpcInstance addSpawn(int npcId, int x, int y, int z,int heading, boolean randomOffset, int despawnDelay)
  1288.     {
  1289.         L2NpcInstance result = null;
  1290.         try
  1291.         {
  1292.             L2NpcTemplate template = NpcTable.getInstance().getTemplate(npcId);
  1293.             if (template != null)
  1294.             {
  1295.                 // Sometimes, even if the quest script specifies some xyz (for example npc.getX() etc) by the time the code
  1296.                 // reaches here, xyz have become 0!  Also, a questdev might have purposely set xy to 0,0...however,
  1297.                 // the spawn code is coded such that if x=y=0, it looks into location for the spawn loc!  This will NOT work
  1298.                 // with quest spawns!  For both of the above cases, we need a fail-safe spawn.  For this, we use the
  1299.                 // default spawn location, which is at the player's loc.
  1300.                 if ((x == 0) && (y == 0))
  1301.                 {
  1302.                     _log.log(Level.SEVERE, "Failed to adjust bad locks for quest spawn!  Spawn aborted!");
  1303.                     return null;
  1304.                 }
  1305.  
  1306.                 if (randomOffset)
  1307.                 {
  1308.                     int offset;
  1309.                     offset = Rnd.get(2); // Get the direction of the offset
  1310.                     if (offset == 0)
  1311.                         offset = -1; // make offset negative
  1312.                     offset *= Rnd.get(50, 100);
  1313.                     x += offset;
  1314.  
  1315.                     offset = Rnd.get(2); // Get the direction of the offset
  1316.                     if (offset == 0)
  1317.                         offset = -1; // make offset negative
  1318.                     offset *= Rnd.get(50, 100);
  1319.                     y += offset;
  1320.                 }
  1321.  
  1322.                 L2Spawn spawn = new L2Spawn(template);
  1323.                 spawn.setHeading(heading);
  1324.                 spawn.setLocx(x);
  1325.                 spawn.setLocy(y);
  1326.                 spawn.setLocz(z);
  1327.                 spawn.stopRespawn();
  1328.                 result = spawn.spawnOne();
  1329.  
  1330.                 if (despawnDelay > 0)
  1331.                     ThreadPoolManager.getInstance().scheduleGeneral(new DeSpawnScheduleTimerTask(result), despawnDelay);
  1332.  
  1333.                 return result;
  1334.             }
  1335.         }
  1336.         catch (Exception e1)
  1337.         {
  1338.             _log.warning("Could not spawn Npc " + npcId);
  1339.         }
  1340.  
  1341.         return null;
  1342.     }
  1343.  
  1344.     /**
  1345.      * @see net.sf.l2j.gameserver.scripting.ManagedScript#getScriptName()
  1346.      */
  1347.     @Override
  1348.     public String getScriptName()
  1349.     {
  1350.         return getName();
  1351.     }
  1352.  
  1353.     /**
  1354.      * @see net.sf.l2j.gameserver.scripting.ManagedScript#setActive(boolean)
  1355.      */
  1356.     @Override
  1357.     public void setActive(boolean status)
  1358.     {
  1359.         // TODO implement me
  1360.     }
  1361.  
  1362.     /**
  1363.      * @see net.sf.l2j.gameserver.scripting.ManagedScript#reload()
  1364.      */
  1365.     @Override
  1366.     public boolean reload()
  1367.     {
  1368.         unload();
  1369.         return super.reload();
  1370.     }
  1371.  
  1372.     /**
  1373.      * @see net.sf.l2j.gameserver.scripting.ManagedScript#unload()
  1374.      */
  1375.     @Override
  1376.     public boolean unload()
  1377.     {
  1378.         saveGlobalData();
  1379.  
  1380.         // cancel all pending timers before reloading.
  1381.         // if timers ought to be restarted, the quest can take care of it
  1382.         // with its code (example: save global data indicating what timer must
  1383.         // be restarted).
  1384.         for (FastList<QuestTimer> timers : allEventTimers.values())
  1385.         {
  1386.             for (QuestTimer timer : timers)
  1387.                 timer.cancel();
  1388.         }
  1389.         allEventTimers.clear();
  1390.         return QuestManager.getInstance().removeQuest(this);
  1391.     }
  1392.  
  1393.     /**
  1394.      * @see net.sf.l2j.gameserver.scripting.ManagedScript#getScriptManager()
  1395.      */
  1396.     @Override
  1397.     public ScriptManager<?> getScriptManager()
  1398.     {
  1399.         return QuestManager.getInstance();
  1400.     }
  1401. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement