1269 lines
40 KiB
Java
1269 lines
40 KiB
Java
/*
|
|
* This file is part of the L2J Mobius project.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package com.l2jmobius.gameserver.model.quest;
|
|
|
|
import java.sql.Connection;
|
|
import java.sql.PreparedStatement;
|
|
import java.sql.ResultSet;
|
|
import java.util.Calendar;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
import com.l2jmobius.Config;
|
|
import com.l2jmobius.commons.database.DatabaseFactory;
|
|
import com.l2jmobius.gameserver.enums.QuestSound;
|
|
import com.l2jmobius.gameserver.enums.QuestType;
|
|
import com.l2jmobius.gameserver.instancemanager.PcCafePointsManager;
|
|
import com.l2jmobius.gameserver.instancemanager.QuestManager;
|
|
import com.l2jmobius.gameserver.model.actor.L2Character;
|
|
import com.l2jmobius.gameserver.model.actor.L2Npc;
|
|
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
|
|
import com.l2jmobius.gameserver.model.events.AbstractScript;
|
|
import com.l2jmobius.gameserver.model.holders.ItemHolder;
|
|
import com.l2jmobius.gameserver.network.NpcStringId;
|
|
import com.l2jmobius.gameserver.network.serverpackets.ExShowQuestMark;
|
|
import com.l2jmobius.gameserver.network.serverpackets.PlaySound;
|
|
import com.l2jmobius.gameserver.network.serverpackets.QuestList;
|
|
import com.l2jmobius.gameserver.network.serverpackets.TutorialEnableClientEvent;
|
|
import com.l2jmobius.gameserver.network.serverpackets.TutorialShowQuestionMark;
|
|
import com.l2jmobius.gameserver.util.Util;
|
|
|
|
/**
|
|
* Quest state class.
|
|
* @author Luis Arias
|
|
*/
|
|
public final class QuestState
|
|
{
|
|
protected static final Logger _log = Logger.getLogger(QuestState.class.getName());
|
|
|
|
/** The name of the quest of this QuestState */
|
|
private final String _questName;
|
|
|
|
/** The "owner" of this QuestState object */
|
|
private final L2PcInstance _player;
|
|
|
|
/** The current state of the quest */
|
|
private byte _state;
|
|
|
|
/** A map of key->value pairs containing the quest state variables and their values */
|
|
private Map<String, String> _vars;
|
|
|
|
/**
|
|
* boolean flag letting QuestStateManager know to exit quest when cleaning up
|
|
*/
|
|
private boolean _isExitQuestOnCleanUp = false;
|
|
|
|
/**
|
|
* Constructor of the QuestState. Creates the QuestState object and sets the player's progress of the quest to this QuestState.
|
|
* @param quest the {@link Quest} object associated with the QuestState
|
|
* @param player the owner of this {@link QuestState} object
|
|
* @param state the initial state of the quest
|
|
*/
|
|
public QuestState(Quest quest, L2PcInstance player, byte state)
|
|
{
|
|
_questName = quest.getName();
|
|
_player = player;
|
|
_state = state;
|
|
|
|
player.setQuestState(this);
|
|
}
|
|
|
|
/**
|
|
* @return the name of the quest of this QuestState
|
|
*/
|
|
public String getQuestName()
|
|
{
|
|
return _questName;
|
|
}
|
|
|
|
/**
|
|
* @return the {@link Quest} object of this QuestState
|
|
*/
|
|
public Quest getQuest()
|
|
{
|
|
return QuestManager.getInstance().getQuest(_questName);
|
|
}
|
|
|
|
/**
|
|
* @return the {@link L2PcInstance} object of the owner of this QuestState
|
|
*/
|
|
public L2PcInstance getPlayer()
|
|
{
|
|
return _player;
|
|
}
|
|
|
|
/**
|
|
* @return the current State of this QuestState
|
|
* @see com.l2jmobius.gameserver.model.quest.State
|
|
*/
|
|
public byte getState()
|
|
{
|
|
return _state;
|
|
}
|
|
|
|
/**
|
|
* @return {@code true} if the State of this QuestState is CREATED, {@code false} otherwise
|
|
* @see com.l2jmobius.gameserver.model.quest.State
|
|
*/
|
|
public boolean isCreated()
|
|
{
|
|
return (_state == State.CREATED);
|
|
}
|
|
|
|
/**
|
|
* @return {@code true} if the State of this QuestState is STARTED, {@code false} otherwise
|
|
* @see com.l2jmobius.gameserver.model.quest.State
|
|
*/
|
|
public boolean isStarted()
|
|
{
|
|
return (_state == State.STARTED);
|
|
}
|
|
|
|
/**
|
|
* @return {@code true} if the State of this QuestState is COMPLETED, {@code false} otherwise
|
|
* @see com.l2jmobius.gameserver.model.quest.State
|
|
*/
|
|
public boolean isCompleted()
|
|
{
|
|
return (_state == State.COMPLETED);
|
|
}
|
|
|
|
/**
|
|
* @param state the new state of the quest to set
|
|
* @return {@code true} if state was changed, {@code false} otherwise
|
|
* @see #setState(byte state, boolean saveInDb)
|
|
* @see com.l2jmobius.gameserver.model.quest.State
|
|
*/
|
|
public boolean setState(byte state)
|
|
{
|
|
return setState(state, true);
|
|
}
|
|
|
|
/**
|
|
* Change the state of this quest to the specified value.
|
|
* @param state the new state of the quest to set
|
|
* @param saveInDb if {@code true}, will save the state change in the database
|
|
* @return {@code true} if state was changed, {@code false} otherwise
|
|
* @see com.l2jmobius.gameserver.model.quest.State
|
|
*/
|
|
public boolean setState(byte state, boolean saveInDb)
|
|
{
|
|
if (_state == state)
|
|
{
|
|
return false;
|
|
}
|
|
final boolean newQuest = isCreated();
|
|
_state = state;
|
|
if (saveInDb)
|
|
{
|
|
if (newQuest)
|
|
{
|
|
Quest.createQuestInDb(this);
|
|
}
|
|
else
|
|
{
|
|
Quest.updateQuestInDb(this);
|
|
}
|
|
}
|
|
|
|
_player.sendPacket(new QuestList());
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Add parameter used in quests.
|
|
* @param var String pointing out the name of the variable for quest
|
|
* @param val String pointing out the value of the variable for quest
|
|
* @return String (equal to parameter "val")
|
|
*/
|
|
public String setInternal(String var, String val)
|
|
{
|
|
if (_vars == null)
|
|
{
|
|
_vars = new HashMap<>();
|
|
}
|
|
|
|
if (val == null)
|
|
{
|
|
val = "";
|
|
}
|
|
|
|
_vars.put(var, val);
|
|
return val;
|
|
}
|
|
|
|
public String set(String var, int val)
|
|
{
|
|
return set(var, Integer.toString(val));
|
|
}
|
|
|
|
/**
|
|
* Return value of parameter "val" after adding the couple (var,val) in class variable "vars".<br>
|
|
* Actions:<br>
|
|
* <ul>
|
|
* <li>Initialize class variable "vars" if is null.</li>
|
|
* <li>Initialize parameter "val" if is null</li>
|
|
* <li>Add/Update couple (var,val) in class variable Map "vars"</li>
|
|
* <li>If the key represented by "var" exists in Map "vars", the couple (var,val) is updated in the database.<br>
|
|
* The key is known as existing if the preceding value of the key (given as result of function put()) is not null.<br>
|
|
* If the key doesn't exist, the couple is added/created in the database</li>
|
|
* <ul>
|
|
* @param var String indicating the name of the variable for quest
|
|
* @param val String indicating the value of the variable for quest
|
|
* @return String (equal to parameter "val")
|
|
*/
|
|
public String set(String var, String val)
|
|
{
|
|
if (_vars == null)
|
|
{
|
|
_vars = new HashMap<>();
|
|
}
|
|
|
|
if (val == null)
|
|
{
|
|
val = "";
|
|
}
|
|
|
|
final String old = _vars.put(var, val);
|
|
if (old != null)
|
|
{
|
|
Quest.updateQuestVarInDb(this, var, val);
|
|
}
|
|
else
|
|
{
|
|
Quest.createQuestVarInDb(this, var, val);
|
|
}
|
|
|
|
if ("cond".equals(var))
|
|
{
|
|
try
|
|
{
|
|
int previousVal = 0;
|
|
try
|
|
{
|
|
previousVal = Integer.parseInt(old);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
previousVal = 0;
|
|
}
|
|
setCond(Integer.parseInt(val), previousVal);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.WARNING, _player.getName() + ", " + getQuestName() + " cond [" + val + "] is not an integer. Value stored, but no packet was sent: " + e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
/**
|
|
* Internally handles the progression of the quest so that it is ready for sending appropriate packets to the client.<br>
|
|
* <u><i>Actions :</i></u><br>
|
|
* <ul>
|
|
* <li>Check if the new progress number resets the quest to a previous (smaller) step.</li>
|
|
* <li>If not, check if quest progress steps have been skipped.</li>
|
|
* <li>If skipped, prepare the variable completedStateFlags appropriately to be ready for sending to clients.</li>
|
|
* <li>If no steps were skipped, flags do not need to be prepared...</li>
|
|
* <li>If the passed step resets the quest to a previous step, reset such that steps after the parameter are not considered, while skipped steps before the parameter, if any, maintain their info.</li>
|
|
* </ul>
|
|
* @param cond the current quest progress condition (0 - 31 including)
|
|
* @param old the previous quest progress condition to check against
|
|
*/
|
|
private void setCond(int cond, int old)
|
|
{
|
|
if (cond == old)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int completedStateFlags = 0;
|
|
// cond 0 and 1 do not need completedStateFlags. Also, if cond > 1, the 1st step must
|
|
// always exist (i.e. it can never be skipped). So if cond is 2, we can still safely
|
|
// assume no steps have been skipped.
|
|
// Finally, more than 31 steps CANNOT be supported in any way with skipping.
|
|
if ((cond < 3) || (cond > 31))
|
|
{
|
|
unset("__compltdStateFlags");
|
|
}
|
|
else
|
|
{
|
|
completedStateFlags = getInt("__compltdStateFlags");
|
|
}
|
|
|
|
// case 1: No steps have been skipped so far...
|
|
if (completedStateFlags == 0)
|
|
{
|
|
// check if this step also doesn't skip anything. If so, no further work is needed
|
|
// also, in this case, no work is needed if the state is being reset to a smaller value
|
|
// in those cases, skip forward to informing the client about the change...
|
|
|
|
// ELSE, if we just now skipped for the first time...prepare the flags!!!
|
|
if (cond > (old + 1))
|
|
{
|
|
// set the most significant bit to 1 (indicates that there exist skipped states)
|
|
// also, ensure that the least significant bit is an 1 (the first step is never skipped, no matter
|
|
// what the cond says)
|
|
completedStateFlags = 0x80000001;
|
|
|
|
// since no flag had been skipped until now, the least significant bits must all
|
|
// be set to 1, up until "old" number of bits.
|
|
completedStateFlags |= ((1 << old) - 1);
|
|
|
|
// now, just set the bit corresponding to the passed cond to 1 (current step)
|
|
completedStateFlags |= (1 << (cond - 1));
|
|
set("__compltdStateFlags", String.valueOf(completedStateFlags));
|
|
}
|
|
}
|
|
// case 2: There were exist previously skipped steps
|
|
// if this is a push back to a previous step, clear all completion flags ahead
|
|
else if (cond < old)
|
|
{
|
|
// note, this also unsets the flag indicating that there exist skips
|
|
completedStateFlags &= ((1 << cond) - 1);
|
|
|
|
// now, check if this resulted in no steps being skipped any more
|
|
if (completedStateFlags == ((1 << cond) - 1))
|
|
{
|
|
unset("__compltdStateFlags");
|
|
}
|
|
else
|
|
{
|
|
// set the most significant bit back to 1 again, to correctly indicate that this skips states.
|
|
// also, ensure that the least significant bit is an 1 (the first step is never skipped, no matter
|
|
// what the cond says)
|
|
completedStateFlags |= 0x80000001;
|
|
set("__compltdStateFlags", String.valueOf(completedStateFlags));
|
|
}
|
|
}
|
|
// If this moves forward, it changes nothing on previously skipped steps.
|
|
// Just mark this state and we are done.
|
|
else
|
|
{
|
|
completedStateFlags |= (1 << (cond - 1));
|
|
set("__compltdStateFlags", String.valueOf(completedStateFlags));
|
|
}
|
|
|
|
// send a packet to the client to inform it of the quest progress (step change)
|
|
_player.sendPacket(new QuestList());
|
|
|
|
final Quest q = getQuest();
|
|
if (!q.isCustomQuest() && (cond > 0))
|
|
{
|
|
_player.sendPacket(new ExShowQuestMark(q.getId(), getCond()));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes a quest variable from the list of existing quest variables.
|
|
* @param var the name of the variable to remove
|
|
* @return the previous value of the variable or {@code null} if none were found
|
|
*/
|
|
public String unset(String var)
|
|
{
|
|
if (_vars == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
final String old = _vars.remove(var);
|
|
if (old != null)
|
|
{
|
|
Quest.deleteQuestVarInDb(this, var);
|
|
}
|
|
return old;
|
|
}
|
|
|
|
/**
|
|
* Insert (or update) in the database variables that need to stay persistent for this player after a reboot. This function is for storage of values that are not related to a specific quest but are global instead, i.e. can be used by any script.
|
|
* @param var the name of the variable to save
|
|
* @param value the value of the variable
|
|
*/
|
|
// TODO: these methods should not be here, they could be used by other classes to save some variables, but they can't because they require to create a QuestState first.
|
|
public final void saveGlobalQuestVar(String var, String value)
|
|
{
|
|
try (Connection con = DatabaseFactory.getInstance().getConnection();
|
|
PreparedStatement ps = con.prepareStatement("REPLACE INTO character_quest_global_data (charId, var, value) VALUES (?, ?, ?)"))
|
|
{
|
|
ps.setInt(1, _player.getObjectId());
|
|
ps.setString(2, var);
|
|
ps.setString(3, value);
|
|
ps.executeUpdate();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.WARNING, "Could not insert player's global quest variable: " + e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Read from the database a previously saved variable for this quest.<br>
|
|
* Due to performance considerations, this function should best be used only when the quest is first loaded.<br>
|
|
* Subclasses of this class can define structures into which these loaded values can be saved.<br>
|
|
* However, on-demand usage of this function throughout the script is not prohibited, only not recommended.<br>
|
|
* Values read from this function were entered by calls to "saveGlobalQuestVar".
|
|
* @param var the name of the variable whose value to get
|
|
* @return the value of the variable or an empty string if the variable does not exist in the database
|
|
*/
|
|
// TODO: these methods should not be here, they could be used by other classes to save some variables, but they can't because they require to create a QuestState first.
|
|
public final String getGlobalQuestVar(String var)
|
|
{
|
|
String result = "";
|
|
try (Connection con = DatabaseFactory.getInstance().getConnection();
|
|
PreparedStatement ps = con.prepareStatement("SELECT value FROM character_quest_global_data WHERE charId = ? AND var = ?"))
|
|
{
|
|
ps.setInt(1, _player.getObjectId());
|
|
ps.setString(2, var);
|
|
try (ResultSet rs = ps.executeQuery())
|
|
{
|
|
if (rs.first())
|
|
{
|
|
result = rs.getString(1);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.WARNING, "Could not load player's global quest variable: " + e.getMessage(), e);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Permanently delete a global quest variable from the database.
|
|
* @param var the name of the variable to delete
|
|
*/
|
|
public final void deleteGlobalQuestVar(String var)
|
|
{
|
|
try (Connection con = DatabaseFactory.getInstance().getConnection();
|
|
PreparedStatement ps = con.prepareStatement("DELETE FROM character_quest_global_data WHERE charId = ? AND var = ?"))
|
|
{
|
|
ps.setInt(1, _player.getObjectId());
|
|
ps.setString(2, var);
|
|
ps.executeUpdate();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.WARNING, "could not delete player's global quest variable; charId = " + _player.getObjectId() + ", variable name = " + var + ". Exception: " + e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param var the name of the variable to get
|
|
* @return the value of the variable from the list of quest variables
|
|
*/
|
|
public String get(String var)
|
|
{
|
|
if (_vars == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return _vars.get(var);
|
|
}
|
|
|
|
/**
|
|
* @param var the name of the variable to get
|
|
* @return the integer value of the variable or 0 if the variable does not exist or its value is not an integer
|
|
*/
|
|
public int getInt(String var)
|
|
{
|
|
if (_vars == null)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
final String variable = _vars.get(var);
|
|
if ((variable == null) || variable.isEmpty())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int varint = 0;
|
|
try
|
|
{
|
|
varint = Integer.parseInt(variable);
|
|
}
|
|
catch (NumberFormatException nfe)
|
|
{
|
|
_log.log(Level.INFO, "Quest " + getQuestName() + ", method getInt(" + var + "), tried to parse a non-integer value (" + variable + "). Char Id: " + _player.getObjectId(), nfe);
|
|
}
|
|
|
|
return varint;
|
|
}
|
|
|
|
/**
|
|
* Checks if the quest state progress ({@code cond}) is at the specified step.
|
|
* @param condition the condition to check against
|
|
* @return {@code true} if the quest condition is equal to {@code condition}, {@code false} otherwise
|
|
* @see #getInt(String var)
|
|
*/
|
|
public boolean isCond(int condition)
|
|
{
|
|
return (getInt("cond") == condition);
|
|
}
|
|
|
|
/**
|
|
* Sets the quest state progress ({@code cond}) to the specified step.
|
|
* @param value the new value of the quest state progress
|
|
* @return this {@link QuestState} object
|
|
* @see #set(String var, String val)
|
|
* @see #setCond(int, boolean)
|
|
*/
|
|
public QuestState setCond(int value)
|
|
{
|
|
if (isStarted())
|
|
{
|
|
set("cond", Integer.toString(value));
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* @return the current quest progress ({@code cond})
|
|
*/
|
|
public int getCond()
|
|
{
|
|
if (isStarted())
|
|
{
|
|
return getInt("cond");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Check if a given variable is set for this quest.
|
|
* @param variable the variable to check
|
|
* @return {@code true} if the variable is set, {@code false} otherwise
|
|
* @see #get(String)
|
|
* @see #getInt(String)
|
|
* @see #getCond()
|
|
*/
|
|
public boolean isSet(String variable)
|
|
{
|
|
return (get(variable) != null);
|
|
}
|
|
|
|
/**
|
|
* Sets the quest state progress ({@code cond}) to the specified step.
|
|
* @param value the new value of the quest state progress
|
|
* @param playQuestMiddle if {@code true}, plays "ItemSound.quest_middle"
|
|
* @return this {@link QuestState} object
|
|
* @see #setCond(int value)
|
|
* @see #set(String var, String val)
|
|
*/
|
|
public QuestState setCond(int value, boolean playQuestMiddle)
|
|
{
|
|
if (!isStarted())
|
|
{
|
|
return this;
|
|
}
|
|
set("cond", String.valueOf(value));
|
|
|
|
if (playQuestMiddle)
|
|
{
|
|
AbstractScript.playSound(_player, QuestSound.ITEMSOUND_QUEST_MIDDLE);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public QuestState setMemoState(int value)
|
|
{
|
|
set("memoState", String.valueOf(value));
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* @return the current Memo State
|
|
*/
|
|
public int getMemoState()
|
|
{
|
|
if (isStarted())
|
|
{
|
|
return getInt("memoState");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public boolean isMemoState(int memoState)
|
|
{
|
|
return (getInt("memoState") == memoState);
|
|
}
|
|
|
|
/**
|
|
* Gets the memo state ex.
|
|
* @param slot the slot where the value was saved
|
|
* @return the memo state ex
|
|
*/
|
|
public int getMemoStateEx(int slot)
|
|
{
|
|
if (isStarted())
|
|
{
|
|
return getInt("memoStateEx" + slot);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Sets the memo state ex.
|
|
* @param slot the slot where the value will be saved
|
|
* @param value the value
|
|
* @return this QuestState
|
|
*/
|
|
public QuestState setMemoStateEx(int slot, int value)
|
|
{
|
|
set("memoStateEx" + slot, String.valueOf(value));
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Verifies if the given value is equal to the current memos state ex.
|
|
* @param slot the slot where the value was saved
|
|
* @param memoStateEx the value to verify
|
|
* @return {@code true} if the values are equal, {@code false} otherwise
|
|
*/
|
|
public boolean isMemoStateEx(int slot, int memoStateEx)
|
|
{
|
|
return (getMemoStateEx(slot) == memoStateEx);
|
|
}
|
|
|
|
/**
|
|
* Add player to get notification of characters death
|
|
* @param character the {@link L2Character} object of the character to get notification of death
|
|
*/
|
|
public void addNotifyOfDeath(L2Character character)
|
|
{
|
|
if (!(character instanceof L2PcInstance))
|
|
{
|
|
return;
|
|
}
|
|
|
|
((L2PcInstance) character).addNotifyQuestOfDeath(this);
|
|
}
|
|
|
|
// TODO: This all remains because of backward compatibility, should be cleared when all scripts are rewritten in java
|
|
|
|
/**
|
|
* Return the quantity of one sort of item hold by the player
|
|
* @param itemId the Id of the item wanted to be count
|
|
* @return long
|
|
*/
|
|
public long getQuestItemsCount(int itemId)
|
|
{
|
|
return AbstractScript.getQuestItemsCount(_player, itemId);
|
|
}
|
|
|
|
/**
|
|
* @param itemId the Id of the item required
|
|
* @return true if item exists in player's inventory, false - if not
|
|
*/
|
|
public boolean hasQuestItems(int itemId)
|
|
{
|
|
return AbstractScript.hasQuestItems(_player, itemId);
|
|
}
|
|
|
|
/**
|
|
* @param itemIds list of items that are required
|
|
* @return true if all items exists in player's inventory, false - if not
|
|
*/
|
|
public boolean hasQuestItems(int... itemIds)
|
|
{
|
|
return AbstractScript.hasQuestItems(_player, itemIds);
|
|
}
|
|
|
|
/**
|
|
* Return the level of enchantment on the weapon of the player(Done specifically for weapon SA's)
|
|
* @param itemId Id of the item to check enchantment
|
|
* @return int
|
|
*/
|
|
public int getEnchantLevel(int itemId)
|
|
{
|
|
return AbstractScript.getEnchantLevel(_player, itemId);
|
|
}
|
|
|
|
/**
|
|
* Give adena to the player
|
|
* @param count
|
|
* @param applyRates
|
|
*/
|
|
public void giveAdena(long count, boolean applyRates)
|
|
{
|
|
AbstractScript.giveAdena(_player, count, applyRates);
|
|
}
|
|
|
|
/**
|
|
* Give reward to player using multiplier's
|
|
* @param item
|
|
*/
|
|
public void rewardItems(ItemHolder item)
|
|
{
|
|
AbstractScript.rewardItems(_player, item);
|
|
}
|
|
|
|
/**
|
|
* Give reward to player using multiplier's
|
|
* @param itemId
|
|
* @param count
|
|
*/
|
|
public void rewardItems(int itemId, long count)
|
|
{
|
|
AbstractScript.rewardItems(_player, itemId, count);
|
|
}
|
|
|
|
/**
|
|
* Give item/reward to the player
|
|
* @param itemId
|
|
* @param count
|
|
*/
|
|
public void giveItems(int itemId, long count)
|
|
{
|
|
AbstractScript.giveItems(_player, itemId, count, 0);
|
|
}
|
|
|
|
public void giveItems(ItemHolder holder)
|
|
{
|
|
AbstractScript.giveItems(_player, holder.getId(), holder.getCount(), 0);
|
|
}
|
|
|
|
public void giveItems(int itemId, long count, int enchantlevel)
|
|
{
|
|
AbstractScript.giveItems(_player, itemId, count, enchantlevel);
|
|
}
|
|
|
|
public void giveItems(int itemId, long count, byte attributeId, int attributeLevel)
|
|
{
|
|
AbstractScript.giveItems(_player, itemId, count, attributeId, attributeLevel);
|
|
}
|
|
|
|
public boolean giveItemRandomly(int itemId, long amount, long limit, double dropChance, boolean playSound)
|
|
{
|
|
return AbstractScript.giveItemRandomly(_player, null, itemId, amount, amount, limit, dropChance, playSound);
|
|
}
|
|
|
|
public boolean giveItemRandomly(L2Npc npc, int itemId, long amount, long limit, double dropChance, boolean playSound)
|
|
{
|
|
return AbstractScript.giveItemRandomly(_player, npc, itemId, amount, amount, limit, dropChance, playSound);
|
|
}
|
|
|
|
public boolean giveItemRandomly(L2Npc npc, int itemId, long minAmount, long maxAmount, long limit, double dropChance, boolean playSound)
|
|
{
|
|
return AbstractScript.giveItemRandomly(_player, npc, itemId, minAmount, maxAmount, limit, dropChance, playSound);
|
|
}
|
|
|
|
// TODO: More radar functions need to be added when the radar class is complete.
|
|
// BEGIN STUFF THAT WILL PROBABLY BE CHANGED
|
|
public void addRadar(int x, int y, int z)
|
|
{
|
|
_player.getRadar().addMarker(x, y, z);
|
|
}
|
|
|
|
public void removeRadar(int x, int y, int z)
|
|
{
|
|
_player.getRadar().removeMarker(x, y, z);
|
|
}
|
|
|
|
public void clearRadar()
|
|
{
|
|
_player.getRadar().removeAllMarkers();
|
|
}
|
|
|
|
// END STUFF THAT WILL PROBABLY BE CHANGED
|
|
|
|
/**
|
|
* Remove items from player's inventory when talking to NPC in order to have rewards.<br>
|
|
* Actions:<br>
|
|
* <ul>
|
|
* <li>Destroy quantity of items wanted</li>
|
|
* <li>Send new inventory list to player</li>
|
|
* </ul>
|
|
* @param itemId Identifier of the item
|
|
* @param count Quantity of items to destroy
|
|
*/
|
|
public void takeItems(int itemId, long count)
|
|
{
|
|
AbstractScript.takeItems(_player, itemId, count);
|
|
}
|
|
|
|
/**
|
|
* Send a packet in order to play a sound to the player.
|
|
* @param sound the name of the sound to play
|
|
*/
|
|
public void playSound(String sound)
|
|
{
|
|
AbstractScript.playSound(_player, sound);
|
|
}
|
|
|
|
/**
|
|
* Send a packet in order to play a sound to the player.
|
|
* @param sound the {@link QuestSound} object of the sound to play
|
|
*/
|
|
public void playSound(QuestSound sound)
|
|
{
|
|
AbstractScript.playSound(_player, sound);
|
|
}
|
|
|
|
/**
|
|
* Add XP and SP as quest reward
|
|
* @param exp
|
|
* @param sp
|
|
*/
|
|
public void addExpAndSp(long exp, int sp)
|
|
{
|
|
AbstractScript.addExpAndSp(_player, exp, sp);
|
|
PcCafePointsManager.getInstance().givePcCafePoint(getPlayer(), (long) (exp * Config.RATE_QUEST_REWARD_XP));
|
|
}
|
|
|
|
/**
|
|
* @param loc
|
|
* @return number of ticks from GameTimeController
|
|
*/
|
|
public int getItemEquipped(int loc)
|
|
{
|
|
return AbstractScript.getItemEquipped(_player, loc);
|
|
}
|
|
|
|
/**
|
|
* @return {@code true} if quest is to be exited on clean up by QuestStateManager, {@code false} otherwise
|
|
*/
|
|
public final boolean isExitQuestOnCleanUp()
|
|
{
|
|
return _isExitQuestOnCleanUp;
|
|
}
|
|
|
|
/**
|
|
* @param isExitQuestOnCleanUp {@code true} if quest is to be exited on clean up by QuestStateManager, {@code false} otherwise
|
|
*/
|
|
public void setIsExitQuestOnCleanUp(boolean isExitQuestOnCleanUp)
|
|
{
|
|
_isExitQuestOnCleanUp = isExitQuestOnCleanUp;
|
|
}
|
|
|
|
/**
|
|
* Start a timed event for a quest.<br>
|
|
* Will call an event in onEvent/onAdvEvent.
|
|
* @param name the name of the timer/event
|
|
* @param time time in milliseconds till the event is executed
|
|
*/
|
|
public void startQuestTimer(String name, long time)
|
|
{
|
|
getQuest().startQuestTimer(name, time, null, _player, false);
|
|
}
|
|
|
|
/**
|
|
* Start a timed event for a quest.<br>
|
|
* Will call an event in onEvent/onAdvEvent.
|
|
* @param name the name of the timer/event
|
|
* @param time time in milliseconds till the event is executed
|
|
* @param npc the L2Npc associated with this event
|
|
*/
|
|
public void startQuestTimer(String name, long time, L2Npc npc)
|
|
{
|
|
getQuest().startQuestTimer(name, time, npc, _player, false);
|
|
}
|
|
|
|
/**
|
|
* Start a repeating timed event for a quest.<br>
|
|
* Will call an event in onEvent/onAdvEvent.
|
|
* @param name the name of the timer/event
|
|
* @param time time in milliseconds till the event is executed/repeated
|
|
*/
|
|
public void startRepeatingQuestTimer(String name, long time)
|
|
{
|
|
getQuest().startQuestTimer(name, time, null, _player, true);
|
|
}
|
|
|
|
/**
|
|
* Start a repeating timed event for a quest.<br>
|
|
* Will call an event in onEvent/onAdvEvent.
|
|
* @param name the name of the timer/event
|
|
* @param time time in milliseconds till the event is executed/repeated
|
|
* @param npc the L2Npc associated with this event
|
|
*/
|
|
public void startRepeatingQuestTimer(String name, long time, L2Npc npc)
|
|
{
|
|
getQuest().startQuestTimer(name, time, npc, _player, true);
|
|
}
|
|
|
|
/**
|
|
* @param name the name of the QuestTimer required
|
|
* @return the {@link QuestTimer} object with the specified name or {@code null} if it doesn't exist
|
|
*/
|
|
public final QuestTimer getQuestTimer(String name)
|
|
{
|
|
return getQuest().getQuestTimer(name, null, _player);
|
|
}
|
|
|
|
// --- Spawn methods ---
|
|
/**
|
|
* Add a temporary spawn of the specified npc.<br>
|
|
* Player's coordinates will be used for the spawn.
|
|
* @param npcId the Id of the npc to spawn
|
|
* @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
|
|
* @see #addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
|
|
*/
|
|
public L2Npc addSpawn(int npcId)
|
|
{
|
|
return addSpawn(npcId, _player.getX(), _player.getY(), _player.getZ(), 0, false, 0, false);
|
|
}
|
|
|
|
/**
|
|
* Add a temporary spawn of the specified npc.<br>
|
|
* Player's coordinates will be used for the spawn.
|
|
* @param npcId the Id of the npc to spawn
|
|
* @param despawnDelay time in milliseconds till the npc is despawned (default: 0)
|
|
* @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
|
|
* @see #addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
|
|
*/
|
|
public L2Npc addSpawn(int npcId, int despawnDelay)
|
|
{
|
|
return addSpawn(npcId, _player.getX(), _player.getY(), _player.getZ(), 0, false, despawnDelay, false);
|
|
}
|
|
|
|
/**
|
|
* Add a temporary spawn of the specified npc.
|
|
* @param npcId the Id of the npc to spawn
|
|
* @param x the X coordinate of the npc spawn location
|
|
* @param y the Y coordinate of the npc spawn location
|
|
* @param z the Z coordinate (height) of the npc spawn location
|
|
* @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
|
|
* @see #addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
|
|
*/
|
|
public L2Npc addSpawn(int npcId, int x, int y, int z)
|
|
{
|
|
return addSpawn(npcId, x, y, z, 0, false, 0, false);
|
|
}
|
|
|
|
/**
|
|
* Add a temporary spawn of the specified npc.
|
|
* @param npcId the Id of the npc to spawn
|
|
* @param x the X coordinate of the npc spawn location
|
|
* @param y the Y coordinate of the npc spawn location
|
|
* @param z the Z coordinate (height) of the npc spawn location
|
|
* @param despawnDelay time in milliseconds till the npc is despawned (default: 0)
|
|
* @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
|
|
* @see #addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
|
|
*/
|
|
public L2Npc addSpawn(int npcId, int x, int y, int z, int despawnDelay)
|
|
{
|
|
return addSpawn(npcId, x, y, z, 0, false, despawnDelay, false);
|
|
}
|
|
|
|
/**
|
|
* Add a temporary spawn of the specified npc.
|
|
* @param npcId the Id of the npc to spawn
|
|
* @param cha the character whose coordinates will be used for the npc spawn
|
|
* @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
|
|
* @see #addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
|
|
*/
|
|
public L2Npc addSpawn(int npcId, L2Character cha)
|
|
{
|
|
return addSpawn(npcId, cha.getX(), cha.getY(), cha.getZ(), cha.getHeading(), true, 0, false);
|
|
}
|
|
|
|
/**
|
|
* Add a temporary spawn of the specified npc.
|
|
* @param npcId the Id of the npc to spawn
|
|
* @param cha the character whose coordinates will be used for the npc spawn
|
|
* @param despawnDelay time in milliseconds till the npc is despawned (default: 0)
|
|
* @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
|
|
* @see #addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
|
|
*/
|
|
public L2Npc addSpawn(int npcId, L2Character cha, int despawnDelay)
|
|
{
|
|
return addSpawn(npcId, cha.getX(), cha.getY(), cha.getZ(), cha.getHeading(), true, despawnDelay, false);
|
|
}
|
|
|
|
/**
|
|
* Add a temporary spawn of the specified npc.
|
|
* @param npcId the Id of the npc to spawn
|
|
* @param cha the character whose coordinates will be used for the npc spawn
|
|
* @param randomOffset if {@code true}, adds +/- 50~100 to X/Y coordinates of the spawn location
|
|
* @param despawnDelay time in milliseconds till the npc is despawned (default: 0)
|
|
* @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
|
|
* @see #addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
|
|
*/
|
|
public L2Npc addSpawn(int npcId, L2Character cha, boolean randomOffset, int despawnDelay)
|
|
{
|
|
return addSpawn(npcId, cha.getX(), cha.getY(), cha.getZ(), cha.getHeading(), randomOffset, despawnDelay, false);
|
|
}
|
|
|
|
/**
|
|
* Add a temporary spawn of the specified npc.
|
|
* @param npcId the Id of the npc to spawn
|
|
* @param x the X coordinate of the npc spawn location
|
|
* @param y the Y coordinate of the npc spawn location
|
|
* @param z the Z coordinate (height) of the npc spawn location
|
|
* @param heading the heading of the npc
|
|
* @param randomOffset if {@code true}, adds +/- 50~100 to X/Y coordinates of the spawn location
|
|
* @param despawnDelay time in milliseconds till the npc is despawned (default: 0)
|
|
* @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
|
|
* @see #addSpawn(int, int, int, int, int, boolean, int, boolean)
|
|
*/
|
|
public L2Npc addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay)
|
|
{
|
|
return addSpawn(npcId, x, y, z, heading, randomOffset, despawnDelay, false);
|
|
}
|
|
|
|
/**
|
|
* Add a temporary spawn of the specified npc.
|
|
* @param npcId the Id of the npc to spawn
|
|
* @param x the X coordinate of the npc spawn location
|
|
* @param y the Y coordinate of the npc spawn location
|
|
* @param z the Z coordinate (height) of the npc spawn location
|
|
* @param heading the heading of the npc
|
|
* @param randomOffset if {@code true}, adds +/- 50~100 to X/Y coordinates of the spawn location
|
|
* @param despawnDelay time in milliseconds till the npc is despawned (default: 0)
|
|
* @param isSummonSpawn if {@code true}, displays a summon animation on npc spawn (default: {@code false})
|
|
* @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
|
|
* @see #addSpawn(int)
|
|
* @see #addSpawn(int, int)
|
|
* @see #addSpawn(int, L2Character)
|
|
* @see #addSpawn(int, L2Character, int)
|
|
* @see #addSpawn(int, int, int, int)
|
|
* @see #addSpawn(int, L2Character, boolean, int)
|
|
* @see #addSpawn(int, int, int, int, int)
|
|
* @see #addSpawn(int, int, int, int, int, boolean, int)
|
|
* @see #addSpawn(int, int, int, int, int, boolean, int, boolean)
|
|
*/
|
|
public L2Npc addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
|
|
{
|
|
return AbstractScript.addSpawn(npcId, x, y, z, heading, randomOffset, despawnDelay, isSummonSpawn);
|
|
}
|
|
|
|
/**
|
|
* Send an HTML file to the specified player.
|
|
* @param filename the name of the HTML file to show
|
|
* @return the contents of the HTML file that was sent to the player
|
|
* @see #showHtmlFile(String, L2Npc)
|
|
* @see Quest#showHtmlFile(L2PcInstance, String)
|
|
* @see Quest#showHtmlFile(L2PcInstance, String, L2Npc)
|
|
*/
|
|
public String showHtmlFile(String filename)
|
|
{
|
|
return showHtmlFile(filename, null);
|
|
}
|
|
|
|
/**
|
|
* Send an HTML file to the specified player.
|
|
* @param filename the name of the HTML file to show
|
|
* @param npc the NPC that is showing the HTML file
|
|
* @return the contents of the HTML file that was sent to the player
|
|
* @see Quest#showHtmlFile(L2PcInstance, String)
|
|
* @see Quest#showHtmlFile(L2PcInstance, String, L2Npc)
|
|
*/
|
|
public String showHtmlFile(String filename, L2Npc npc)
|
|
{
|
|
return getQuest().showHtmlFile(_player, filename, npc);
|
|
}
|
|
|
|
/**
|
|
* Set condition to 1, state to STARTED and play the "ItemSound.quest_accept".<br>
|
|
* Works only if state is CREATED and the quest is not a custom quest.
|
|
* @return the newly created {@code QuestState} object
|
|
*/
|
|
public QuestState startQuest()
|
|
{
|
|
if (isCreated() && !getQuest().isCustomQuest())
|
|
{
|
|
set("cond", "1");
|
|
setState(State.STARTED);
|
|
playSound(QuestSound.ITEMSOUND_QUEST_ACCEPT);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Finishes the quest and removes all quest items associated with this quest from the player's inventory.<br>
|
|
* If {@code type} is {@code QuestType.ONE_TIME}, also removes all other quest data associated with this quest.
|
|
* @param type the {@link QuestType} of the quest
|
|
* @return this {@link QuestState} object
|
|
* @see #exitQuest(QuestType type, boolean playExitQuest)
|
|
* @see #exitQuest(boolean repeatable)
|
|
* @see #exitQuest(boolean repeatable, boolean playExitQuest)
|
|
*/
|
|
public QuestState exitQuest(QuestType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case DAILY:
|
|
{
|
|
exitQuest(false);
|
|
setRestartTime();
|
|
break;
|
|
}
|
|
// case ONE_TIME:
|
|
// case REPEATABLE:
|
|
default:
|
|
{
|
|
exitQuest(type == QuestType.REPEATABLE);
|
|
break;
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Finishes the quest and removes all quest items associated with this quest from the player's inventory.<br>
|
|
* If {@code type} is {@code QuestType.ONE_TIME}, also removes all other quest data associated with this quest.
|
|
* @param type the {@link QuestType} of the quest
|
|
* @param playExitQuest if {@code true}, plays "ItemSound.quest_finish"
|
|
* @return this {@link QuestState} object
|
|
* @see #exitQuest(QuestType type)
|
|
* @see #exitQuest(boolean repeatable)
|
|
* @see #exitQuest(boolean repeatable, boolean playExitQuest)
|
|
*/
|
|
public QuestState exitQuest(QuestType type, boolean playExitQuest)
|
|
{
|
|
exitQuest(type);
|
|
if (playExitQuest)
|
|
{
|
|
playSound(QuestSound.ITEMSOUND_QUEST_FINISH);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Finishes the quest and removes all quest items associated with this quest from the player's inventory.<br>
|
|
* If {@code repeatable} is set to {@code false}, also removes all other quest data associated with this quest.
|
|
* @param repeatable if {@code true}, deletes all data and variables of this quest, otherwise keeps them
|
|
* @return this {@link QuestState} object
|
|
* @see #exitQuest(QuestType type)
|
|
* @see #exitQuest(QuestType type, boolean playExitQuest)
|
|
* @see #exitQuest(boolean repeatable, boolean playExitQuest)
|
|
*/
|
|
public QuestState exitQuest(boolean repeatable)
|
|
{
|
|
_player.removeNotifyQuestOfDeath(this);
|
|
|
|
if (!isStarted())
|
|
{
|
|
return this;
|
|
}
|
|
|
|
// Clean registered quest items
|
|
getQuest().removeRegisteredQuestItems(_player);
|
|
|
|
Quest.deleteQuestInDb(this, repeatable);
|
|
if (repeatable)
|
|
{
|
|
_player.delQuestState(getQuestName());
|
|
_player.sendPacket(new QuestList());
|
|
}
|
|
else
|
|
{
|
|
setState(State.COMPLETED);
|
|
}
|
|
_vars = null;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Finishes the quest and removes all quest items associated with this quest from the player's inventory.<br>
|
|
* If {@code repeatable} is set to {@code false}, also removes all other quest data associated with this quest.
|
|
* @param repeatable if {@code true}, deletes all data and variables of this quest, otherwise keeps them
|
|
* @param playExitQuest if {@code true}, plays "ItemSound.quest_finish"
|
|
* @return this {@link QuestState} object
|
|
* @see #exitQuest(QuestType type)
|
|
* @see #exitQuest(QuestType type, boolean playExitQuest)
|
|
* @see #exitQuest(boolean repeatable)
|
|
*/
|
|
public QuestState exitQuest(boolean repeatable, boolean playExitQuest)
|
|
{
|
|
exitQuest(repeatable);
|
|
if (playExitQuest)
|
|
{
|
|
playSound(QuestSound.ITEMSOUND_QUEST_FINISH);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public void showQuestionMark(int number)
|
|
{
|
|
_player.sendPacket(new TutorialShowQuestionMark(number));
|
|
}
|
|
|
|
// TODO make tutorial voices the same as quest sounds
|
|
public void playTutorialVoice(String voice)
|
|
{
|
|
_player.sendPacket(new PlaySound(2, voice, 0, 0, _player.getX(), _player.getY(), _player.getZ()));
|
|
}
|
|
|
|
/**
|
|
* Set the restart time for the daily quests.<br>
|
|
* The time is hardcoded at {@link Quest#getResetHour()} hours, {@link Quest#getResetMinutes()} minutes of the following day.<br>
|
|
* It can be overridden in scripts (quests).
|
|
*/
|
|
public void setRestartTime()
|
|
{
|
|
final Calendar reDo = Calendar.getInstance();
|
|
if (reDo.get(Calendar.HOUR_OF_DAY) >= getQuest().getResetHour())
|
|
{
|
|
reDo.add(Calendar.DATE, 1);
|
|
}
|
|
reDo.set(Calendar.HOUR_OF_DAY, getQuest().getResetHour());
|
|
reDo.set(Calendar.MINUTE, getQuest().getResetMinutes());
|
|
set("restartTime", String.valueOf(reDo.getTimeInMillis()));
|
|
}
|
|
|
|
/**
|
|
* Check if a daily quest is available to be started over.
|
|
* @return {@code true} if the quest is available, {@code false} otherwise.
|
|
*/
|
|
public boolean isNowAvailable()
|
|
{
|
|
final String val = get("restartTime");
|
|
return ((val == null) || !Util.isDigit(val)) || (Long.parseLong(val) <= System.currentTimeMillis());
|
|
}
|
|
|
|
/**
|
|
* @return returns {@link NpcStringId} that is will order all teleports along the way as first option for player when he is on a quest.
|
|
*/
|
|
public NpcStringId getQuestLocation()
|
|
{
|
|
return NpcStringId.getNpcStringIdOrDefault(getInt("LOCATION_ID"), null);
|
|
}
|
|
|
|
/**
|
|
* Sets {@link NpcStringId} that is will order all teleports along the way as first option for player when he is on a quest.
|
|
* @param id
|
|
*/
|
|
public void setQuestLocation(NpcStringId id)
|
|
{
|
|
if (id == null)
|
|
{
|
|
throw new NullPointerException("Attempting to set null quest location string for quest: " + getQuestName());
|
|
}
|
|
set("LOCATION_ID", id.getId());
|
|
}
|
|
|
|
/**
|
|
* Removes the {@link NpcStringId} that is will order all teleports along the way as first option for player when he is on a quest.
|
|
*/
|
|
public void unsetQuestLocation()
|
|
{
|
|
unset("LOCATION_ID");
|
|
}
|
|
|
|
public void onTutorialClientEvent(int number)
|
|
{
|
|
getPlayer().sendPacket(new TutorialEnableClientEvent(number));
|
|
}
|
|
}
|