Você não é registrado, por favor registre-se para ter acesso ao conteúdo completo.
Caso seja registrado, efetue login.
Esqueceu sua senha? Clique aqui
Recomendamos o uso do Mozilla Firefox para uma melhor visualização.    


Início Postados Hoje Marcar Fóruns Como Lidos Álbums Banidos SE Team Medalhas
Voltar   Secret Experience > Área L2J > [L2J] Dúvidas
Registrar Loteria VIPStaff SERegras do fórum Comunidade Arcade Postados Hoje Pesquisar Experience
   

Secret Experience.NET   Secret Experience Corporation - Welcome To The Real World
     Anúncios SE

Resposta
 
Ferramentas do Tópico Modos de Exibição
Antigo 26-01-2010, 10:37 PM   #1
lelebrr
Membro - Capitão
 
Avatar de lelebrr
 
Registrado em: Feb 2009
Posts: 125
Agradeceu: 51
Agradecido 50 Vezes em 22 Posts
Achei Ruim:
Acharam ruim Vezes em Posts
Pontos: 3,786, Nível: 38
Pontos: 3,786, Nível: 38 Pontos: 3,786, Nível: 38 Pontos: 3,786, Nível: 38
Atividade: 99%
Atividade: 99% Atividade: 99% Atividade: 99%

Inventório de lelebrr

Padrão Colocar linhas no java

Gente .. tenho uma duvida aki !
fiz tudo certinho ..
to com meu projeto aki no pc...
mas suponhamos ..
como coloco essas linhas??

sendo q sei q p sinal + eh pra adicionar , - pra retirar .. etc ..

Código: [Somente Usuários Registrados Podem Visualizar os Links Desta PáginaClique aqui para se Registrar]
Index: /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/model/actor/instance/L2PcInstance.java
===================================================================
--- /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/model/actor/instance/L2PcInstance.java (revision 8)
+++ /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/model/actor/instance/L2PcInstance.java (revision 18)
@@ -216,6 +216,6 @@
 	private static final String RESTORE_SKILL_SAVE = "SELECT skill_id,skill_level,effect_count,effect_cur_time, reuse_delay FROM character_skills_save WHERE char_obj_id=? AND class_index=? AND restore_type=? ORDER BY buff_index ASC";
 	private static final String DELETE_SKILL_SAVE = "DELETE FROM character_skills_save WHERE char_obj_id=? AND class_index=?";
-    private static final String UPDATE_CHARACTER = "UPDATE characters SET level=?,maxHp=?,curHp=?,maxCp=?,curCp=?,maxMp=?,curMp=?,str=?,con=?,dex=?,_int=?,men=?,wit=?,face=?,hairStyle=?,hairColor=?,heading=?,x=?,y=?,z=?,exp=?,expBeforeDeath=?,sp=?,karma=?,pvpkills=?,pkkills=?,rec_have=?,rec_left=?,clanid=?,maxload=?,race=?,classid=?,deletetime=?,title=?,accesslevel=?,online=?,isin7sdungeon=?,clan_privs=?,wantspeace=?,base_class=?,onlinetime=?,punish_level=?,punish_timer=?,newbie=?,nobless=?,power_grade=?,subpledge=?,last_recom_date=?,lvl_joined_academy=?,apprentice=?,sponsor=?,varka_ketra_ally=?,clan_join_expiry_time=?,clan_create_expiry_time=?,char_name=?,death_penalty_level=? WHERE obj_id=?";
-    private static final String RESTORE_CHARACTER = "SELECT account_name, obj_Id, char_name, level, maxHp, curHp, maxCp, curCp, maxMp, curMp, acc, crit, evasion, mAtk, mDef, mSpd, pAtk, pDef, pSpd, runSpd, walkSpd, str, con, dex, _int, men, wit, face, hairStyle, hairColor, sex, heading, x, y, z, movement_multiplier, attack_speed_multiplier, colRad, colHeight, exp, expBeforeDeath, sp, karma, pvpkills, pkkills, clanid, maxload, race, classid, deletetime, cancraft, title, rec_have, rec_left, accesslevel, online, char_slot, lastAccess, clan_privs, wantspeace, base_class, onlinetime, isin7sdungeon, punish_level, punish_timer, newbie, nobless, power_grade, subpledge, last_recom_date, lvl_joined_academy, apprentice, sponsor, varka_ketra_ally,clan_join_expiry_time,clan_create_expiry_time,death_penalty_level FROM characters WHERE obj_id=?";
+    private static final String UPDATE_CHARACTER = "UPDATE characters SET level=?,maxHp=?,curHp=?,maxCp=?,curCp=?,maxMp=?,curMp=?,str=?,con=?,dex=?,_int=?,men=?,wit=?,face=?,hairStyle=?,hairColor=?,heading=?,x=?,y=?,z=?,exp=?,expBeforeDeath=?,sp=?,karma=?,pvpkills=?,pkkills=?,rec_have=?,rec_left=?,clanid=?,maxload=?,race=?,classid=?,deletetime=?,title=?,accesslevel=?,online=?,isin7sdungeon=?,clan_privs=?,wantspeace=?,base_class=?,onlinetime=?,punish_level=?,punish_timer=?,newbie=?,nobless=?,power_grade=?,subpledge=?,last_recom_date=?,lvl_joined_academy=?,apprentice=?,sponsor=?,varka_ketra_ally=?,clan_join_expiry_time=?,clan_create_expiry_time=?,char_name=?,death_penalty_level=?,donator=? WHERE obj_id=?";
+    private static final String RESTORE_CHARACTER = "SELECT account_name, obj_Id, char_name, level, maxHp, curHp, maxCp, curCp, maxMp, curMp, acc, crit, evasion, mAtk, mDef, mSpd, pAtk, pDef, pSpd, runSpd, walkSpd, str, con, dex, _int, men, wit, face, hairStyle, hairColor, sex, heading, x, y, z, movement_multiplier, attack_speed_multiplier, colRad, colHeight, exp, expBeforeDeath, sp, karma, pvpkills, pkkills, clanid, maxload, race, classid, deletetime, cancraft, title, rec_have, rec_left, accesslevel, online, char_slot, lastAccess, clan_privs, wantspeace, base_class, onlinetime, isin7sdungeon, punish_level, punish_timer, newbie, nobless, power_grade, subpledge, last_recom_date, lvl_joined_academy, apprentice, sponsor, varka_ketra_ally,clan_join_expiry_time,clan_create_expiry_time,death_penalty_level,donator FROM characters WHERE obj_id=?";
 	private static final String RESTORE_CHAR_SUBCLASSES = "SELECT class_id,exp,sp,level,class_index FROM character_subclasses WHERE char_obj_id=? ORDER BY class_index ASC";
 	private static final String ADD_CHAR_SUBCLASS = "INSERT INTO character_subclasses (char_obj_id,class_id,exp,sp,level,class_index) VALUES (?,?,?,?,?,?)";
@@ -448,4 +448,5 @@
 	private boolean _noble = false;
 	private boolean _hero = false;
+	private boolean _isDonator = false;
 	/** The L2FolkInstance corresponding to the last Folk wich one the player talked. */
 	private L2FolkInstance _lastFolkNpc = null;
@@ -5509,4 +5510,5 @@
 				player.setNewbie(rset.getInt("newbie") == 1);
 				player.setNoble(rset.getInt("nobless") == 1);
+				player.setDonator((rset.getInt("donator")==1)? true : false);
 				player.setClanJoinExpiryTime(rset.getLong("clan_join_expiry_time"));
 				if (player.getClanJoinExpiryTime() < System.currentTimeMillis())
@@ -5953,5 +5955,6 @@
 			statement.setString(55, getName());
 			statement.setLong(56, getDeathPenaltyBuffLevel());
-			statement.setInt(57, getObjectId());
+			statement.setInt(57, isDonator() ? 1 : 0);
+			statement.setInt(58, getObjectId());
 			statement.execute();
 			statement.close();
@@ -10236,3 +10239,13 @@
 		return _floodProtectors;
 	}
+	
+	public boolean isDonator()
+	{
+	      return _isDonator;
+	}
+	      
+	public void setDonator(boolean value)
+	{
+		_isDonator = value;
+	}
 }
Index: /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/handler/DonatorCommandHandler.java
===================================================================
--- /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/handler/DonatorCommandHandler.java (revision 18)
+++ /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/handler/DonatorCommandHandler.java (revision 18)
@@ -0,0 +1,75 @@
+/*
+ * 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 2, 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+package net.ins.gameserver.handler;
+
+import java.util.Map;
+import java.util.logging.Logger;
+
+import javolution.util.FastMap;
+import net.ins.Config;
+
+public class DonatorCommandHandler
+{
+	private static Logger _log = Logger.getLogger(ItemHandler.class.getName());
+	private static DonatorCommandHandler _instance;
+	private Map<String, IDonatorCommandHandler> _datatable;
+
+	public static DonatorCommandHandler getInstance()
+	{
+		if (_instance == null)
+			_instance = new DonatorCommandHandler();
+		return _instance;
+	}
+
+	private DonatorCommandHandler()
+	{
+		_datatable = new FastMap<String, IDonatorCommandHandler>();
+
+		_log.config("DonatorCommandHandler: Loaded " + _datatable.size() + " handlers.");
+	}
+
+	public void registerDonatorCommandHandler(IDonatorCommandHandler handler)
+	{
+		String[] ids = handler.getDonatorCommandList();
+		for (int i = 0; i < ids.length; i++)
+		{
+			if (Config.DEBUG)
+				_log.fine("Adding handler for command " + ids[i]);
+			_datatable.put(ids[i], handler);
+		}
+	}
+
+	public IDonatorCommandHandler getDonatorCommandHandler(String DonatorCommand)
+	{
+		String command = DonatorCommand;
+		if (DonatorCommand.indexOf(" ") != -1)
+			command = DonatorCommand.substring(0, DonatorCommand.indexOf(" "));
+		if (Config.DEBUG)
+			_log.fine("getting handler for command: " + command + " -> " + (_datatable.get(command) != null));
+		return _datatable.get(command);
+	}
+
+	/**
+	 * @return
+	 */
+	public int size()
+	{
+		return _datatable.size();
+	}
+}
Index: /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/handler/IDonatorCommandHandler.java
===================================================================
--- /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/handler/IDonatorCommandHandler.java (revision 18)
+++ /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/handler/IDonatorCommandHandler.java (revision 18)
@@ -0,0 +1,45 @@
+/*
+ * 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 2, 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+package net.ins.gameserver.handler;
+
+import net.ins.gameserver.model.actor.instance.L2PcInstance;
+
+/**
+ * This class ...
+ * 
+ * @version $Revision: 1.1.4.2 $ $Date: 2005/03/27 15:30:09 $
+ */
+public interface IDonatorCommandHandler
+{
+	/**
+	 * this is the worker method that is called when someone uses an admin command.
+	 * 
+	 * @param activeChar
+	 * @param command
+	 * @return command success
+	 */
+	public boolean useDonatorCommand(String command, L2PcInstance activeChar, String target);
+
+	/**
+	 * this method is called at initialization to register all the item ids automatically
+	 * 
+	 * @return all known itemIds
+	 */
+	public String[] getDonatorCommandList();
+}
Index: /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/handler/chathandlers/ChatAll.java
===================================================================
--- /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/handler/chathandlers/ChatAll.java (revision 2)
+++ /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/handler/chathandlers/ChatAll.java (revision 18)
@@ -19,5 +19,7 @@
 
 import net.ins.Config;
+import net.ins.gameserver.handler.DonatorCommandHandler;
 import net.ins.gameserver.handler.IChatHandler;
+import net.ins.gameserver.handler.IDonatorCommandHandler;
 import net.ins.gameserver.handler.IVoicedCommandHandler;
 import net.ins.gameserver.handler.VoicedCommandHandler;
@@ -44,4 +46,5 @@
 	{
 		boolean vcd_used = false;
+		boolean dcd_used = false;
 		if (text.startsWith("."))
 		{
@@ -79,5 +82,43 @@
 			}
 		}
-		if (!vcd_used)
+		else if (text.startsWith("-"))
+		{
+			StringTokenizer st = new StringTokenizer(text);
+			IDonatorCommandHandler dch;
+			String command = "";
+			if (activeChar.isDonator())
+			{
+				if (st.countTokens() > 1)
+				{
+					command = st.nextToken().substring(1);
+					target = text.substring(command.length() + 2);
+					dch = DonatorCommandHandler.getInstance().getDonatorCommandHandler(command);
+				}
+				else
+				{
+					command = text.substring(1);
+					if (Config.DEBUG)
+						_log.info("Command: " + command);
+					dch = DonatorCommandHandler.getInstance().getDonatorCommandHandler(command);
+				}
+				if (!activeChar.getFloodProtectors().getVoicedCommands().tryPerformAction("voiced command ." + command))
+				{
+					activeChar.sendMessage("Do not spam voiced commands.");
+					return;
+				}
+				if (dch != null)
+				{
+					dch.useDonatorCommand(command, activeChar, target);
+					dcd_used = true;
+				}
+				else
+				{
+					if (Config.DEBUG)
+						_log.warning("No handler registered for bypass '" + command + "'");
+					dcd_used = false;
+				}
+			}
+		}
+		if (!vcd_used || !dcd_used)
 		{
 			CreatureSay cs = new CreatureSay(activeChar.getObjectId(), type, activeChar.getAppearance().getVisibleName(), text);
Index: /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/handler/AdminCommandHandler.java
===================================================================
--- /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/handler/AdminCommandHandler.java (revision 2)
+++ /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/handler/AdminCommandHandler.java (revision 18)
@@ -33,4 +33,5 @@
 import net.ins.gameserver.handler.admincommandhandlers.AdminCursedWeapons;
 import net.ins.gameserver.handler.admincommandhandlers.AdminDelete;
+import net.ins.gameserver.handler.admincommandhandlers.AdminDonator;
 import net.ins.gameserver.handler.admincommandhandlers.AdminDoorControl;
 import net.ins.gameserver.handler.admincommandhandlers.AdminEditChar;
@@ -94,4 +95,5 @@
 		_datatable = new FastMap<String, IAdminCommandHandler>();
 		registerAdminCommandHandler(new AdminAdmin());
+		registerAdminCommandHandler(new AdminDonator());
 		registerAdminCommandHandler(new AdminInvul());
 		registerAdminCommandHandler(new AdminDelete());
Index: /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/handler/admincommandhandlers/AdminDonator.java
===================================================================
--- /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/handler/admincommandhandlers/AdminDonator.java (revision 18)
+++ /trunk/Interlude_C6_GameServer/java/net/ins/gameserver/handler/admincommandhandlers/AdminDonator.java (revision 18)
@@ -0,0 +1,152 @@
+/*
+ * 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 2, 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+package net.ins.gameserver.handler.admincommandhandlers;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import net.ins.L2DatabaseFactory;
+import net.ins.gameserver.Announcements;
+import net.ins.gameserver.datatables.GmListTable;
+import net.ins.gameserver.handler.IAdminCommandHandler;
+import net.ins.gameserver.model.L2Object;
+import net.ins.gameserver.model.actor.instance.L2PcInstance;
+import net.ins.gameserver.network.SystemMessageId;
+import net.ins.gameserver.network.serverpackets.SystemMessage;
+
+/**
+ *
+ * Author Rayan
+ *
+ */
+public class AdminDonator implements IAdminCommandHandler
+{
+	private static String[] _adminCommands =
+	{
+		"admin_setdonator",};
+	private final static Logger _log = Logger.getLogger(AdminDonator.class.getName());
+
+	public boolean useAdminCommand(String command, L2PcInstance activeChar)
+	{
+		if (command.startsWith("admin_setdonator"))
+		{
+			L2Object target = activeChar.getTarget();
+			L2PcInstance player = null;
+			SystemMessage sm = new SystemMessage(SystemMessageId.S1_S2);
+			if (target instanceof L2PcInstance)
+				player = (L2PcInstance)target;
+			else
+				player = activeChar;
+			
+			if (player.isDonator())
+			{
+				player.setDonator(false);
+				sm.addString("You are no longer a server donator.");
+				GmListTable.broadcastMessageToGMs("GM "+activeChar.getName()+" removed donator stat of player"+ target.getName());
+				Connection connection = null;
+				try
+				{
+					connection = L2DatabaseFactory.getInstance().getConnection();
+
+					PreparedStatement statement = connection.prepareStatement("SELECT obj_id FROM characters where char_name=?");
+					statement.setString(1,target.getName());
+					ResultSet rset = statement.executeQuery();
+					int objId = 0;
+					if (rset.next())
+						objId = rset.getInt(1);
+					rset.close();
+					statement.close();
+
+					if (objId == 0) 
+					{
+						connection.close(); 
+						return false;
+					}
+
+					statement = connection.prepareStatement("UPDATE characters SET donator=0 WHERE obj_id=?");
+					statement.setInt(1, objId);
+					statement.execute();
+					statement.close();
+					connection.close();
+				}
+				catch (Exception e)
+				{
+					_log.log(Level.WARNING,"could not set donator stats of char:", e);
+				}
+				finally
+				{
+					L2DatabaseFactory.close(connection);
+				}
+			}
+			else
+			{
+				player.setDonator(true);
+				sm.addString("You are now a server donator, congratulations!");
+				GmListTable.broadcastMessageToGMs("GM "+activeChar.getName()+" has given donator stat for player "+target.getName()+".");
+				Connection connection = null;
+				try
+				{
+					connection = L2DatabaseFactory.getInstance().getConnection();
+
+					PreparedStatement statement = connection.prepareStatement("SELECT obj_id FROM characters where char_name=?");
+					statement.setString(1,target.getName());
+					ResultSet rset = statement.executeQuery();
+					int objId = 0;
+					if (rset.next())
+						objId = rset.getInt(1);
+					rset.close();
+					statement.close();
+
+					if (objId == 0) 
+					{
+						connection.close(); 
+						return false;
+					}
+
+					statement = connection.prepareStatement("UPDATE characters SET donator=1 WHERE obj_id=?");
+					statement.setInt(1, objId);
+					statement.execute();
+					statement.close();
+					connection.close();
+				}
+				catch (Exception e)
+				{
+					_log.log(Level.WARNING,"could not set donator stats of char:", e);
+				}
+				finally
+				{
+					L2DatabaseFactory.close(connection);
+				}
+
+			}
+			player.sendPacket(sm);
+			player.broadcastUserInfo();
+			if(player.isDonator() == true)
+				Announcements.getInstance().announceToAll(player.getName() + " Has Become a Server Donator!");
+		}
+		return false;
+	}
+   public String[] getAdminCommandList()
+   {
+		return _adminCommands;
+   }
+}
gostaria de um passo a passo ai gente !!
acho q ajudaria mt gente =)

pensei em criar um arkivo d texto e add como patch ..
eh assim??
Obrigado!

Meu original eh assim !!!

Código: [Somente Usuários Registrados Podem Visualizar os Links Desta PáginaClique aqui para se Registrar]
/*
 * 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.l2jserver.gameserver.model.actor.instance;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;

import javolution.util.FastList;
import javolution.util.FastMap;

import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.Announcements;
import com.l2jserver.gameserver.GameTimeController;
import com.l2jserver.gameserver.GeoData;
import com.l2jserver.gameserver.GmListTable;
import com.l2jserver.gameserver.ItemsAutoDestroy;
import com.l2jserver.gameserver.LoginServerThread;
import com.l2jserver.gameserver.RecipeController;
import com.l2jserver.gameserver.SevenSigns;
import com.l2jserver.gameserver.SevenSignsFestival;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.Universe;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.ai.L2CharacterAI;
import com.l2jserver.gameserver.ai.L2PlayerAI;
import com.l2jserver.gameserver.ai.L2SummonAI;
import com.l2jserver.gameserver.cache.HtmCache;
import com.l2jserver.gameserver.cache.WarehouseCacheManager;
import com.l2jserver.gameserver.communitybbs.BB.Forum;
import com.l2jserver.gameserver.communitybbs.Manager.ForumsBBSManager;
import com.l2jserver.gameserver.communitybbs.Manager.RegionBBSManager;
import com.l2jserver.gameserver.datatables.AccessLevels;
import com.l2jserver.gameserver.datatables.AdminCommandAccessRights;
import com.l2jserver.gameserver.datatables.CharNameTable;
import com.l2jserver.gameserver.datatables.CharTemplateTable;
import com.l2jserver.gameserver.datatables.ClanTable;
import com.l2jserver.gameserver.datatables.FishTable;
import com.l2jserver.gameserver.datatables.HennaTable;
import com.l2jserver.gameserver.datatables.HeroSkillTable;
import com.l2jserver.gameserver.datatables.ItemTable;
import com.l2jserver.gameserver.datatables.MapRegionTable;
import com.l2jserver.gameserver.datatables.NobleSkillTable;
import com.l2jserver.gameserver.datatables.NpcTable;
import com.l2jserver.gameserver.datatables.PetDataTable;
import com.l2jserver.gameserver.datatables.SkillTable;
import com.l2jserver.gameserver.datatables.SkillTreeTable;
import com.l2jserver.gameserver.handler.AdminCommandHandler;
import com.l2jserver.gameserver.handler.IAdminCommandHandler;
import com.l2jserver.gameserver.handler.IItemHandler;
import com.l2jserver.gameserver.handler.ItemHandler;
import com.l2jserver.gameserver.instancemanager.AntiFeedManager;
import com.l2jserver.gameserver.instancemanager.CastleManager;
import com.l2jserver.gameserver.instancemanager.CoupleManager;
import com.l2jserver.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jserver.gameserver.instancemanager.DimensionalRiftManager;
import com.l2jserver.gameserver.instancemanager.DuelManager;
import com.l2jserver.gameserver.instancemanager.FortManager;
import com.l2jserver.gameserver.instancemanager.FortSiegeManager;
import com.l2jserver.gameserver.instancemanager.InstanceManager;
import com.l2jserver.gameserver.instancemanager.ItemsOnGroundManager;
import com.l2jserver.gameserver.instancemanager.QuestManager;
import com.l2jserver.gameserver.instancemanager.SiegeManager;
import com.l2jserver.gameserver.model.BlockList;
import com.l2jserver.gameserver.model.Elementals;
import com.l2jserver.gameserver.model.FishData;
import com.l2jserver.gameserver.model.L2AccessLevel;
import com.l2jserver.gameserver.model.L2CharPosition;
import com.l2jserver.gameserver.model.L2Clan;
import com.l2jserver.gameserver.model.L2ClanMember;
import com.l2jserver.gameserver.model.L2Effect;
import com.l2jserver.gameserver.model.L2EnchantSkillLearn;
import com.l2jserver.gameserver.model.L2Fishing;
import com.l2jserver.gameserver.model.L2HennaInstance;
import com.l2jserver.gameserver.model.L2ItemInstance;
import com.l2jserver.gameserver.model.L2Macro;
import com.l2jserver.gameserver.model.L2ManufactureItem;
import com.l2jserver.gameserver.model.L2ManufactureList;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Party;
import com.l2jserver.gameserver.model.L2PetData;
import com.l2jserver.gameserver.model.L2Radar;
import com.l2jserver.gameserver.model.L2RecipeList;
import com.l2jserver.gameserver.model.L2Request;
import com.l2jserver.gameserver.model.L2ShortCut;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.L2SkillLearn;
import com.l2jserver.gameserver.model.L2Transformation;
import com.l2jserver.gameserver.model.L2World;
import com.l2jserver.gameserver.model.L2WorldRegion;
import com.l2jserver.gameserver.model.MacroList;
import com.l2jserver.gameserver.model.ShortCuts;
import com.l2jserver.gameserver.model.TradeList;
import com.l2jserver.gameserver.model.L2Skill.SkillTargetType;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Decoy;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.L2Playable;
import com.l2jserver.gameserver.model.actor.L2Summon;
import com.l2jserver.gameserver.model.actor.L2Trap;
import com.l2jserver.gameserver.model.actor.appearance.PcAppearance;
import com.l2jserver.gameserver.model.actor.knownlist.PcKnownList;
import com.l2jserver.gameserver.model.actor.position.PcPosition;
import com.l2jserver.gameserver.model.actor.stat.PcStat;
import com.l2jserver.gameserver.model.actor.status.PcStatus;
import com.l2jserver.gameserver.model.base.ClassId;
import com.l2jserver.gameserver.model.base.ClassLevel;
import com.l2jserver.gameserver.model.base.Experience;
import com.l2jserver.gameserver.model.base.PlayerClass;
import com.l2jserver.gameserver.model.base.Race;
import com.l2jserver.gameserver.model.base.SubClass;
import com.l2jserver.gameserver.model.entity.Castle;
import com.l2jserver.gameserver.model.entity.Duel;
import com.l2jserver.gameserver.model.entity.Fort;
import com.l2jserver.gameserver.model.entity.Instance;
import com.l2jserver.gameserver.model.entity.L2Event;
import com.l2jserver.gameserver.model.entity.Siege;
import com.l2jserver.gameserver.model.entity.TvTEvent;
import com.l2jserver.gameserver.model.itemcontainer.Inventory;
import com.l2jserver.gameserver.model.itemcontainer.ItemContainer;
import com.l2jserver.gameserver.model.itemcontainer.PcInventory;
import com.l2jserver.gameserver.model.itemcontainer.PcRefund;
import com.l2jserver.gameserver.model.itemcontainer.PcWarehouse;
import com.l2jserver.gameserver.model.itemcontainer.PetInventory;
import com.l2jserver.gameserver.model.olympiad.Olympiad;
import com.l2jserver.gameserver.model.quest.Quest;
import com.l2jserver.gameserver.model.quest.QuestState;
import com.l2jserver.gameserver.model.quest.State;
import com.l2jserver.gameserver.network.L2GameClient;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.communityserver.CommunityServerThread;
import com.l2jserver.gameserver.network.communityserver.writepackets.WorldInfo;
import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
import com.l2jserver.gameserver.network.serverpackets.ChangeWaitType;
import com.l2jserver.gameserver.network.serverpackets.CharInfo;
import com.l2jserver.gameserver.network.serverpackets.ConfirmDlg;
import com.l2jserver.gameserver.network.serverpackets.EtcStatusUpdate;
import com.l2jserver.gameserver.network.serverpackets.ExAutoSoulShot;
import com.l2jserver.gameserver.network.serverpackets.ExBrExtraUserInfo;
import com.l2jserver.gameserver.network.serverpackets.ExDuelUpdateUserInfo;
import com.l2jserver.gameserver.network.serverpackets.ExFishingEnd;
import com.l2jserver.gameserver.network.serverpackets.ExFishingStart;
import com.l2jserver.gameserver.network.serverpackets.ExGetBookMarkInfoPacket;
import com.l2jserver.gameserver.network.serverpackets.ExGetOnAirShip;
import com.l2jserver.gameserver.network.serverpackets.ExOlympiadMode;
import com.l2jserver.gameserver.network.serverpackets.ExOlympiadUserInfo;
import com.l2jserver.gameserver.network.serverpackets.ExPrivateStoreSetWholeMsg;
import com.l2jserver.gameserver.network.serverpackets.ExSetCompassZoneCode;
import com.l2jserver.gameserver.network.serverpackets.ExSpawnEmitter;
import com.l2jserver.gameserver.network.serverpackets.ExStartScenePlayer;
import com.l2jserver.gameserver.network.serverpackets.ExStorageMaxCount;
import com.l2jserver.gameserver.network.serverpackets.ExVitalityPointInfo;
import com.l2jserver.gameserver.network.serverpackets.FriendStatusPacket;
import com.l2jserver.gameserver.network.serverpackets.GMHide;
import com.l2jserver.gameserver.network.serverpackets.GameGuardQuery;
import com.l2jserver.gameserver.network.serverpackets.GetOnVehicle;
import com.l2jserver.gameserver.network.serverpackets.HennaInfo;
import com.l2jserver.gameserver.network.serverpackets.InventoryUpdate;
import com.l2jserver.gameserver.network.serverpackets.ItemList;
import com.l2jserver.gameserver.network.serverpackets.L2GameServerPacket;
import com.l2jserver.gameserver.network.serverpackets.LeaveWorld;
import com.l2jserver.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jserver.gameserver.network.serverpackets.MyTargetSelected;
import com.l2jserver.gameserver.network.serverpackets.NicknameChanged;
import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
import com.l2jserver.gameserver.network.serverpackets.ObservationMode;
import com.l2jserver.gameserver.network.serverpackets.ObservationReturn;
import com.l2jserver.gameserver.network.serverpackets.PartySmallWindowUpdate;
import com.l2jserver.gameserver.network.serverpackets.PetInventoryUpdate;
import com.l2jserver.gameserver.network.serverpackets.PledgeShowMemberListDelete;
import com.l2jserver.gameserver.network.serverpackets.PledgeShowMemberListUpdate;
import com.l2jserver.gameserver.network.serverpackets.PrivateStoreListBuy;
import com.l2jserver.gameserver.network.serverpackets.PrivateStoreListSell;
import com.l2jserver.gameserver.network.serverpackets.PrivateStoreManageListBuy;
import com.l2jserver.gameserver.network.serverpackets.PrivateStoreManageListSell;
import com.l2jserver.gameserver.network.serverpackets.PrivateStoreMsgBuy;
import com.l2jserver.gameserver.network.serverpackets.PrivateStoreMsgSell;
import com.l2jserver.gameserver.network.serverpackets.QuestList;
import com.l2jserver.gameserver.network.serverpackets.RecipeShopMsg;
import com.l2jserver.gameserver.network.serverpackets.RecipeShopSellList;
import com.l2jserver.gameserver.network.serverpackets.RelationChanged;
import com.l2jserver.gameserver.network.serverpackets.Ride;
import com.l2jserver.gameserver.network.serverpackets.ServerClose;
import com.l2jserver.gameserver.network.serverpackets.SetupGauge;
import com.l2jserver.gameserver.network.serverpackets.ShortBuffStatusUpdate;
import com.l2jserver.gameserver.network.serverpackets.ShortCutInit;
import com.l2jserver.gameserver.network.serverpackets.SkillCoolTime;
import com.l2jserver.gameserver.network.serverpackets.SkillList;
import com.l2jserver.gameserver.network.serverpackets.Snoop;
import com.l2jserver.gameserver.network.serverpackets.SocialAction;
import com.l2jserver.gameserver.network.serverpackets.StatusUpdate;
import com.l2jserver.gameserver.network.serverpackets.StopMove;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
import com.l2jserver.gameserver.network.serverpackets.TargetSelected;
import com.l2jserver.gameserver.network.serverpackets.TargetUnselected;
import com.l2jserver.gameserver.network.serverpackets.TradeDone;
import com.l2jserver.gameserver.network.serverpackets.TradeOtherDone;
import com.l2jserver.gameserver.network.serverpackets.TradeStart;
import com.l2jserver.gameserver.network.serverpackets.UserInfo;
import com.l2jserver.gameserver.network.serverpackets.ValidateLocation;
import com.l2jserver.gameserver.skills.Formulas;
import com.l2jserver.gameserver.skills.Stats;
import com.l2jserver.gameserver.skills.l2skills.L2SkillSiegeFlag;
import com.l2jserver.gameserver.skills.l2skills.L2SkillSummon;
import com.l2jserver.gameserver.skills.l2skills.L2SkillTrap;
import com.l2jserver.gameserver.taskmanager.AttackStanceTaskManager;
import com.l2jserver.gameserver.templates.chars.L2PcTemplate;
import com.l2jserver.gameserver.templates.item.L2Armor;
import com.l2jserver.gameserver.templates.item.L2ArmorType;
import com.l2jserver.gameserver.templates.item.L2EtcItemType;
import com.l2jserver.gameserver.templates.item.L2Henna;
import com.l2jserver.gameserver.templates.item.L2Item;
import com.l2jserver.gameserver.templates.item.L2Weapon;
import com.l2jserver.gameserver.templates.item.L2WeaponType;
import com.l2jserver.gameserver.templates.skills.L2EffectType;
import com.l2jserver.gameserver.templates.skills.L2SkillType;
import com.l2jserver.gameserver.util.FloodProtectors;
import com.l2jserver.gameserver.util.Util;
import com.l2jserver.util.Point3D;
import com.l2jserver.util.Rnd;

/**
 * This class represents all player characters in the world.
 * There is always a client-thread connected to this (except if a player-store is activated upon logout).<BR><BR>
 *
 * @version $Revision: 1.66.2.41.2.33 $ $Date: 2005/04/11 10:06:09 $
 */
public final class L2PcInstance extends L2Playable
{
    // Character Skill SQL String Definitions:
	private static final String RESTORE_SKILLS_FOR_CHAR = "SELECT skill_id,skill_level FROM character_skills WHERE charId=? AND class_index=?";
	private static final String ADD_NEW_SKILL = "INSERT INTO character_skills (charId,skill_id,skill_level,class_index) VALUES (?,?,?,?)";
	private static final String UPDATE_CHARACTER_SKILL_LEVEL = "UPDATE character_skills SET skill_level=? WHERE skill_id=? AND charId=? AND class_index=?";
	private static final String DELETE_SKILL_FROM_CHAR = "DELETE FROM character_skills WHERE skill_id=? AND charId=? AND class_index=?";
	private static final String DELETE_CHAR_SKILLS = "DELETE FROM character_skills WHERE charId=? AND class_index=?";

	// Character Skill Save SQL String Definitions:
	private static final String ADD_SKILL_SAVE = "INSERT INTO character_skills_save (charId,skill_id,skill_level,effect_count,effect_cur_time,reuse_delay,systime,restore_type,class_index,buff_index) VALUES (?,?,?,?,?,?,?,?,?,?)";
	private static final String RESTORE_SKILL_SAVE = "SELECT skill_id,skill_level,effect_count,effect_cur_time, reuse_delay, systime FROM character_skills_save WHERE charId=? AND class_index=? AND restore_type=? ORDER BY buff_index ASC";
	private static final String DELETE_SKILL_SAVE = "DELETE FROM character_skills_save WHERE charId=? AND class_index=?";

	// Character Character SQL String Definitions:
    private static final String INSERT_CHARACTER = "INSERT INTO characters (account_name,charId,char_name,level,maxHp,curHp,maxCp,curCp,maxMp,curMp,face,hairStyle,hairColor,sex,exp,sp,karma,fame,pvpkills,pkkills,clanid,race,classid,deletetime,cancraft,title,title_color,accesslevel,online,isin7sdungeon,clan_privs,wantspeace,base_class,newbie,nobless,power_grade,last_recom_date,createTime) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
	private static final String UPDATE_CHARACTER = "UPDATE characters SET level=?,maxHp=?,curHp=?,maxCp=?,curCp=?,maxMp=?,curMp=?,face=?,hairStyle=?,hairColor=?,sex=?,heading=?,x=?,y=?,z=?,exp=?,expBeforeDeath=?,sp=?,karma=?,fame=?,pvpkills=?,pkkills=?,rec_have=?,rec_left=?,clanid=?,race=?,classid=?,deletetime=?,title=?,title_color=?,accesslevel=?,online=?,isin7sdungeon=?,clan_privs=?,wantspeace=?,base_class=?,onlinetime=?,punish_level=?,punish_timer=?,newbie=?,nobless=?,power_grade=?,subpledge=?,last_recom_date=?,lvl_joined_academy=?,apprentice=?,sponsor=?,varka_ketra_ally=?,clan_join_expiry_time=?,clan_create_expiry_time=?,char_name=?,death_penalty_level=?,bookmarkslot=?,vitality_points=? WHERE charId=?";
    private static final String RESTORE_CHARACTER = "SELECT account_name, charId, char_name, level, maxHp, curHp, maxCp, curCp, maxMp, curMp, face, hairStyle, hairColor, sex, heading, x, y, z, exp, expBeforeDeath, sp, karma, fame, pvpkills, pkkills, clanid, race, classid, deletetime, cancraft, title, title_color, rec_have, rec_left, accesslevel, online, char_slot, lastAccess, clan_privs, wantspeace, base_class, onlinetime, isin7sdungeon, punish_level, punish_timer, newbie, nobless, power_grade, subpledge, last_recom_date, lvl_joined_academy, apprentice, sponsor, varka_ketra_ally,clan_join_expiry_time,clan_create_expiry_time,death_penalty_level,bookmarkslot,vitality_points,createTime FROM characters WHERE charId=?";

    // Character Teleport Bookmark:
    private static final String INSERT_TP_BOOKMARK = "INSERT INTO character_tpbookmark (charId,Id,x,y,z,icon,tag,name) values (?,?,?,?,?,?,?,?)";
    private static final String UPDATE_TP_BOOKMARK = "UPDATE character_tpbookmark SET icon=?,tag=?,name=? where charId=? AND Id=?";	
    private static final String RESTORE_TP_BOOKMARK = "SELECT Id,x,y,z,icon,tag,name FROM character_tpbookmark WHERE charId=?";	
    private static final String DELETE_TP_BOOKMARK = "DELETE FROM character_tpbookmark WHERE charId=? AND Id=?";
    
    
    // Character Subclass SQL String Definitions:
    private static final String RESTORE_CHAR_SUBCLASSES = "SELECT class_id,exp,sp,level,class_index FROM character_subclasses WHERE charId=? ORDER BY class_index ASC";
    private static final String ADD_CHAR_SUBCLASS = "INSERT INTO character_subclasses (charId,class_id,exp,sp,level,class_index) VALUES (?,?,?,?,?,?)";
    private static final String UPDATE_CHAR_SUBCLASS = "UPDATE character_subclasses SET exp=?,sp=?,level=?,class_id=? WHERE charId=? AND class_index =?";
    private static final String DELETE_CHAR_SUBCLASS = "DELETE FROM character_subclasses WHERE charId=? AND class_index=?";

    // Character Henna SQL String Definitions:
	private static final String RESTORE_CHAR_HENNAS = "SELECT slot,symbol_id FROM character_hennas WHERE charId=? AND class_index=?";
	private static final String ADD_CHAR_HENNA = "INSERT INTO character_hennas (charId,symbol_id,slot,class_index) VALUES (?,?,?,?)";
	private static final String DELETE_CHAR_HENNA = "DELETE FROM character_hennas WHERE charId=? AND slot=? AND class_index=?";
	private static final String DELETE_CHAR_HENNAS = "DELETE FROM character_hennas WHERE charId=? AND class_index=?";

	// Character Shortcut SQL String Definitions:
	private static final String DELETE_CHAR_SHORTCUTS = "DELETE FROM character_shortcuts WHERE charId=? AND class_index=?";

	// Character Recommendation SQL String Definitions:
	private static final String RESTORE_CHAR_RECOMS = "SELECT charId,target_id FROM character_recommends WHERE charId=?";
	private static final String ADD_CHAR_RECOM = "INSERT INTO character_recommends (charId,target_id) VALUES (?,?)";
	private static final String DELETE_CHAR_RECOMS = "DELETE FROM character_recommends WHERE charId=?";

	// Character Transformation SQL String Definitions:
	private static final String SELECT_CHAR_TRANSFORM = "SELECT transform_id FROM characters WHERE charId=?";
	private static final String UPDATE_CHAR_TRANSFORM = "UPDATE characters SET transform_id=? WHERE charId=?";

	public static final int REQUEST_TIMEOUT = 15;
	public static final int STORE_PRIVATE_NONE = 0;
	public static final int STORE_PRIVATE_SELL = 1;
	public static final int STORE_PRIVATE_BUY = 3;
	public static final int STORE_PRIVATE_MANUFACTURE = 5;
	public static final int STORE_PRIVATE_PACKAGE_SELL = 8;

	/** The table containing all minimum level needed for each Expertise (None, D, C, B, A, S, S80, S84)*/
    private static final int[] EXPERTISE_LEVELS =
    {
	    SkillTreeTable.getInstance().getExpertiseLevel(0), //NONE
	    SkillTreeTable.getInstance().getExpertiseLevel(1), //D
	    SkillTreeTable.getInstance().getExpertiseLevel(2), //C
	    SkillTreeTable.getInstance().getExpertiseLevel(3), //B
	    SkillTreeTable.getInstance().getExpertiseLevel(4), //A
	    SkillTreeTable.getInstance().getExpertiseLevel(5), //S
	    SkillTreeTable.getInstance().getExpertiseLevel(6), //S80
	    SkillTreeTable.getInstance().getExpertiseLevel(7)  //S84
    };

	private static final int[] COMMON_CRAFT_LEVELS = { 5, 20, 28, 36, 43, 49, 55, 62 };
	
	public class AIAccessor extends L2Character.AIAccessor
	{
		protected AIAccessor()
		{
			
		}
		
		public L2PcInstance getPlayer()
		{
			return L2PcInstance.this;
		}
		
		public void doPickupItem(L2Object object)
		{
			L2PcInstance.this.doPickupItem(object);
		}
		
		public void doInteract(L2Character target)
		{
			L2PcInstance.this.doInteract(target);
		}
		
		@Override
		public void doAttack(L2Character target)
		{
			super.doAttack(target);
			
			// cancel the recent fake-death protection instantly if the player attacks or casts spells
			getPlayer().setRecentFakeDeath(false);
		}
		
		@Override
		public void doCast(L2Skill skill)
		{
			super.doCast(skill);
			
			// cancel the recent fake-death protection instantly if the player attacks or casts spells
			getPlayer().setRecentFakeDeath(false);
		}
	}

	private L2GameClient _client;

	private String _accountName;
	private long _deleteTimer;
	private long _creationTime; 

	private boolean _isOnline = false;
	private long _onlineTime;
	private long _onlineBeginTime;
	private long _lastAccess;
	private long _uptime;

	private final ReentrantLock _subclassLock = new ReentrantLock();
	protected int _baseClass;
	protected int _activeClass;
	protected int _classIndex = 0;
	
	/** data for mounted pets */
	private int _controlItemId;
	private L2PetData _data;
	private int _curFeed;
	protected Future<?> _mountFeedTask;
	private ScheduledFuture<?> _dismountTask;
	
	/** The list of sub-classes this character has. */
    private Map<Integer, SubClass> _subClasses;
    
	private PcAppearance _appearance;

	/** The Identifier of the L2PcInstance */
	private int _charId = 0x00030b7a;

	/** The Experience of the L2PcInstance before the last Death Penalty */
	private long _expBeforeDeath;

	/** The Karma of the L2PcInstance (if higher than 0, the name of the L2PcInstance appears in red) */
	private int _karma;

	/** The number of player killed during a PvP (the player killed was PvP Flagged) */
	private int _pvpKills;

	/** The PK counter of the L2PcInstance (= Number of non PvP Flagged player killed) */
	private int _pkKills;

	/** The PvP Flag state of the L2PcInstance (0=White, 1=Purple) */
	private byte _pvpFlag;
	
	/** The Fame of this L2PcInstance */
	private int _fame;
	private ScheduledFuture<?> _fameTask;

	/** Vitality recovery task */
	private ScheduledFuture<?> _vitalityTask;

	private ScheduledFuture<?> _teleportWatchdog;

	/** The Siege state of the L2PcInstance */
	private byte _siegeState = 0;

	/** The id of castle/fort which the L2PcInstance is registered for siege */
	private int _siegeSide = 0;

	private int _curWeightPenalty = 0;

	private int _lastCompassZone; // the last compass zone update send to the client

	private boolean _isIn7sDungeon = false;
	
	public int _bookmarkslot = 0; // The Teleport Bookmark Slot
	
	public FastList<TeleportBookmark> tpbookmark = new FastList<TeleportBookmark>();
	
	private final FloodProtectors _floodProtectors = new FloodProtectors(this);

    private PunishLevel _punishLevel = PunishLevel.NONE;
	private long _punishTimer = 0;
	private ScheduledFuture<?> _punishTask;
    
    public enum PunishLevel
	{
		NONE(0, ""),
		CHAT(1, "chat banned"),
		JAIL(2, "jailed"),
		CHAR(3, "banned"),
		ACC(4, "banned");
		
		private final int punValue;
		private final String punString;
		
		PunishLevel(int value, String string)
		{
			punValue = value;
			punString = string;
		}
		
		public int value()
		{
			return punValue;
		}
		
		public String string()
		{
			return punString;
		}
	}
	
	/** Olympiad */
	private boolean _inOlympiadMode = false;
	private boolean _OlympiadStart = false;
	private int _olympiadGameId = -1;
	private int _olympiadSide = -1;
	public int olyBuff = 0;

    /** Duel */
    private boolean _isInDuel = false;
    private int _duelState = Duel.DUELSTATE_NODUEL;
    private int _duelId = 0;
    private SystemMessageId _noDuelReason = SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL;

	/** Boat */
	private boolean _inBoat;
    private L2BoatInstance _boat;
    private Point3D _inBoatPosition;
    
    /** AirShip */
    private L2AirShipInstance _airShip;
	private boolean _inAirShip;
	private Point3D _inAirShipPosition;

	public ScheduledFuture<?> _taskforfish;
	private int _mountType;
    private int _mountNpcId;
    private int _mountLevel;
    /** Store object used to summon the strider you are mounting **/
	private int _mountObjectID = 0;

	public int _telemode = 0;

	public boolean _exploring = false;
	
	private boolean _inCrystallize;
	private boolean _inCraftMode;
    
    private L2Transformation _transformation;
    
    private int _transformationId = 0;

	/** The table containing all L2RecipeList of the L2PcInstance */
	private Map<Integer, L2RecipeList> _dwarvenRecipeBook = new FastMap<Integer, L2RecipeList>();
	private Map<Integer, L2RecipeList> _commonRecipeBook = new FastMap<Integer, L2RecipeList>();

		/** True if the L2PcInstance is sitting */
	private boolean _waitTypeSitting;

	/** True if the L2PcInstance is using the relax skill */
	private boolean _relax;

	/** Location before entering Observer Mode */
	private int _obsX;
	private int _obsY;
	private int _obsZ;
	private boolean _observerMode = false;

	/** Stored from last ValidatePosition **/
	private Point3D _lastServerPosition = new Point3D(0, 0, 0);

	/** Previous coordinate sent to party in ValidatePosition **/
	private Point3D _lastPartyPosition = new Point3D(0, 0, 0);
	
	/** The number of recommendation obtained by the L2PcInstance */
	private int _recomHave; // how much I was recommended by others

	/** The number of recommendation that the L2PcInstance can give */
	private int _recomLeft; // how many recommendations I can give to others

	/** Date when recommendation points were updated last time */
	private long _lastRecomUpdate;
	/** List with the recommendations that I've give */
	private List<Integer> _recomChars = new FastList<Integer>();

	/** The random number of the L2PcInstance */
	//private static final Random _rnd = new Random();

	private PcInventory _inventory = new PcInventory(this);
	private PcWarehouse _warehouse;
	private PcRefund _refund;

	/** The Private Store type of the L2PcInstance (STORE_PRIVATE_NONE=0, STORE_PRIVATE_SELL=1, sellmanage=2, STORE_PRIVATE_BUY=3, buymanage=4, STORE_PRIVATE_MANUFACTURE=5) */
	private int _privatestore;

	private TradeList _activeTradeList;
	private ItemContainer _activeWarehouse;
	private L2ManufactureList _createList;
	private TradeList _sellList;
	private TradeList _buyList;

	/** Bitmask used to keep track of one-time/newbie quest rewards*/
	private int _newbie;

	private boolean _noble = false;
	private boolean _hero = false;

	/** The L2FolkInstance corresponding to the last Folk wich one the player talked. */
	private L2Npc _lastFolkNpc = null;

	/** Last NPC Id talked on a quest */
	private int _questNpcObject = 0;

	/** The table containing all Quests began by the L2PcInstance */
	private Map<String, QuestState> _quests = new FastMap<String, QuestState>();

	/** The list containing all shortCuts of this L2PcInstance */
	private ShortCuts _shortCuts = new ShortCuts(this);

	/** The list containing all macroses of this L2PcInstance */
	private MacroList _macroses = new MacroList(this);

	private List<L2PcInstance> _snoopListener = new FastList<L2PcInstance>();
	private List<L2PcInstance> _snoopedPlayer = new FastList<L2PcInstance>();

	private ClassId _skillLearningClassId;

	// hennas
	private final L2HennaInstance[] _henna = new L2HennaInstance[3];
	private int _hennaSTR;
	private int _hennaINT;
	private int _hennaDEX;
	private int _hennaMEN;
	private int _hennaWIT;
	private int _hennaCON;

	/** The L2Summon of the L2PcInstance */
	private L2Summon _summon = null;
	/** The L2Decoy of the L2PcInstance */
	private L2Decoy _decoy = null;
	/** The L2Trap of the L2PcInstance */
	private L2Trap _trap = null;
	/** The L2Agathion of the L2PcInstance */
	private int _agathionId = 0;
	// apparently, a L2PcInstance CAN have both a summon AND a tamed beast at the same time!!
	private L2TamedBeastInstance _tamedBeast = null;

	// client radar
	//TODO: This needs to be better intergrated and saved/loaded
	private L2Radar _radar;

	// these values are only stored temporarily
	private boolean _partyMatchingAutomaticRegistration;
	private boolean _partyMatchingShowLevel;
	private boolean _partyMatchingShowClass;
	private String _partyMatchingMemo;

	// Clan related attributes
	/** The Clan Identifier of the L2PcInstance */
	private int _clanId;

	/** The Clan object of the L2PcInstance */
	private L2Clan _clan;

	/** Apprentice and Sponsor IDs */
    private int _apprentice = 0;
    private int _sponsor = 0;

	private long _clanJoinExpiryTime;
	private long _clanCreateExpiryTime;

	private int _powerGrade = 0;
	private int _clanPrivileges = 0;

    /** L2PcInstance's pledge class (knight, Baron, etc.)*/
    private int _pledgeClass = 0;
    private int _pledgeType = 0;

    /** Level at which the player joined the clan as an academy member*/
    private int _lvlJoinedAcademy = 0;

	private int _wantsPeace = 0;

	//Death Penalty Buff Level
	private int _deathPenaltyBuffLevel = 0;
	
	// self resurrect during siege
	private boolean _charmOfCourage = false;

	// charges
	private AtomicInteger _charges = new AtomicInteger();
	private ScheduledFuture<?> _chargeTask = null;
	
	// Absorbed Souls
    private int _souls = 0;
    private ScheduledFuture<?> _soulTask = null;

    // WorldPosition used by TARGET_SIGNET_GROUND
    private Point3D _currentSkillWorldPosition;
    
    private L2AccessLevel _accessLevel;

	private boolean _messageRefusal = false;    // message refusal mode
	
	private boolean _silenceMode = false;     // silence mode
	private boolean _dietMode = false;          // ignore weight penalty
	private boolean _tradeRefusal = false;       // Trade refusal
	private boolean _exchangeRefusal = false;   // Exchange refusal

	private L2Party _party;

	// this is needed to find the inviting player for Party response
	// there can only be one active party request at once
	private L2PcInstance _activeRequester;
	private long _requestExpireTime = 0;
	private L2Request _request = new L2Request(this);
	private L2ItemInstance _arrowItem;
    private L2ItemInstance _boltItem;

	// Used for protection after teleport
	private long _protectEndTime = 0;
	public boolean isSpawnProtected() { return (_protectEndTime > 0); }

	// protects a char from agro mobs when getting up from fake death
	private long _recentFakeDeathEndTime = 0;
	private boolean _isFakeDeath;

	/** The fists L2Weapon of the L2PcInstance (used when no weapon is equiped) */
	private L2Weapon _fistsWeaponItem;

	private final Map<Integer, String> _chars = new FastMap<Integer, String>();

	//private byte _updateKnownCounter = 0;

	/** The current higher Expertise of the L2PcInstance (None=0, D=1, C=2, B=3, A=4, S=5, S80=6, S84=7)*/
	private int _expertiseIndex; // index in EXPERTISE_LEVELS
	private int _expertiseArmorPenalty = 0;
	private int _expertiseWeaponPenalty = 0;

	private boolean _isEnchanting = false;
	private L2ItemInstance _activeEnchantItem = null;
	private L2ItemInstance _activeEnchantSupportItem = null;
	private L2ItemInstance _activeEnchantAttrItem = null;
	private long _activeEnchantTimestamp = 0;

	protected boolean _inventoryDisable = false;

	protected Map<Integer, L2CubicInstance> _cubics = new FastMap<Integer, L2CubicInstance>().setShared(true);

	/** Active shots. A FastSet variable would actually suffice but this was changed to fix threading stability... */
	protected Map<Integer, Integer> _activeSoulShots = new FastMap<Integer, Integer>().setShared(true);

	public final ReentrantLock soulShotLock = new ReentrantLock();

	/** Event parameters */
	public int eventX;
	public int eventY;
	public int eventZ;
	public int eventkarma;
	public int eventpvpkills;
	public int eventpkkills;
	public String eventTitle;
	public LinkedList<String> kills = new LinkedList<String>();
	public boolean eventSitForced = false;
	public boolean atEvent = false;

	/** new loto ticket **/
	private int _loto[] = new int[5];
	//public static int _loto_nums[] = {0,1,2,3,4,5,6,7,8,9,};
	/** new race ticket **/
	private int _race[] = new int[2];

	private final BlockList _blockList = new BlockList(this);

	private int _team = 0;

    /** lvl of alliance with ketra orcs or varka silenos, used in quests and aggro checks
     *  [-5,-1] varka, 0 neutral, [1,5] ketra
     * */
    private int _alliedVarkaKetra = 0;

    private L2Fishing _fishCombat;
    private boolean _fishing = false;
    private int _fishx = 0;
    private int _fishy = 0;
    private int _fishz = 0;

    private int[] _transformAllowedSkills = {};
    private ScheduledFuture<?> _taskRentPet;
    private ScheduledFuture<?> _taskWater;

	/** Bypass validations */
	private List<String> _validBypass = new FastList<String>();
	private List<String> _validBypass2 = new FastList<String>();

	private Forum _forumMail;
	private Forum _forumMemo;

    /** Current skill in use. Note that L2Character has _lastSkillCast, but
     * this has the button presses */
	private SkillDat _currentSkill;
    private SkillDat _currentPetSkill;

    /** Skills queued because a skill is already in progress */
    private SkillDat _queuedSkill;

    /* Flag to disable equipment/skills while wearing formal wear **/
    private boolean _IsWearingFormalWear = false;

	private int _cursedWeaponEquippedId = 0;
	private boolean _combatFlagEquippedId = false;

	private int _reviveRequested = 0;
	private double _revivePower = 0;
	private boolean _revivePet = false;

	private double _cpUpdateIncCheck = .0;
	private double _cpUpdateDecCheck = .0;
	private double _cpUpdateInterval = .0;
	private double _mpUpdateIncCheck = .0;
	private double _mpUpdateDecCheck = .0;
	private double _mpUpdateInterval = .0;
	
	/* not used any more
	private boolean _isRidingFenrirWolf	= false;
	private boolean _isRidingWFenrirWolf = false;
	private boolean _isRidingGreatSnowWolf = false;
	*/
	private boolean _isRidingStrider = false;
	private boolean _isFlyingMounted = false;

	/** Herbs Task Time **/
	private int _herbstask = 0;
	/** Task for Herbs */
	public class HerbTask implements Runnable
	{
		private String _process;
		private int _itemId;
		private long _count;
		private L2Object _reference;
		private boolean _sendMessage;
		
		HerbTask(String process, int itemId, long count, L2Object reference, boolean sendMessage)
		{
			_process = process;
			_itemId = itemId;
			_count = count;
			_reference = reference;
			_sendMessage = sendMessage;
		}
		
		public void run()
		{
			try
			{
				addItem(_process, _itemId, _count, _reference, _sendMessage);
			}
			catch (Exception e)
			{
				_log.log(Level.WARNING, "", e);
			}
		}
	}

	/** ShortBuff clearing Task */
	ScheduledFuture<?> _shortBuffTask = null;

	public class ShortBuffTask implements Runnable
	{
		private L2PcInstance _player = null;
		
		public ShortBuffTask(L2PcInstance activeChar)
		{
			_player = activeChar;
		}
		
		public void run()
		{
			if (_player == null)
				return;
			
			_player.sendPacket(new ShortBuffStatusUpdate(0, 0, 0));
			setShortBuffTaskSkillId(0);
		}
	}

	// L2JMOD Wedding
	private boolean _married = false;
	private int _partnerId = 0;
	private int _coupleId = 0;
	private boolean _engagerequest = false;
	private int _engageid = 0;
	private boolean _marryrequest = false;
	private boolean _marryaccepted = false;

    /** Skill casting information (used to queue when several skills are cast in a short time) **/
    public class SkillDat
    {
        private L2Skill _skill;
        private boolean _ctrlPressed;
        private boolean _shiftPressed;

        protected SkillDat(L2Skill skill, boolean ctrlPressed, boolean shiftPressed)
        {
            _skill = skill;
            _ctrlPressed = ctrlPressed;
            _shiftPressed = shiftPressed;
        }

        public boolean isCtrlPressed()
        {
            return _ctrlPressed;
        }

        public boolean isShiftPressed()
        {
            return _shiftPressed;
        }

        public L2Skill getSkill()
        {
            return _skill;
        }

        public int getSkillId()
        {
            return (getSkill() != null) ? getSkill().getId() : -1;
        }
    }

    //summon friend
    private summonRequest _summonRequest = new summonRequest();

    public class summonRequest
    {
    	private L2PcInstance _target = null;
    	private L2Skill _skill = null;

    	public void setTarget(L2PcInstance destination, L2Skill skill)
    	{
    		_target = destination;
    		_skill = skill;
    	}

    	public L2PcInstance getTarget()
    	{
    		return _target;
    	}
    	
    	public L2Skill getSkill()
    	{
    		return _skill;
    	}
    }
    
    // open/close gates
    private gatesRequest _gatesRequest = new gatesRequest();
    
    public class gatesRequest
    {
    	private L2DoorInstance _target = null;
    	public void setTarget(L2DoorInstance door)
    	{
    		_target = door;
    	}
    	public L2DoorInstance getDoor()
    	{
    		return _target;
    	}
    }
	/**
	 * Create a new L2PcInstance and add it in the characters table of the database.<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Create a new L2PcInstance with an account name </li>
	 * <li>Set the name, the Hair Style, the Hair Color and  the Face type of the L2PcInstance</li>
	 * <li>Add the player in the characters table of the database</li><BR><BR>
	 *
	 * @param objectId Identifier of the object to initialized
	 * @param template The L2PcTemplate to apply to the L2PcInstance
	 * @param accountName The name of the L2PcInstance
	 * @param name The name of the L2PcInstance
	 * @param hairStyle The hair style Identifier of the L2PcInstance
	 * @param hairColor The hair color Identifier of the L2PcInstance
	 * @param face The face type Identifier of the L2PcInstance
	 *
	 * @return The L2PcInstance added to the database or null
	 *
	 */
	public static L2PcInstance create(int objectId, L2PcTemplate template, String accountName, String name, byte hairStyle, byte hairColor, byte face, boolean sex)
	{
		// Create a new L2PcInstance with an account name
		PcAppearance app = new PcAppearance(face, hairColor, hairStyle, sex);
		L2PcInstance player = new L2PcInstance(objectId, template, accountName, app);
		
		// Set the name of the L2PcInstance
		player.setName(name);
		
		// Set Character's create time 
		player.setCreateTime(System.currentTimeMillis());
		
		// Set the base class ID to that of the actual class ID.
		player.setBaseClass(player.getClassId());
		// Kept for backwards compabitility.
		player.setNewbie(1);
		// Add the player in the characters table of the database
		boolean ok = player.createDb();
		
		if (!ok)
			return null;
		
		return player;
	}

	public static L2PcInstance createDummyPlayer(int objectId, String name)
	{
		// Create a new L2PcInstance with an account name
		L2PcInstance player = new L2PcInstance(objectId);
		player.setName(name);

		return player;
	}

	public String getAccountName()
	{
		if (getClient() == null || getClient().isDetached())
			return "disconnected";
		return getClient().getAccountName();
	}

	public Map<Integer, String> getAccountChars()
	{
		return _chars;
	}

	public int getRelation(L2PcInstance target)
	{
		int result = 0;

		if (getClan() != null)
			result |= RelationChanged.RELATION_CLAN_MEMBER;
		if (isClanLeader())
			result |= RelationChanged.RELATION_LEADER;
		if (getParty() != null && getParty() == target.getParty())
		{
			result |= RelationChanged.RELATION_HAS_PARTY;
			for (int i = 0; i < getParty().getPartyMembers().size(); i++)
			{
				if (getParty().getPartyMembers().get(i) != this)
					continue;
				switch (i)
				{
					case 0:
						result |= RelationChanged.RELATION_PARTYLEADER; // 0x10
						break;
					case 1:
						result |= RelationChanged.RELATION_PARTY4; // 0x8
						break;
					case 2:
						result |= RelationChanged.RELATION_PARTY3+RelationChanged.RELATION_PARTY2+RelationChanged.RELATION_PARTY1; // 0x7
						break;
					case 3:
						result |= RelationChanged.RELATION_PARTY3+RelationChanged.RELATION_PARTY2; // 0x6
						break;
					case 4:
						result |= RelationChanged.RELATION_PARTY3+RelationChanged.RELATION_PARTY1; // 0x5
						break;
					case 5:
						result |= RelationChanged.RELATION_PARTY3; // 0x4
						break;
					case 6:
						result |= RelationChanged.RELATION_PARTY2+RelationChanged.RELATION_PARTY1; // 0x3
						break;
					case 7:
						result |= RelationChanged.RELATION_PARTY2; // 0x2
						break;
					case 8:
						result |= RelationChanged.RELATION_PARTY1; // 0x1
						break;
				}
			}	
		}
		if (getSiegeState() != 0)
		{
			result |= RelationChanged.RELATION_INSIEGE;
			if (getSiegeState() != target.getSiegeState())
				result |= RelationChanged.RELATION_ENEMY;
			else
				result |= RelationChanged.RELATION_ALLY;
			if (getSiegeState() == 1)
				result |= RelationChanged.RELATION_ATTACKER;
		}

		if (getClan() != null && target.getClan() != null)
		{
			if (target.getPledgeType() != L2Clan.SUBUNIT_ACADEMY
				&& getPledgeType() != L2Clan.SUBUNIT_ACADEMY
				&& target.getClan().isAtWarWith(getClan().getClanId()))
			{
				result |= RelationChanged.RELATION_1SIDED_WAR;
				if (getClan().isAtWarWith(target.getClan().getClanId()))
					result |= RelationChanged.RELATION_MUTUAL_WAR;
			}
		}
		return result;
	}

	/**
	 * Retrieve a L2PcInstance from the characters table of the database and add it in _allObjects of the L2world (call restore method).<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Retrieve the L2PcInstance from the characters table of the database </li>
	 * <li>Add the L2PcInstance object in _allObjects </li>
	 * <li>Set the x,y,z position of the L2PcInstance and make it invisible</li>
	 * <li>Update the overloaded status of the L2PcInstance</li><BR><BR>
	 *
	 * @param objectId Identifier of the object to initialized
	 *
	 * @return The L2PcInstance loaded from the database
	 *
	 */
	public static L2PcInstance load(int objectId)
	{
		return restore(objectId);
	}

	private void initPcStatusUpdateValues()
	{
		_cpUpdateInterval = getMaxCp() / 352.0;
		_cpUpdateIncCheck = getMaxCp();
		_cpUpdateDecCheck = getMaxCp() - _cpUpdateInterval;
		_mpUpdateInterval = getMaxMp() / 352.0;
		_mpUpdateIncCheck = getMaxMp();
		_mpUpdateDecCheck = getMaxMp() - _mpUpdateInterval;
	}

	/**
	 * Constructor of L2PcInstance (use L2Character constructor).<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Call the L2Character constructor to create an empty _skills slot and copy basic Calculator set to this L2PcInstance </li>
	 * <li>Set the name of the L2PcInstance</li><BR><BR>
	 *
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method SET the level of the L2PcInstance to 1</B></FONT><BR><BR>
	 *
	 * @param objectId Identifier of the object to initialized
	 * @param template The L2PcTemplate to apply to the L2PcInstance
	 * @param accountName The name of the account including this L2PcInstance
	 *
	 */
	private L2PcInstance(int objectId, L2PcTemplate template, String accountName, PcAppearance app)
	{
		super(objectId, template);
        super.initCharStatusUpdateValues();
        initPcStatusUpdateValues();

		_accountName  = accountName;
        app.setOwner(this);
		_appearance   = app;

		// Create an AI
		_ai = new L2PlayerAI(new L2PcInstance.AIAccessor());

		// Create a L2Radar object
		_radar = new L2Radar(this);

		// Retrieve from the database all skills of this L2PcInstance and add them to _skills
		// Retrieve from the database all items of this L2PcInstance and add them to _inventory
		getInventory().restore();
		if (!Config.WAREHOUSE_CACHE)
			getWarehouse();
		startVitalityTask();
	}

	private L2PcInstance(int objectId)
	{
		super(objectId, null);
        super.initCharStatusUpdateValues();
        initPcStatusUpdateValues();
	}

	@Override
	public final PcKnownList getKnownList()
	{
		return (PcKnownList)super.getKnownList();
	}
	
    @Override
    public void initKnownList()
    {
    	setKnownList(new PcKnownList(this));
    }

	@Override
	public final PcStat getStat()
	{
		return (PcStat)super.getStat();
	}
    
    @Override
    public void initCharStat()
    {
    	setStat(new PcStat(this));
    }

	@Override
	public final PcStatus getStatus()
	{
		return (PcStatus)super.getStatus();
	}
	
    @Override
    public void initCharStatus()
    {
    	setStatus(new PcStatus(this));
    }
	
	@Override
	public PcPosition getPosition()
	{
		return (PcPosition)super.getPosition();
	}
	
    @Override
    public void initPosition()
    {
    	setObjectPosition(new PcPosition(this));
    }

	public final PcAppearance getAppearance()
	{
		return _appearance;
	}

	/**
	 * Return the base L2PcTemplate link to the L2PcInstance.<BR><BR>
	 */
	public final L2PcTemplate getBaseTemplate()
	{
		return CharTemplateTable.getInstance().getTemplate(_baseClass);
	}

	/** Return the L2PcTemplate link to the L2PcInstance. */
	@Override
	public final L2PcTemplate getTemplate() { return (L2PcTemplate)super.getTemplate(); }

	public void setTemplate(ClassId newclass) { super.setTemplate(CharTemplateTable.getInstance().getTemplate(newclass)); }

	/**
	 * Return the AI of the L2PcInstance (create it if necessary).<BR><BR>
	 */
	@Override
	public L2CharacterAI getAI()
	{
		L2CharacterAI ai = _ai; // copy handle
    	if (ai == null)
    	{
    		synchronized(this)
    		{
    			if (_ai == null) _ai = new L2PlayerAI(new L2PcInstance.AIAccessor());
    			return _ai;
    		}
    	}
    	return ai;
	}


	/**
	 * Calculate a destination to explore the area and set the AI Intention to AI_INTENTION_MOVE_TO.<BR><BR>
	 */
	public void explore()
	{
		if (!_exploring) return;

		if(getMountType() == 2)
			return;

		// Calculate the destination point (random)

		int x = getX()+Rnd.nextInt(6000)-3000;
		int y = getY()+Rnd.nextInt(6000)-3000;

		if (x > Universe.MAX_X) x = Universe.MAX_X;
		if (x < Universe.MIN_X) x = Universe.MIN_X;
		if (y > Universe.MAX_Y) y = Universe.MAX_Y;
		if (y < Universe.MIN_Y) y = Universe.MIN_Y;

		int z = getZ();

		L2CharPosition pos = new L2CharPosition(x,y,z,0);

		// Set the AI Intention to AI_INTENTION_MOVE_TO
		getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO,pos);

	}

	/** Return the Level of the L2PcInstance. */
	@Override
	public final int getLevel() { return getStat().getLevel(); }
	
	/**
	 * Return the _newbie rewards state of the L2PcInstance.<BR><BR>
	 */
	public int getNewbie()
	{
		return _newbie;
	}

	/**
	 * Set the _newbie rewards state of the L2PcInstance.<BR><BR>
	 *
	 * @param newbieRewards The Identifier of the _newbie state<BR><BR>
	 *
	 */
	public void setNewbie(int newbieRewards)
	{
		_newbie = newbieRewards;
	}


	public void setBaseClass(int baseClass)
	{
		_baseClass = baseClass;
	}

	public void setBaseClass(ClassId classId)
	{
		_baseClass = classId.ordinal();
	}

	public boolean isInStoreMode() { return (getPrivateStoreType() > 0); }
//	public boolean isInCraftMode() { return (getPrivateStoreType() == STORE_PRIVATE_MANUFACTURE); }

	public boolean isInCraftMode()
	{
		return _inCraftMode;
	}

	public void isInCraftMode(boolean b)
	{
		_inCraftMode = b;
	}

	/**
	 * Manage Logout Task: <li>Remove player from world <BR>
	 * {@link L2PcInstance#deleteMe()}</li> <li>Save player data into DB <BR>
	 * {@link L2GameClient#saveCharToDisk(L2PcInstance)}</li> <BR>
	 * <BR>
	 */
	public void logout()
	{
		logout(true);
	}

	/**
	 * Manage Logout Task: <li>Remove player from world <BR>
	 * {@link L2PcInstance#deleteMe()}</li> <li>Save player data into DB <BR>
	 * {@link L2GameClient#saveCharToDisk(L2PcInstance)}</li> <BR>
	 * <BR>
	 * @param closeClient
	 */
	public void logout(boolean closeClient)
	{
		try
		{
			deleteMe(closeClient);
			L2GameClient.saveCharToDisk(this, false);
		}
		catch (Exception e)
		{
			_log.info("logout(): " + e.getMessage());
			e.printStackTrace();
		}
	}

	/**
	 * Return a table containing all Common L2RecipeList of the L2PcInstance.<BR><BR>
	 */
	public L2RecipeList[] getCommonRecipeBook()
	{
		return _commonRecipeBook.values().toArray(new L2RecipeList[_commonRecipeBook.values().size()]);
	}

	/**
	 * Return a table containing all Dwarf L2RecipeList of the L2PcInstance.<BR><BR>
	 */
	public L2RecipeList[] getDwarvenRecipeBook()
	{
		return _dwarvenRecipeBook.values().toArray(new L2RecipeList[_dwarvenRecipeBook.values().size()]);
	}

	/**
	 * Add a new L2RecipList to the table _commonrecipebook containing all L2RecipeList of the L2PcInstance <BR><BR>
	 *
	 * @param recipe The L2RecipeList to add to the _recipebook
	 *
	 */
	public void registerCommonRecipeList(L2RecipeList recipe, boolean saveToDb)
	{
		_commonRecipeBook.put(recipe.getId(), recipe);
		
		if (saveToDb)
			insertNewRecipeData(recipe.getId(), false);
	}

	/**
	 * Add a new L2RecipList to the table _recipebook containing all L2RecipeList of the L2PcInstance <BR><BR>
	 *
	 * @param recipe The L2RecipeList to add to the _recipebook
	 *
	 */
	public void registerDwarvenRecipeList(L2RecipeList recipe, boolean saveToDb)
	{
		_dwarvenRecipeBook.put(recipe.getId(), recipe);
		
		if (saveToDb)
			insertNewRecipeData(recipe.getId(), true);
	}

	/**
	 * @param RecipeID The Identifier of the L2RecipeList to check in the player's recipe books
	 *
	 * @return
	 * <b>TRUE</b> if player has the recipe on Common or Dwarven Recipe book else returns <b>FALSE</b>
	 */
	public boolean hasRecipeList(int recipeId)
	{
		if (_dwarvenRecipeBook.containsKey(recipeId))
			return true;
		else if(_commonRecipeBook.containsKey(recipeId))
			return true;
		else
			return false;
	}

	/**
	 * Tries to remove a L2RecipList from the table _DwarvenRecipeBook or from table _CommonRecipeBook, those table contain all L2RecipeList of the L2PcInstance <BR><BR>
	 *
	 * @param RecipeID The Identifier of the L2RecipeList to remove from the _recipebook
	 *
	 */
	public void unregisterRecipeList(int recipeId)
	{
		if (_dwarvenRecipeBook.remove(recipeId) != null)
			 deleteRecipeData(recipeId, true);
		else if (_commonRecipeBook.remove(recipeId) != null)
			deleteRecipeData(recipeId, false);
		else
			_log.warning("Attempted to remove unknown RecipeList: "+recipeId);

		L2ShortCut[] allShortCuts = getAllShortCuts();

		for (L2ShortCut sc : allShortCuts)
		{
			if (sc != null && sc.getId() == recipeId && sc.getType() == L2ShortCut.TYPE_RECIPE)
				deleteShortCut(sc.getSlot(), sc.getPage());
		}
	}
	
	private void insertNewRecipeData(int recipeId, boolean isDwarf)
	{
		Connection con = null;
		try
		{
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement("INSERT INTO character_recipebook (charId, id, classIndex, type) values(?,?,?,?)");
			statement.setInt(1, getObjectId());
			statement.setInt(2,recipeId);
			statement.setInt(3, isDwarf ? _classIndex : 0);
			statement.setInt(4, isDwarf ? 1 : 0);
			statement.execute();
			statement.close();
		}
		catch (SQLException e)
		{
			if(_log.isLoggable(Level.SEVERE))
				_log.log(Level.SEVERE, "SQL exception while inserting recipe: "+recipeId+" from character "+getObjectId(), e);
		}
		finally
		{
			try
			{
				con.close();
			}
			catch (Exception e){}
		}		
	}
	
	private void deleteRecipeData(int recipeId, boolean isDwarf)
	{
		Connection con = null;

		try
		{
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement("DELETE FROM character_recipebook WHERE charId=? AND id=? AND classIndex=?");
			statement.setInt(1, getObjectId());
			statement.setInt(2, recipeId);
			statement.setInt(3, isDwarf ? _classIndex : 0);
			statement.execute();
			statement.close();
		}
		catch (SQLException e)
		{
			if (_log.isLoggable(Level.SEVERE))
				_log.log(Level.SEVERE, "SQL exception while deleting recipe: "+recipeId+" from character "+getObjectId(), e);
		}
		finally
		{
			try
			{
				con.close();
			} catch (Exception e) {}
		}
	}

	/**
	 * Returns the Id for the last talked quest NPC.<BR><BR>
	 */
	public int getLastQuestNpcObject()
	{
		return _questNpcObject;
	}

	public void setLastQuestNpcObject(int npcId)
	{
		_questNpcObject = npcId;
	}

	/**
	 * Return the QuestState object corresponding to the quest name.<BR><BR>
	 *
	 * @param quest The name of the quest
	 *
	 */
	public QuestState getQuestState(String quest)
	{
		return _quests.get(quest);
	}

	/**
	 * Add a QuestState to the table _quest containing all quests began by the L2PcInstance.<BR><BR>
	 *
	 * @param qs The QuestState to add to _quest
	 *
	 */
	public void setQuestState(QuestState qs)
	{
		_quests.put(qs.getQuestName(), qs);
	}


	/**
	 * Remove a QuestState from the table _quest containing all quests began by the L2PcInstance.<BR><BR>
	 *
	 * @param quest The name of the quest
	 *
	 */
	public void delQuestState(String quest)
	{
		_quests.remove(quest);
	}

	private QuestState[] addToQuestStateArray(QuestState[] questStateArray, QuestState state) {
		int len = questStateArray.length;
		QuestState[] tmp = new QuestState[len+1];
		for (int i=0; i < len; i++)
			tmp[i] = questStateArray[i];
		tmp[len] = state;
		return tmp;
	}

	/**
	 * Return a table containing all Quest in progress from the table _quests.<BR><BR>
	 */
	public Quest[] getAllActiveQuests()
	{
		FastList<Quest> quests = new FastList<Quest>();

		for (QuestState qs : _quests.values())
		{
			if (qs == null)
				continue;
			
			if (qs.getQuest() == null)
				continue;
			
		    int questId = qs.getQuest().getQuestIntId();
			if ((questId>19999) || (questId<1))
				continue;

			if (!qs.isStarted() && !Config.DEVELOPER)
				continue;

			quests.add(qs.getQuest());
		}

		return quests.toArray(new Quest[quests.size()]);
	}

	/**
	 * Return a table containing all QuestState to modify after a L2Attackable killing.<BR><BR>
	 *
	 * @param npcId The Identifier of the L2Attackable attacked
	 *
	 */
	public QuestState[] getQuestsForAttacks(L2Npc npc)
	{
		// Create a QuestState table that will contain all QuestState to modify
		QuestState[] states = null;

		// Go through the QuestState of the L2PcInstance quests
		for (Quest quest : npc.getTemplate().getEventQuests(Quest.QuestEventType.ON_ATTACK))
		{
			// Check if the Identifier of the L2Attackable attck is needed for the current quest
			if (getQuestState(quest.getName())!=null)
			{
				// Copy the current L2PcInstance QuestState in the QuestState table
				if (states == null)
					states = new QuestState[]{getQuestState(quest.getName())};
				else
					states = addToQuestStateArray(states, getQuestState(quest.getName()));
			}
		}

		// Return a table containing all QuestState to modify
		return states;
	}

	/**
	 * Return a table containing all QuestState to modify after a L2Attackable killing.<BR><BR>
	 *
	 * @param npcId The Identifier of the L2Attackable killed
	 *
	 */
	public QuestState[] getQuestsForKills(L2Npc npc)
	{
		// Create a QuestState table that will contain all QuestState to modify
		QuestState[] states = null;

		// Go through the QuestState of the L2PcInstance quests
		for (Quest quest : npc.getTemplate().getEventQuests(Quest.QuestEventType.ON_KILL))
		{
			// Check if the Identifier of the L2Attackable killed is needed for the current quest
			if (getQuestState(quest.getName())!=null)
			{
				// Copy the current L2PcInstance QuestState in the QuestState table
				if (states == null)
					states = new QuestState[]{getQuestState(quest.getName())};
				else
					states = addToQuestStateArray(states, getQuestState(quest.getName()));
			}
		}

		// Return a table containing all QuestState to modify
		return states;
	}

	/**
	 * Return a table containing all QuestState from the table _quests in which the L2PcInstance must talk to the NPC.<BR><BR>
	 *
	 * @param npcId The Identifier of the NPC
	 *
	 */
	public QuestState[] getQuestsForTalk(int npcId)
	{
		// Create a QuestState table that will contain all QuestState to modify
		QuestState[] states = null;

		// Go through the QuestState of the L2PcInstance quests
		Quest[] quests = NpcTable.getInstance().getTemplate(npcId).getEventQuests(Quest.QuestEventType.ON_TALK);
		if (quests != null)
		{
			for (Quest quest: quests)
			{
				if (quest != null)
				{
					// Copy the current L2PcInstance QuestState in the QuestState table
					if (getQuestState(quest.getName())!=null)
					{
						if (states == null)
							states = new QuestState[]{getQuestState(quest.getName())};
						else
							states = addToQuestStateArray(states, getQuestState(quest.getName()));
					}
				}
			}
		}

		// Return a table containing all QuestState to modify
		return states;
	}

	public QuestState processQuestEvent(String quest, String event)
	{
		QuestState retval = null;
		if (event == null)
			event = "";
		if (!_quests.containsKey(quest))
			return retval;
		QuestState qs = getQuestState(quest);
		if (qs == null && event.length() == 0)
			return retval;
		if (qs == null) {
			Quest q = QuestManager.getInstance().getQuest(quest);
			if (q == null)
				return retval;
			qs = q.newQuestState(this);
		}
		if (qs != null) {
			if (getLastQuestNpcObject() > 0)
			{
				L2Object object = L2World.getInstance().findObject(getLastQuestNpcObject());
				if (object instanceof L2Npc && isInsideRadius(object, L2Npc.INTERACTION_DISTANCE, false, false))
                {
					L2Npc npc = (L2Npc)object;
					QuestState[] states = getQuestsForTalk(npc.getNpcId());

					if (states != null)
					{
						for (QuestState state : states)
						{
							if ((state.getQuest().getQuestIntId() == qs.getQuest().getQuestIntId()))
							{
								if (qs.getQuest().notifyEvent(event, npc, this))
									showQuestWindow(quest, State.getStateName(qs.getState()));

								retval = qs;
							}
						}
						sendPacket(new QuestList());
					}
				}
			}
		}

		return retval;
	}

	private void showQuestWindow(String questId, String stateId)
	{
		String path = "data/scripts/quests/"+questId+"/"+stateId+".htm";
		String content = HtmCache.getInstance().getHtm(path);  //TODO path for quests html

		if (content != null)
		{
			if (Config.DEBUG)
				_log.fine("Showing quest window for quest "+questId+" state "+stateId+" html path: " + path);

			NpcHtmlMessage npcReply = new NpcHtmlMessage(5);
			npcReply.setHtml(content);
			sendPacket(npcReply);
		}

		sendPacket( ActionFailed.STATIC_PACKET );
	}

	/** List of all QuestState instance that needs to be notified of this L2PcInstance's or its pet's death */
	private List<QuestState> _NotifyQuestOfDeathList = new FastList<QuestState>();

	/**
	 * Add QuestState instance that is to be notified of L2PcInstance's death.<BR><BR>
	 *
	 * @param qs The QuestState that subscribe to this event
	 *
	 */
	public void addNotifyQuestOfDeath (QuestState qs)
	{
		if (qs == null || _NotifyQuestOfDeathList.contains(qs))
			return;

		_NotifyQuestOfDeathList.add(qs);
	}

	/**
	 * Remove QuestState instance that is to be notified of L2PcInstance's death.<BR><BR>
	 *
	 * @param qs The QuestState that subscribe to this event
	 *
	 */
	public void removeNotifyQuestOfDeath (QuestState qs)
	{
		if (qs == null || !_NotifyQuestOfDeathList.contains(qs))
			return;

		_NotifyQuestOfDeathList.remove(qs);
	}

	/**
	 * Return a list of QuestStates which registered for notify of death of this L2PcInstance.<BR><BR>
	 */
	public final List<QuestState> getNotifyQuestOfDeath ()
	{
		if (_NotifyQuestOfDeathList == null)
			_NotifyQuestOfDeathList = new FastList<QuestState>();

		return _NotifyQuestOfDeathList;
	}

	/**
	 * Return a table containing all L2ShortCut of the L2PcInstance.<BR><BR>
	 */
	public L2ShortCut[] getAllShortCuts()
	{
		return _shortCuts.getAllShortCuts();
	}

	/**
	 * Return the L2ShortCut of the L2PcInstance corresponding to the position (page-slot).<BR><BR>
	 *
	 * @param slot The slot in wich the shortCuts is equiped
	 * @param page The page of shortCuts containing the slot
	 *
	 */
	public L2ShortCut getShortCut(int slot, int page)
	{
		return _shortCuts.getShortCut(slot, page);
	}

	/**
	 * Add a L2shortCut to the L2PcInstance _shortCuts<BR><BR>
	 */
	public void registerShortCut(L2ShortCut shortcut)
	{
		_shortCuts.registerShortCut(shortcut);
	}

	/**
	 * Delete the L2ShortCut corresponding to the position (page-slot) from the L2PcInstance _shortCuts.<BR><BR>
	 */
	public void deleteShortCut(int slot, int page)
	{
		_shortCuts.deleteShortCut(slot, page);
	}

	/**
	 * Add a L2Macro to the L2PcInstance _macroses<BR><BR>
	 */
	public void registerMacro(L2Macro macro)
	{
		_macroses.registerMacro(macro);
	}

	/**
	 * Delete the L2Macro corresponding to the Identifier from the L2PcInstance _macroses.<BR><BR>
	 */
	public void deleteMacro(int id)
	{
		_macroses.deleteMacro(id);
	}

	/**
	 * Return all L2Macro of the L2PcInstance.<BR><BR>
	 */
	public MacroList getMacroses()
	{
		return _macroses;
	}

	/**
	 * Set the siege state of the L2PcInstance.<BR><BR>
	 * 1 = attacker, 2 = defender, 0 = not involved
	 */
	public void setSiegeState(byte siegeState)
	{
		_siegeState = siegeState;
	}
	/**
	 * Get the siege state of the L2PcInstance.<BR><BR>
	 * 1 = attacker, 2 = defender, 0 = not involved
	 */
	public byte getSiegeState()
	{
		return _siegeState;
	}

	/**
	 * Set the siege Side of the L2PcInstance.<BR><BR>
	 */
	public void setSiegeSide(int val)
	{
		_siegeSide = val;
	}
	
	public boolean isRegisteredOnThisSiegeField(int val)
	{
		if (_siegeSide != val && (_siegeSide < 81 || _siegeSide > 89))
			return false;
		return true;
	}
	
	public int getSiegeSide()
	{
		return _siegeSide;
	}
	
	/**
	 * Set the PvP Flag of the L2PcInstance.<BR><BR>
	 */
	public void setPvpFlag(int pvpFlag)
	{
		_pvpFlag = (byte)pvpFlag;
	}

	public byte getPvpFlag()
	{
		return _pvpFlag;
	}

	@Override
	public void updatePvPFlag(int value)
	{
		if (getPvpFlag() == value)
			return;
		setPvpFlag(value);

		sendPacket(new UserInfo(this));
		sendPacket(new ExBrExtraUserInfo(this));

		// If this player has a pet update the pets pvp flag as well
		if (getPet() != null) sendPacket(new RelationChanged(getPet(), getRelation(this), false));

		Collection<L2PcInstance> plrs = getKnownList().getKnownPlayers().values();
		//synchronized (getKnownList().getKnownPlayers())
		{
			for (L2PcInstance target : plrs)
			{
				target.sendPacket(new RelationChanged(this, getRelation(target), isAutoAttackable(target)));
				if (getPet() != null)
					target.sendPacket(new RelationChanged(getPet(), getRelation(target), isAutoAttackable(target)));
			}
		}
	}

	@Override
    public void revalidateZone(boolean force)
    {
    	// Cannot validate if not in  a world region (happens during teleport)
    	if (getWorldRegion() == null) return;

    	// This function is called too often from movement code
    	if (force) _zoneValidateCounter = 4;
    	else
    	{
    		_zoneValidateCounter--;
    		if (_zoneValidateCounter < 0)
    			_zoneValidateCounter = 4;
    		else return;
    	}

    	getWorldRegion().revalidateZones(this);
    	
        if (Config.ALLOW_WATER)
            checkWaterState();

        if (isInsideZone(ZONE_DANGERAREA))
        {
        	if (_lastCompassZone == ExSetCompassZoneCode.ALTEREDZONE) return;
        	_lastCompassZone = ExSetCompassZoneCode.ALTEREDZONE;
        	ExSetCompassZoneCode cz = new ExSetCompassZoneCode(ExSetCompassZoneCode.ALTEREDZONE);
        	sendPacket(cz);
        }
        else if (isInsideZone(ZONE_SIEGE))
        {
        	if (_lastCompassZone == ExSetCompassZoneCode.SIEGEWARZONE2) return;
        	_lastCompassZone = ExSetCompassZoneCode.SIEGEWARZONE2;
        	ExSetCompassZoneCode cz = new ExSetCompassZoneCode(ExSetCompassZoneCode.SIEGEWARZONE2);
        	sendPacket(cz);
        }
        else if (isInsideZone(ZONE_PVP))
        {
        	if (_lastCompassZone == ExSetCompassZoneCode.PVPZONE) return;
        	_lastCompassZone = ExSetCompassZoneCode.PVPZONE;
        	ExSetCompassZoneCode cz = new ExSetCompassZoneCode(ExSetCompassZoneCode.PVPZONE);
        	sendPacket(cz);
        }
        else if (isIn7sDungeon())
        {
        	if (_lastCompassZone == ExSetCompassZoneCode.SEVENSIGNSZONE) return;
        	_lastCompassZone = ExSetCompassZoneCode.SEVENSIGNSZONE;
        	ExSetCompassZoneCode cz = new ExSetCompassZoneCode(ExSetCompassZoneCode.SEVENSIGNSZONE);
        	sendPacket(cz);
        }
        else if (isInsideZone(ZONE_PEACE))
        {
        	if (_lastCompassZone == ExSetCompassZoneCode.PEACEZONE) return;
        	_lastCompassZone = ExSetCompassZoneCode.PEACEZONE;
        	ExSetCompassZoneCode cz = new ExSetCompassZoneCode(ExSetCompassZoneCode.PEACEZONE);
        	sendPacket(cz);
        }
        else
        {
        	if (_lastCompassZone == ExSetCompassZoneCode.GENERALZONE) return;
        	if (_lastCompassZone == ExSetCompassZoneCode.SIEGEWARZONE2) updatePvPStatus();
        	_lastCompassZone = ExSetCompassZoneCode.GENERALZONE;
        	ExSetCompassZoneCode cz = new ExSetCompassZoneCode(ExSetCompassZoneCode.GENERALZONE);
        	sendPacket(cz);
        }
    }

	/**
	 * Return True if the L2PcInstance can Craft Dwarven Recipes.<BR><BR>
	 */
	public boolean hasDwarvenCraft()
	{
		return getSkillLevel(L2Skill.SKILL_CREATE_DWARVEN) >= 1;
	}

	public int getDwarvenCraft()
	{
		return getSkillLevel(L2Skill.SKILL_CREATE_DWARVEN);
	}

	/**
	 * Return True if the L2PcInstance can Craft Dwarven Recipes.<BR><BR>
	 */
	public boolean hasCommonCraft()
	{
		return getSkillLevel(L2Skill.SKILL_CREATE_COMMON) >= 1;
	}

	public int getCommonCraft()
	{
		return getSkillLevel(L2Skill.SKILL_CREATE_COMMON);
	}

	/**
	 * Return the PK counter of the L2PcInstance.<BR><BR>
	 */
	public int getPkKills()
	{
		return _pkKills;
	}

	/**
	 * Set the PK counter of the L2PcInstance.<BR><BR>
	 */
	public void setPkKills(int pkKills)
	{
		_pkKills = pkKills;
	}

	/**
	 * Return the _deleteTimer of the L2PcInstance.<BR><BR>
	 */
	public long getDeleteTimer()
	{
		return _deleteTimer;
	}

	/**
	 * Set the _deleteTimer of the L2PcInstance.<BR><BR>
	 */
	public void setDeleteTimer(long deleteTimer)
	{
		_deleteTimer = deleteTimer;
	}

	/**
	 * Return the current weight of the L2PcInstance.<BR><BR>
	 */
	public int getCurrentLoad()
	{
		return _inventory.getTotalWeight();
	}
	/**
	 * Return date of las update of recomPoints
	 */
	public long getLastRecomUpdate()
	{
		return _lastRecomUpdate;
	}
	public void setLastRecomUpdate(long date)
	{
		_lastRecomUpdate = date;
	}
	/**
	 * Return the number of recommandation obtained by the L2PcInstance.<BR><BR>
	 */
	public int getRecomHave()
	{
		return _recomHave;
	}

	/**
	 * Increment the number of recommandation obtained by the L2PcInstance (Max : 255).<BR><BR>
	 */
	protected void incRecomHave()
	{
		if (_recomHave < 255)
			_recomHave++;
	}

	/**
	 * Set the number of recommandation obtained by the L2PcInstance (Max : 255).<BR><BR>
	 */
	public void setRecomHave(int value)
	{
		if (value > 255)
			_recomHave = 255;
		else if (value < 0)
			_recomHave = 0;
		else
			_recomHave = value;
	}



	/**
	 * Return the number of recommandation that the L2PcInstance can give.<BR><BR>
	 */
	public int getRecomLeft()
	{
		return _recomLeft;
	}

	/**
	 * Increment the number of recommandation that the L2PcInstance can give.<BR><BR>
	 */
	protected void decRecomLeft()
	{
		if (_recomLeft > 0)
			_recomLeft--;
	}

	public void giveRecom(L2PcInstance target)
	{
		if (Config.ALT_RECOMMEND)
		{
			Connection con = null;
			try
			{
				con = L2DatabaseFactory.getInstance().getConnection();
				PreparedStatement statement = con.prepareStatement(ADD_CHAR_RECOM);
				statement.setInt(1, getObjectId());
				statement.setInt(2, target.getObjectId());
				statement.execute();
				statement.close();
			}
			catch (Exception e)
			{
				_log.log(Level.SEVERE, "Failed updating character recommendations.", e);
			}
			finally
			{
				try { con.close(); } catch (Exception e) {}
			}
		}
		target.incRecomHave();
		decRecomLeft();
		_recomChars.add(target.getObjectId());
	}

	public boolean canRecom(L2PcInstance target)
	{
		return !_recomChars.contains(target.getObjectId());
	}

	/**
	 * Set the exp of the L2PcInstance before a death
	 * @param exp
	 */
	public void setExpBeforeDeath(long exp)
	{
		_expBeforeDeath = exp;
	}

	public long getExpBeforeDeath()
	{
		return _expBeforeDeath;
	}

	/**
	 * Return the Karma of the L2PcInstance.<BR><BR>
	 */
	public int getKarma()
	{
		return _karma;
	}

	/**
	 * Set the Karma of the L2PcInstance and send a Server->Client packet StatusUpdate (broadcast).<BR><BR>
	 */
	public void setKarma(int karma)
	{
		if (karma < 0) karma = 0;
		if (_karma == 0 && karma > 0)
		{
			Collection<L2Object> objs = getKnownList().getKnownObjects().values();
			//synchronized (getKnownList().getKnownObjects())
			{
				for (L2Object object : objs)
				{
					if (!(object instanceof L2GuardInstance))
						continue;
					
					if (((L2GuardInstance) object).getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE)
						((L2GuardInstance) object).getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE, null);
				}
			}
		}
		else if (_karma > 0 && karma == 0)
		{
			// Send a Server->Client StatusUpdate packet with Karma and PvP Flag to the L2PcInstance and all L2PcInstance to inform (broadcast)
			setKarmaFlag(0);
		}

		_karma = karma;
		broadcastKarma();
	}

	/**
	 * Return the max weight that the L2PcInstance can load.<BR><BR>
	 */
	public int getMaxLoad()
	{
		// Weight Limit = (CON Modifier*69000)*Skills
		// Source http://l2p.bravehost.com/weightlimit.html (May 2007)
		// Fitted exponential curve to the data
		int con = getCON();
		if (con < 1) return 31000;
		if (con > 59) return 176000;
		double baseLoad = Math.pow(1.029993928, con)*30495.627366;
		return (int)calcStat(Stats.MAX_LOAD, baseLoad*Config.ALT_WEIGHT_LIMIT, this, null);
	}

	public int getExpertiseArmorPenalty()
	{
		return _expertiseArmorPenalty;
	}

	public int getExpertiseWeaponPenalty()
	{
		return _expertiseWeaponPenalty;
	}

	public int getWeightPenalty()
	{
		if (_dietMode)
			return 0;
		return _curWeightPenalty;
	}

	/**
	 * Update the overloaded status of the L2PcInstance.<BR><BR>
	 */
	public void refreshOverloaded()
	{
		int maxLoad = getMaxLoad();
		if (maxLoad > 0)
		{
			long weightproc = (long)getCurrentLoad() * 1000 / maxLoad;
			weightproc *= calcStat(Stats.WEIGHT_LIMIT, 1, this, null);
			int newWeightPenalty;
			if (weightproc < 500 || _dietMode)
			{
				newWeightPenalty = 0;
			}
			else if (weightproc < 666)
			{
				newWeightPenalty = 1;
			}
			else if ( weightproc < 800)
			{
				newWeightPenalty = 2;
			}
			else if (weightproc < 1000)
			{
				newWeightPenalty = 3;
			}
			else
			{
				newWeightPenalty = 4;
			}

			if (_curWeightPenalty != newWeightPenalty)
			{
				_curWeightPenalty = newWeightPenalty;
				if (newWeightPenalty > 0 && !_dietMode)
				{
					super.addSkill(SkillTable.getInstance().getInfo(4270,newWeightPenalty));
					setIsOverloaded(getCurrentLoad() > maxLoad);
				}
				else
				{
					super.removeSkill(getKnownSkill(4270));
					setIsOverloaded(false);
				}
				sendPacket(new UserInfo(this));
				sendPacket(new EtcStatusUpdate(this));
				broadcastPacket(new CharInfo(this));
				broadcastPacket(new ExBrExtraUserInfo(this));
			}
		}
	}

	public void refreshExpertisePenalty()
	{
		if (!Config.EXPERTISE_PENALTY)
			return;
		
		int armorPenalty = 0;
		int weaponPenalty = 0;
		
		for (L2ItemInstance item : getInventory().getItems())
		{
			if (item != null && item.isEquipped())
			{
				int crystaltype = item.getItem().getCrystalType();
				
				if (crystaltype > getExpertiseIndex())
				{
					if (item.isWeapon() && crystaltype > weaponPenalty)
						weaponPenalty = crystaltype;
					else if (crystaltype > armorPenalty)
						armorPenalty = crystaltype;
				}
			}
		}
		
		boolean changed = false;
		
		// calc armor penalty
		armorPenalty = armorPenalty - getExpertiseIndex();
		
		if (armorPenalty < 0)
			armorPenalty = 0;
		else if (armorPenalty > 4)
			armorPenalty = 4;
		
		if (getExpertiseArmorPenalty() != armorPenalty || getSkillLevel(6213) != armorPenalty)
		{
			_expertiseArmorPenalty = armorPenalty;
			
			if (_expertiseArmorPenalty > 0)
				super.addSkill(SkillTable.getInstance().getInfo(6213, _expertiseArmorPenalty)); // level used to be newPenalty
			else
				super.removeSkill(getKnownSkill(6213));
			
			changed = true;
		}
		
		// calc weapon penalty
		weaponPenalty = weaponPenalty - getExpertiseIndex();
		if (weaponPenalty < 0)
			weaponPenalty = 0;
		else if (weaponPenalty > 4)
			weaponPenalty = 4;
		
		if (getExpertiseWeaponPenalty() != weaponPenalty || getSkillLevel(6209) != weaponPenalty)
		{
			_expertiseWeaponPenalty = weaponPenalty;
			
			if (_expertiseWeaponPenalty > 0)
				super.addSkill(SkillTable.getInstance().getInfo(6209, _expertiseWeaponPenalty)); // level used to be newPenalty
			else
				super.removeSkill(getKnownSkill(6209));
			
			changed = true;
		}
		
		if (changed)
			sendPacket(new EtcStatusUpdate(this));
	}

    public void checkIfWeaponIsAllowed()
    {
        // Override for Gamemasters
        if (isGM())
            return;

        // Iterate through all effects currently on the character.
        for (L2Effect currenteffect : getAllEffects())
        {
            L2Skill effectSkill = currenteffect.getSkill();

            // Ignore all buff skills that are party related (ie. songs, dances) while still remaining weapon dependant on cast though.
            if (!effectSkill.isOffensive() && !(effectSkill.getTargetType() == SkillTargetType.TARGET_PARTY && effectSkill.getSkillType() == L2SkillType.BUFF))
            {
                // Check to rest to assure current effect meets weapon requirements.
            	if (!effectSkill.getWeaponDependancy(this))
                {
            		SystemMessage sm = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
            		sm.addSkillName(effectSkill);
            		sendPacket(sm);

                    if (Config.DEBUG)
                        _log.info("   | Skill "+effectSkill.getName()+" has been disabled for ("+getName()+"); Reason: Incompatible Weapon Type.");

                    currenteffect.exit();
                }
            }

            continue;
        }
    }

    public void checkSSMatch(L2ItemInstance equipped, L2ItemInstance unequipped)
    {
    	if (unequipped == null)
    		return;

		if (unequipped.getItem().getType2() == L2Item.TYPE2_WEAPON &&
				(equipped == null ? true : equipped.getItem().getCrystalType() != unequipped.getItem().getCrystalType()))
		{
			for (L2ItemInstance ss : getInventory().getItems())
			{
				if (ss == null)
					continue;
				
				int _itemId = ss.getItemId();

				if (((_itemId >= 2509 && _itemId <= 2514) ||
						(_itemId >= 3947 && _itemId <= 3952) ||
						(_itemId <= 1804 && _itemId >= 1808) ||
						_itemId == 5789 || _itemId == 5790 || _itemId == 1835
						|| (_itemId >=22072 && _itemId <=22086)) &&
						ss.getItem().getCrystalType() == unequipped.getItem().getCrystalType())
				{
                    sendPacket(new ExAutoSoulShot(_itemId, 0));

                    SystemMessage sm = new SystemMessage(SystemMessageId.AUTO_USE_OF_S1_CANCELLED);
                    sm.addString(ss.getItemName());
                    sendPacket(sm);
				}
			}
		}
    }

    public void useEquippableItem(L2ItemInstance item, boolean abortAttack)
	{
		// Equip or unEquip
        L2ItemInstance[] items = null;
        final boolean isEquiped = item.isEquipped();
        final int oldInvLimit = getInventoryLimit();
        SystemMessage sm = null;
        L2ItemInstance old = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LRHAND);
        if (old == null)
        	old = getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);

        checkSSMatch(item, old);

        if (isEquiped)
        {
            if (item.getEnchantLevel() > 0)
            {
            	sm = new SystemMessage(SystemMessageId.EQUIPMENT_S1_S2_REMOVED);
            	sm.addNumber(item.getEnchantLevel());
            	sm.addItemName(item);
            }
            else
            {
	            sm = new SystemMessage(SystemMessageId.S1_DISARMED);
	            sm.addItemName(item);
            }
            sendPacket(sm);

            int slot = getInventory().getSlotFromItem(item);
            // we cant unequip talisman by body slot
            if (slot == L2Item.SLOT_DECO)
            	items = getInventory().unEquipItemInSlotAndRecord(item.getLocationSlot());
            else
            	items = getInventory().unEquipItemInBodySlotAndRecord(slot);
        }
        else
        {
        	int tempBodyPart = item.getItem().getBodyPart();
        	L2ItemInstance tempItem = getInventory().getPaperdollItemByL2ItemId(tempBodyPart);

        	//check if the item replaces a wear-item
        	if (tempItem != null && tempItem.isWear())
        	{
        		// dont allow an item to replace a wear-item
        		return;
        	}
        	else if (tempBodyPart == L2Item.SLOT_LR_HAND)
        	{
        		// this may not remove left OR right hand equipment
        		tempItem = getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
        		if (tempItem != null && tempItem.isWear()) return;

        		tempItem = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
        		if (tempItem != null && tempItem.isWear()) return;
        	}
        	else if (tempBodyPart == L2Item.SLOT_FULL_ARMOR)
        	{
        		// this may not remove chest or leggins
        		tempItem = getInventory().getPaperdollItem(Inventory.PAPERDOLL_CHEST);
        		if (tempItem != null && tempItem.isWear()) return;

        		tempItem = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LEGS);
        		if (tempItem != null && tempItem.isWear()) return;
        	}

			if (item.getEnchantLevel() > 0)
			{
				sm = new SystemMessage(SystemMessageId.S1_S2_EQUIPPED);
				sm.addNumber(item.getEnchantLevel());
				sm.addItemName(item);
			}
			else
			{
				sm = new SystemMessage(SystemMessageId.S1_EQUIPPED);
				sm.addItemName(item);
			}
			sendPacket(sm);

			items = getInventory().equipItemAndRecord(item);

            // Consume mana - will start a task if required; returns if item is not a shadow item
            item.decreaseMana(false);
        }
        sm = null;

        refreshExpertisePenalty();

		/**
		// remove effects which doesn't match weapon type (but not party buffs)
		if (item.getItem().getType2() == L2Item.TYPE2_WEAPON)
			checkIfWeaponIsAllowed();
		**/

		broadcastUserInfo();
		
		InventoryUpdate iu = new InventoryUpdate();
		iu.addItems(Arrays.asList(items));
		sendPacket(iu);
		
		if (abortAttack) abortAttack();
		
		if (getInventoryLimit() != oldInvLimit)
			sendPacket(new ExStorageMaxCount(this));
	}
    
	/**
	 * Return the the PvP Kills of the L2PcInstance (Number of player killed during a PvP).<BR><BR>
	 */
	public int getPvpKills()
	{
		return _pvpKills;
	}

	/**
	 * Set the the PvP Kills of the L2PcInstance (Number of player killed during a PvP).<BR><BR>
	 */
	public void setPvpKills(int pvpKills)
	{
		_pvpKills = pvpKills;
	}
	
	/**
	 * Return the Fame of this L2PcInstance <BR><BR>
	 * @return
	 */
	public int getFame()
	{
		return _fame;
	}
	
	/**
	 * Set the Fame of this L2PcInstane <BR><BR>
	 * @param fame
	 */
	public void setFame(int fame)
	{
		if (fame > Config.MAX_PERSONAL_FAME_POINTS)
			_fame = Config.MAX_PERSONAL_FAME_POINTS;
		else
			_fame = fame;
	}

	/**
	 * Return the ClassId object of the L2PcInstance contained in L2PcTemplate.<BR><BR>
	 */
	public ClassId getClassId()
	{
		return getTemplate().classId;
	}

	/**
	 * Set the template of the L2PcInstance.<BR><BR>
	 *
	 * @param Id The Identifier of the L2PcTemplate to set to the L2PcInstance
	 *
	 */
	public void setClassId(int Id)
	{
    	if (!_subclassLock.tryLock())
    		return;

    	try
    	{
    		if (getLvlJoinedAcademy() != 0 && _clan != null && PlayerClass.values()[Id].getLevel() == ClassLevel.Third)
            {
    			if(getLvlJoinedAcademy() <= 16)
    				_clan.addReputationScore(Config.JOIN_ACADEMY_MAX_REP_SCORE, true);
                else if(getLvlJoinedAcademy() >= 39)
                	_clan.addReputationScore(Config.JOIN_ACADEMY_MIN_REP_SCORE, true);
                else
                	_clan.addReputationScore((Config.JOIN_ACADEMY_MAX_REP_SCORE-(getLvlJoinedAcademy()-16)*20), true);
    			setLvlJoinedAcademy(0);
                //oust pledge member from the academy, cuz he has finished his 2nd class transfer
                SystemMessage msg = new SystemMessage(SystemMessageId.CLAN_MEMBER_S1_EXPELLED);
                msg.addPcName(this);
                _clan.broadcastToOnlineMembers(msg);
                _clan.broadcastToOnlineMembers(new PledgeShowMemberListDelete(getName()));
                _clan.removeClanMember(getObjectId(), 0);
                sendPacket(new SystemMessage(SystemMessageId.ACADEMY_MEMBERSHIP_TERMINATED));

                // receive graduation gift
                getInventory().addItem("Gift",8181,1,this,null); // give academy circlet
            }
    		if (isSubClassActive())
    		{
    			getSubClasses().get(_classIndex).setClassId(Id);
    		}
    		setTarget(this);
    		broadcastPacket(new MagicSkillUse(this, 5103, 1, 1000, 0));
    		setClassTemplate(Id);
    		if (getClassId().level() == 3)
    			sendPacket(new SystemMessage(SystemMessageId.THIRD_CLASS_TRANSFER));
    		else
    			sendPacket(new SystemMessage(SystemMessageId.CLASS_TRANSFER));
    		
    		// Update class icon in party and clan
    		if (isInParty())
    			getParty().broadcastToPartyMembers(new PartySmallWindowUpdate(this));

    		if (getClan() != null)
    			getClan().broadcastToOnlineMembers(new PledgeShowMemberListUpdate(this));
    		
    		if (Config.AUTO_LEARN_SKILLS)
    			rewardSkills();
    	}
    	finally
    	{
    		_subclassLock.unlock();
    	}
	}

	/** Return the Experience of the L2PcInstance. */
	public long getExp() { return getStat().getExp(); }

	public void setActiveEnchantAttrItem(L2ItemInstance stone)
	{
		_activeEnchantAttrItem = stone;
	}

	public L2ItemInstance getActiveEnchantAttrItem()
	{
		return _activeEnchantAttrItem;
	}

	public void setActiveEnchantItem(L2ItemInstance scroll)
	{
		// If we dont have a Enchant Item, we are not enchanting.
		if (scroll == null)
		{
			setActiveEnchantSupportItem(null);
			setActiveEnchantTimestamp(0);
			setIsEnchanting(false);
		}
		_activeEnchantItem = scroll;
	}

	public L2ItemInstance getActiveEnchantItem()
	{
		return _activeEnchantItem;
	}

	public void setActiveEnchantSupportItem(L2ItemInstance item)
	{
		_activeEnchantSupportItem = item;
	}

	public L2ItemInstance getActiveEnchantSupportItem()
	{
		return _activeEnchantSupportItem;
	}

	public long getActiveEnchantTimestamp()
	{
		return _activeEnchantTimestamp;
	}

	public void setActiveEnchantTimestamp(long val)
	{
		_activeEnchantTimestamp = val;
	}

	public void setIsEnchanting(boolean val)
	{
		_isEnchanting = val;
	}
	
	public boolean isEnchanting()
	{
		return _isEnchanting;
	}

	/**
	 * Set the fists weapon of the L2PcInstance (used when no weapon is equiped).<BR><BR>
	 *
	 * @param weaponItem The fists L2Weapon to set to the L2PcInstance
	 *
	 */
	public void setFistsWeaponItem(L2Weapon weaponItem)
	{
		_fistsWeaponItem = weaponItem;
	}

	/**
	 * Return the fists weapon of the L2PcInstance (used when no weapon is equiped).<BR><BR>
	 */
	public L2Weapon getFistsWeaponItem()
	{
		return _fistsWeaponItem;
	}

	/**
	 * Return the fists weapon of the L2PcInstance Class (used when no weapon is equiped).<BR><BR>
	 */
	public L2Weapon findFistsWeaponItem(int classId)
	{
		L2Weapon weaponItem = null;
		if ((classId >= 0x00) && (classId <= 0x09))
		{
			//human fighter fists
			L2Item temp = ItemTable.getInstance().getTemplate(246);
			weaponItem = (L2Weapon)temp;
		}
		else if ((classId >= 0x0a) && (classId <= 0x11))
		{
			//human mage fists
			L2Item temp = ItemTable.getInstance().getTemplate(251);
			weaponItem = (L2Weapon)temp;
		}
		else if ((classId >= 0x12) && (classId <= 0x18))
		{
			//elven fighter fists
			L2Item temp = ItemTable.getInstance().getTemplate(244);
			weaponItem = (L2Weapon)temp;
		}
		else if ((classId >= 0x19) && (classId <= 0x1e))
		{
			//elven mage fists
			L2Item temp = ItemTable.getInstance().getTemplate(249);
			weaponItem = (L2Weapon)temp;
		}
		else if ((classId >= 0x1f) && (classId <= 0x25))
		{
			//dark elven fighter fists
			L2Item temp = ItemTable.getInstance().getTemplate(245);
			weaponItem = (L2Weapon)temp;
		}
		else if ((classId >= 0x26) && (classId <= 0x2b))
		{
			//dark elven mage fists
			L2Item temp = ItemTable.getInstance().getTemplate(250);
			weaponItem = (L2Weapon)temp;
		}
		else if ((classId >= 0x2c) && (classId <= 0x30))
		{
			//orc fighter fists
			L2Item temp = ItemTable.getInstance().getTemplate(248);
			weaponItem = (L2Weapon)temp;
		}
		else if ((classId >= 0x31) && (classId <= 0x34))
		{
			//orc mage fists
			L2Item temp = ItemTable.getInstance().getTemplate(252);
			weaponItem = (L2Weapon)temp;
		}
		else if ((classId >= 0x35) && (classId <= 0x39))
		{
			//dwarven fists
			L2Item temp = ItemTable.getInstance().getTemplate(247);
			weaponItem = (L2Weapon)temp;
		}

		return weaponItem;
	}

	/**
	 * Give Expertise skill of this level and remove beginner Lucky skill.<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Get the Level of the L2PcInstance </li>
	 * <li>If L2PcInstance Level is 5, remove beginner Lucky skill </li>
	 * <li>Add the Expertise skill corresponding to its Expertise level</li>
	 * <li>Update the overloaded status of the L2PcInstance</li><BR><BR>
	 *
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T give other free skills (SP needed = 0)</B></FONT><BR><BR>
	 *
	 */
	public void rewardSkills()
	{
		// Get the Level of the L2PcInstance
		int lvl = getLevel();

		// Remove beginner Lucky skill
		if (lvl == 10)
		{
			L2Skill skill = SkillTable.getInstance().getInfo(194, 1);
			skill = removeSkill(skill);

			if (Config.DEBUG && skill != null) _log.fine("removed skill 'Lucky' from "+getName());
		}

		// Calculate the current higher Expertise of the L2PcInstance
		for (int i=0; i < EXPERTISE_LEVELS.length; i++)
		{
			if (lvl >= EXPERTISE_LEVELS[i])
				setExpertiseIndex(i);
		}

		// Add the Expertise skill corresponding to its Expertise level
		if (getExpertiseIndex() > 0)
		{
			L2Skill skill = SkillTable.getInstance().getInfo(239, getExpertiseIndex());
			addSkill(skill, true);

			if (Config.DEBUG) _log.fine("awarded "+getName()+" with new expertise.");

		}
		else
		{
			if (Config.DEBUG) _log.fine("No skills awarded at lvl: "+lvl);
		}

		//Active skill dwarven craft

		if (getSkillLevel(1321) < 1 && getRace() == Race.Dwarf)
		{
			L2Skill skill = SkillTable.getInstance().getInfo(1321,1);
			addSkill(skill, true);
		}

		//Active skill common craft
		if (getSkillLevel(1322) < 1)
		{
			L2Skill skill = SkillTable.getInstance().getInfo(1322,1);
			addSkill(skill, true);
		}

		for(int i = 0; i < COMMON_CRAFT_LEVELS.length; i++)
		{
			if(lvl >= COMMON_CRAFT_LEVELS[i] && getSkillLevel(1320) < (i+1))
			{
				L2Skill skill = SkillTable.getInstance().getInfo(1320, (i+1));
				addSkill(skill, true);
			}
		}

		// Auto-Learn skills if activated
		if (Config.AUTO_LEARN_SKILLS)
		{
			giveAvailableSkills();
		}
		checkItemRestriction();
		sendSkillList(); 
	}

	/**
	 * Regive all skills which aren't saved to database, like Noble, Hero, Clan Skills<BR><BR>
	 *
	 */
	public void regiveTemporarySkills()
	{
		// Do not call this on enterworld or char load

		// Add noble skills if noble
		if (isNoble())
			setNoble(true);

		// Add Hero skills if hero
		if (isHero())
			setHero(true);

		// Add clan skills 
		if (getClan() != null)
		{
			L2Clan clan = getClan();
			if (clan.getReputationScore() >= 0)
			{
				L2Skill[] skills = getClan().getAllSkills();
				for (L2Skill sk : skills)
				{
					if(sk.getMinPledgeClass() <= getPledgeClass())
						addSkill(sk, false);
				}
			}
			if (clan.getLevel() >= SiegeManager.getInstance().getSiegeClanMinLevel() && isClanLeader())
				SiegeManager.getInstance().addSiegeSkills(this);
			if (getClan().getHasCastle() > 0)
				CastleManager.getInstance().getCastleByOwner(getClan()).giveResidentialSkills(this);
			if (getClan().getHasFort() > 0)
				FortManager.getInstance().getFortByOwner(getClan()).giveResidentialSkills(this);
		}
		
		// Reload passive skills from armors / jewels / weapons
		getInventory().reloadEquippedItems();
		
		// Add Death Penalty Buff Level
		restoreDeathPenaltyBuffLevel();
	}

	/**
	 * Give all available skills to the player.<br><br>
	 *
	 */
	private void giveAvailableSkills()
	{
		int unLearnable = 0;
		int skillCounter = 0;

		// Get available skills
		L2SkillLearn[] skills = SkillTreeTable.getInstance().getAvailableSkills(this, getClassId());
		while (skills.length > unLearnable)
		{
			for (L2SkillLearn s: skills)
			{
				L2Skill sk = SkillTable.getInstance().getInfo(s.getId(), s.getLevel());
				if (sk == null || (sk.getId() == L2Skill.SKILL_DIVINE_INSPIRATION && !Config.AUTO_LEARN_DIVINE_INSPIRATION))
				{
					unLearnable++;
					continue;
				}

				if (getSkillLevel(sk.getId()) == -1)
					skillCounter++;

				// fix when learning toggle skills
				if (sk.isToggle())
				{
					L2Effect toggleEffect = getFirstEffect(sk.getId());
					if (toggleEffect != null)
					{
						// stop old toggle skill effect, and give new toggle skill effect back
						toggleEffect.exit();
						sk.getEffects(this, this);
					}
				}

				addSkill(sk, true);
			}

			// Get new available skills
			skills = SkillTreeTable.getInstance().getAvailableSkills(this, getClassId());
		}

		sendMessage("You have learned " + skillCounter + " new skills.");
	}

	/** Set the Experience value of the L2PcInstance. */
	public void setExp(long exp)
	{
		if (exp < 0)
			exp = 0;
		
		getStat().setExp(exp);
	}

	/**
	 * Return the Race object of the L2PcInstance.<BR><BR>
	 */
	public Race getRace()
	{
		if (!isSubClassActive())
			return getTemplate().race;

		L2PcTemplate charTemp = CharTemplateTable.getInstance().getTemplate(_baseClass);
		return charTemp.race;
	}

    public L2Radar getRadar()
    {
        return _radar;
    }

	/** Return the SP amount of the L2PcInstance. */
	public int getSp() { return getStat().getSp(); }

	/** Set the SP amount of the L2PcInstance. */
	public void setSp(int sp)
	{
		if (sp < 0)
			sp = 0;
		
		super.getStat().setSp(sp);
	}

	/**
	 * Return true if this L2PcInstance is a clan leader in
	 * ownership of the passed castle
	 */
	public boolean isCastleLord(int castleId)
	{
		L2Clan clan = getClan();

		// player has clan and is the clan leader, check the castle info
		if ((clan != null) && (clan.getLeader().getPlayerInstance() == this))
		{
			// if the clan has a castle and it is actually the queried castle, return true
			Castle castle = CastleManager.getInstance().getCastleByOwner(clan);
			if ((castle != null) && (castle == CastleManager.getInstance().getCastleById(castleId)))
				return true;
		}

		return false;
	}
	/**
	 * Return the Clan Identifier of the L2PcInstance.<BR><BR>
	 */
	public int getClanId()
	{
		return _clanId;
	}

	/**
	 * Return the Clan Crest Identifier of the L2PcInstance or 0.<BR><BR>
	 */
	public int getClanCrestId()
	{
		if (_clan != null && _clan.hasCrest())
			return _clan.getCrestId();

		return 0;
	}

	/**
	 * @return The Clan CrestLarge Identifier or 0
	 */
	public int getClanCrestLargeId()
	{
		if (_clan != null && _clan.hasCrestLarge())
			return _clan.getCrestLargeId();

		return 0;
	}

	public long getClanJoinExpiryTime()
	{
		return _clanJoinExpiryTime;
	}

	public void setClanJoinExpiryTime(long time)
	{
		_clanJoinExpiryTime = time;
	}

	public long getClanCreateExpiryTime()
	{
		return _clanCreateExpiryTime;
	}

	public void setClanCreateExpiryTime(long time)
	{
		_clanCreateExpiryTime = time;
	}

	public void setOnlineTime(long time)
	{
		_onlineTime = time;
		_onlineBeginTime = System.currentTimeMillis();
	}

	/**
	 * Return the PcInventory Inventory of the L2PcInstance contained in _inventory.<BR><BR>
	 */
	@Override
	public PcInventory getInventory()
	{
		return _inventory;
	}

	/**
	 * Delete a ShortCut of the L2PcInstance _shortCuts.<BR><BR>
	 */
	public void removeItemFromShortCut(int objectId)
	{
		_shortCuts.deleteShortCutByObjectId(objectId);
	}

	/**
	 * Return True if the L2PcInstance is sitting.<BR><BR>
	 */
	public boolean isSitting()
	{
		return _waitTypeSitting;
	}

	/**
	 * Set _waitTypeSitting to given value
	 */
	public void setIsSitting(boolean state)
	{
		_waitTypeSitting = state;
	}
	/**
	 * Sit down the L2PcInstance, set the AI Intention to AI_INTENTION_REST and send a Server->Client ChangeWaitType packet (broadcast)<BR><BR>
	 */
	public void sitDown()
	{
		if ((isCastingNow() || isCastingSimultaneouslyNow()) && !_relax)
		{
			sendMessage("Cannot sit while casting");
			return;
		}

		if (!_waitTypeSitting && !isAttackingDisabled() && !isOutOfControl() && !isImmobilized())
		{
			breakAttack();
			setIsSitting(true);
			broadcastPacket(new ChangeWaitType (this, ChangeWaitType.WT_SITTING));
			// Schedule a sit down task to wait for the animation to finish
			ThreadPoolManager.getInstance().scheduleGeneral(new SitDownTask(this), 2500);
			setIsParalyzed(true);
		}
	}
	/**
	 * Sit down Task
	 */
	class SitDownTask implements Runnable
	{
		L2PcInstance _player;
		SitDownTask(L2PcInstance player)
		{
			_player = player;
		}
		public void run()
		{
			_player.setIsParalyzed(false);
			_player.getAI().setIntention(CtrlIntention.AI_INTENTION_REST);
		}
	}
	/**
	 * Stand up Task
	 */
	class StandUpTask implements Runnable
	{
		L2PcInstance _player;
		StandUpTask(L2PcInstance player)
		{
			_player = player;
		}
		public void run()
		{
			_player.setIsSitting(false);
			_player.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
		}
	}
	/**
	 * Stand up the L2PcInstance, set the AI Intention to AI_INTENTION_IDLE and send a Server->Client ChangeWaitType packet (broadcast)<BR><BR>
	 */
	public void standUp()
	{
		if (L2Event.active && eventSitForced)
		{
			sendMessage("A dark force beyond your mortal understanding makes your knees to shake when you try to stand up ...");
		}
		else if (_waitTypeSitting && !isInStoreMode() && !isAlikeDead())
		{
			if (_relax)
			{
				setRelax(false);
				stopEffects(L2EffectType.RELAXING);
			}

			broadcastPacket(new ChangeWaitType (this, ChangeWaitType.WT_STANDING));
			// Schedule a stand up task to wait for the animation to finish
			ThreadPoolManager.getInstance().scheduleGeneral(new StandUpTask(this), 2500);
		}
	}

	/**
	 * Set the value of the _relax value. Must be True if using skill Relax and False if not.
	 */
	public void setRelax(boolean val)
	{
		_relax = val;
	}

	/**
	 * Return the PcWarehouse object of the L2PcInstance.<BR><BR>
	 */
	public PcWarehouse getWarehouse()
	{
		if (_warehouse == null)
		{
			_warehouse = new PcWarehouse(this);
			_warehouse.restore();
		}
		if (Config.WAREHOUSE_CACHE)
			WarehouseCacheManager.getInstance().addCacheTask(this);
		return _warehouse;
	}

	/**
	 * Free memory used by Warehouse
	 */
	public void clearWarehouse()
	{
		if (_warehouse != null)
			_warehouse.deleteMe();
		_warehouse = null;
	}

	/**
	 * Returns true if refund list is not empty
	 */
	public boolean hasRefund()
	{
		return _refund != null && _refund.getSize() > 0 && Config.ALLOW_REFUND;
	}

	/**
	 * Returns refund object or create new if not exist
	 */
	public PcRefund getRefund()
	{
		if (_refund == null)
			_refund = new PcRefund(this);
		return _refund;
	}

	/**
	 * Clear refund
	 */
	public void clearRefund()
	{
		if (_refund != null)
			_refund.deleteMe();
		_refund = null;
	}

	/**
	 * Return the Identifier of the L2PcInstance.<BR><BR>
	 */
	public int getCharId()
	{
		return _charId;
	}

	/**
	 * Set the Identifier of the L2PcInstance.<BR><BR>
	 */
	public void setCharId(int charId)
	{
		_charId = charId;
	}

	/**
	 * Return the Adena amount of the L2PcInstance.<BR><BR>
	 */
	public long getAdena()
	{
		return _inventory.getAdena();
	}

    /**
     * Return the Ancient Adena amount of the L2PcInstance.<BR><BR>
     */
	public long getAncientAdena()
	{
	    return _inventory.getAncientAdena();
	}

	/**
	 * Add adena to Inventory of the L2PcInstance and send a Server->Client InventoryUpdate packet to the L2PcInstance.
	 * @param process : String Identifier of process triggering this action
	 * @param count : int Quantity of adena to be added
	 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
	 * @param sendMessage : boolean Specifies whether to send message to Client about this action
	 */
	public void addAdena(String process, long count, L2Object reference, boolean sendMessage)
	{
		if (sendMessage)
		{
			SystemMessage sm = new SystemMessage(SystemMessageId.EARNED_ADENA);
			sm.addItemNumber(count);
			sendPacket(sm);
		}

		if (count > 0)
		{
			_inventory.addAdena(process, count, this, reference);

			// Send update packet
			if (!Config.FORCE_INVENTORY_UPDATE)
			{
				InventoryUpdate iu = new InventoryUpdate();
				iu.addItem(_inventory.getAdenaInstance());
				sendPacket(iu);
			}
			else sendPacket(new ItemList(this, false));
		}
	}

	/**
	 * Reduce adena in Inventory of the L2PcInstance and send a Server->Client InventoryUpdate packet to the L2PcInstance.
	 * @param process : String Identifier of process triggering this action
	 * @param count : long Quantity of adena to be reduced
	 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
	 * @param sendMessage : boolean Specifies whether to send message to Client about this action
	 * @return boolean informing if the action was successfull
	 */
	public boolean reduceAdena(String process, long count, L2Object reference, boolean sendMessage)
	{
		if (count > getAdena())
		{
			if (sendMessage) sendPacket(new SystemMessage(SystemMessageId.YOU_NOT_ENOUGH_ADENA));
			return false;
		}

		if (count > 0)
		{
			L2ItemInstance adenaItem = _inventory.getAdenaInstance();
			_inventory.reduceAdena(process, count, this, reference);

			// Send update packet
			if (!Config.FORCE_INVENTORY_UPDATE)
			{
				InventoryUpdate iu = new InventoryUpdate();
				iu.addItem(adenaItem);
				sendPacket(iu);
			}
			else sendPacket(new ItemList(this, false));

			if (sendMessage)
			{
				SystemMessage sm = new SystemMessage(SystemMessageId.DISAPPEARED_ADENA);
				sm.addItemNumber(count);
				sendPacket(sm);
			}
		}

		return true;
	}

	/**
	 * Add ancient adena to Inventory of the L2PcInstance and send a Server->Client InventoryUpdate packet to the L2PcInstance.
	 *
	 * @param process : String Identifier of process triggering this action
	 * @param count : int Quantity of ancient adena to be added
	 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
	 * @param sendMessage : boolean Specifies whether to send message to Client about this action
	 */
	public void addAncientAdena(String process, long count, L2Object reference, boolean sendMessage)
	{
	    if (sendMessage)
	    {
	        SystemMessage sm = new SystemMessage(SystemMessageId.EARNED_S2_S1_S);
	        sm.addItemName(PcInventory.ANCIENT_ADENA_ID);
            sm.addItemNumber(count);
	        sendPacket(sm);
	    }

	    if (count > 0)
	    {
	        _inventory.addAncientAdena(process, count, this, reference);

	        if (!Config.FORCE_INVENTORY_UPDATE)
	        {
	            InventoryUpdate iu = new InventoryUpdate();
	            iu.addItem(_inventory.getAncientAdenaInstance());
	            sendPacket(iu);
	        }
	        else sendPacket(new ItemList(this, false));
	    }
	}

	/**
	 * Reduce ancient adena in Inventory of the L2PcInstance and send a Server->Client InventoryUpdate packet to the L2PcInstance.
	 * @param process : String Identifier of process triggering this action
	 * @param count : long Quantity of ancient adena to be reduced
	 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
	 * @param sendMessage : boolean Specifies whether to send message to Client about this action
	 * @return boolean informing if the action was successfull
	 */
	public boolean reduceAncientAdena(String process, long count, L2Object reference, boolean sendMessage)
	{
	    if (count > getAncientAdena())
	    {
	        if (sendMessage)
	            sendPacket(new SystemMessage(SystemMessageId.YOU_NOT_ENOUGH_ADENA));

	        return false;
	    }

	    if (count > 0)
	    {
	        L2ItemInstance ancientAdenaItem = _inventory.getAncientAdenaInstance();
	        _inventory.reduceAncientAdena(process, count, this, reference);

	        if (!Config.FORCE_INVENTORY_UPDATE)
	        {
	            InventoryUpdate iu = new InventoryUpdate();
	            iu.addItem(ancientAdenaItem);
	            sendPacket(iu);
	        }
	        else
	        {
	            sendPacket(new ItemList(this, false));
	        }

	        if (sendMessage)
	        {
	            SystemMessage sm = new SystemMessage(SystemMessageId.S2_S1_DISAPPEARED);
	            sm.addItemName(PcInventory.ANCIENT_ADENA_ID);
	            sm.addItemNumber(count);
	            sendPacket(sm);
	        }
	    }

	    return true;
	}

	/**
	 * Adds item to inventory and send a Server->Client InventoryUpdate packet to the L2PcInstance.
	 * @param process : String Identifier of process triggering this action
	 * @param item : L2ItemInstance to be added
	 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
	 * @param sendMessage : boolean Specifies whether to send message to Client about this action
	 */
	public void addItem(String process, L2ItemInstance item, L2Object reference, boolean sendMessage)
	{
		if (item.getCount() > 0)
		{
			// Sends message to client if requested
			if (sendMessage)
			{
				if (item.getCount() > 1)
				{
					SystemMessage sm = new SystemMessage(SystemMessageId.YOU_PICKED_UP_S1_S2);
					sm.addItemName(item);
					sm.addItemNumber(item.getCount());
					sendPacket(sm);
				}
				else if (item.getEnchantLevel() > 0)
				{
					SystemMessage sm = new SystemMessage(SystemMessageId.YOU_PICKED_UP_A_S1_S2);
					sm.addNumber(item.getEnchantLevel());
					sm.addItemName(item);
					sendPacket(sm);
				}
				else
				{
					SystemMessage sm = new SystemMessage(SystemMessageId.YOU_PICKED_UP_S1);
					sm.addItemName(item);
					sendPacket(sm);
				}
			}

			// Add the item to inventory
			L2ItemInstance newitem = _inventory.addItem(process, item, this, reference);

			// Send inventory update packet
			if (!Config.FORCE_INVENTORY_UPDATE)
			{
				InventoryUpdate playerIU = new InventoryUpdate();
				playerIU.addItem(newitem);
				sendPacket(playerIU);
			}
			else
			{
			    sendPacket(new ItemList(this, false));
			}

			// Update current load as well
			StatusUpdate su = new StatusUpdate(getObjectId());
			su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
			sendPacket(su);

            // If over capacity, drop the item
            if (!isGM() && !_inventory.validateCapacity(0) && newitem.isDropable())
                dropItem("InvDrop", newitem, null, true);

			// Cursed Weapon
            else if(CursedWeaponsManager.getInstance().isCursed(newitem.getItemId()))
			{
				CursedWeaponsManager.getInstance().activate(this, newitem);
			}
			
			// Combat Flag
            else if(FortSiegeManager.getInstance().isCombat(item.getItemId()))
            {
            	if(FortSiegeManager.getInstance().activateCombatFlag(this, item))
            	{
            		Fort fort = FortManager.getInstance().getFort(this);
            		fort.getSiege().announceToPlayer(new SystemMessage(SystemMessageId.C1_ACQUIRED_THE_FLAG), this.getName());
            	}
            }
		}
	}

	/**
	 * Adds item to Inventory and send a Server->Client InventoryUpdate packet to the L2PcInstance.
	 * @param process : String Identifier of process triggering this action
	 * @param itemId : int Item Identifier of the item to be added
	 * @param count : long Quantity of items to be added
	 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
	 * @param sendMessage : boolean Specifies whether to send message to Client about this action
	 */
	public void addItem(String process, int itemId, long count, L2Object reference, boolean sendMessage)
	{
		if (count > 0)
		{
			L2ItemInstance item = null;
			if(ItemTable.getInstance().getTemplate(itemId) != null)
			{
				item = ItemTable.getInstance().createDummyItem(itemId);
			}
			else
			{
				_log.log(Level.SEVERE, "Item doesn't exist so cannot be added. Item ID: " + itemId);
				return;
			}
			// Sends message to client if requested
			if (sendMessage && ((!isCastingNow() && item.getItemType() == L2EtcItemType.HERB)
					|| item.getItemType() != L2EtcItemType.HERB))
			{
				if (count > 1)
				{
					if (process.equalsIgnoreCase("sweep") || process.equalsIgnoreCase("Quest"))
					{
						SystemMessage sm = new SystemMessage(SystemMessageId.EARNED_S2_S1_S);
						sm.addItemName(itemId);
						sm.addItemNumber(count);
						sendPacket(sm);
					}
					else
					{
						SystemMessage sm = new SystemMessage(SystemMessageId.YOU_PICKED_UP_S1_S2);
						sm.addItemName(itemId);
						sm.addItemNumber(count);
						sendPacket(sm);
					}
				}
				else
				{
					if (process.equalsIgnoreCase("sweep") || process.equalsIgnoreCase("Quest"))
					{
						SystemMessage sm = new SystemMessage(SystemMessageId.EARNED_ITEM);
						sm.addItemName(itemId);
						sendPacket(sm);
					}
					else
					{
						SystemMessage sm = new SystemMessage(SystemMessageId.YOU_PICKED_UP_S1);
						sm.addItemName(itemId);
						sendPacket(sm);
					}
				}
			}
			//Auto use herbs - autoloot
			if (item.getItemType() == L2EtcItemType.HERB) //If item is herb dont add it to iv :]
			{
				if(!isCastingNow())
				{
					L2ItemInstance herb = new L2ItemInstance(_charId, itemId);
					IItemHandler handler = ItemHandler.getInstance().getItemHandler(herb.getEtcItem());
					if (handler == null)
						_log.warning("No item handler registered for Herb - item ID " + herb.getItemId() + ".");
					else
					{
						handler.useItem(this, herb);
						if(_herbstask>=100)
							_herbstask -=100;
					}
				}
				else
				{
					_herbstask += 100;
					ThreadPoolManager.getInstance().scheduleAi(new HerbTask(process, itemId, count, reference, sendMessage), _herbstask);
				}
			}
			else
			{
				// Add the item to inventory
				L2ItemInstance createdItem = _inventory.addItem(process, itemId, count, this, reference);

				// If over capacity, drop the item
				if (!isGM() && !_inventory.validateCapacity(0) && createdItem.isDropable())
					dropItem("InvDrop", createdItem, null, true);

				// Cursed Weapon
				else if(CursedWeaponsManager.getInstance().isCursed(createdItem.getItemId()))
					CursedWeaponsManager.getInstance().activate(this, createdItem);

				// Combat Flag
				else if(FortSiegeManager.getInstance().isCombat(createdItem.getItemId()))
				{
					if( FortSiegeManager.getInstance().activateCombatFlag(this, item))
					{
						Fort fort = FortManager.getInstance().getFort(this);
						fort.getSiege().announceToPlayer(new SystemMessage(SystemMessageId.C1_ACQUIRED_THE_FLAG), this.getName());
					}
				}
			}
		}
	}

	/**
	 * Destroy item from inventory and send a Server->Client InventoryUpdate packet to the L2PcInstance.
	 * @param process : String Identifier of process triggering this action
	 * @param item : L2ItemInstance to be destroyed
	 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
	 * @param sendMessage : boolean Specifies whether to send message to Client about this action
	 * @return boolean informing if the action was successfull
	 */
	public boolean destroyItem(String process, L2ItemInstance item, L2Object reference, boolean sendMessage)
	{
		return this.destroyItem(process, item, item.getCount(), reference, sendMessage);
	}
    
    /**
     * Destroy item from inventory and send a Server->Client InventoryUpdate packet to the L2PcInstance.
     * @param process : String Identifier of process triggering this action
     * @param item : L2ItemInstance to be destroyed
     * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
     * @param sendMessage : boolean Specifies whether to send message to Client about this action
     * @return boolean informing if the action was successfull
     */
    public boolean destroyItem(String process, L2ItemInstance item, long count, L2Object reference, boolean sendMessage)
    {
        item = _inventory.destroyItem(process, item, count, this, reference);

        if (item == null)
        {
            if (sendMessage)
            {
                sendPacket(new SystemMessage(SystemMessageId.NOT_ENOUGH_ITEMS));
            }
            return false;
        }

        // Send inventory update packet
        if (!Config.FORCE_INVENTORY_UPDATE)
        {
            InventoryUpdate playerIU = new InventoryUpdate();
            playerIU.addItem(item);
            sendPacket(playerIU);
        }
        else 
        {
            sendPacket(new ItemList(this, false));
        }

        // Update current load as well
        StatusUpdate su = new StatusUpdate(getObjectId());
        su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
        sendPacket(su);

        // Sends message to client if requested
        if (sendMessage)
        {
            SystemMessage sm = new SystemMessage(SystemMessageId.S2_S1_DISAPPEARED);
            sm.addItemName(item);
            sm.addItemNumber(count);
            sendPacket(sm);
        }

        return true;
    }

	/**
	 * Destroys item from inventory and send a Server->Client InventoryUpdate packet to the L2PcInstance.
	 * @param process : String Identifier of process triggering this action
	 * @param objectId : int Item Instance identifier of the item to be destroyed
	 * @param count : int Quantity of items to be destroyed
	 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
	 * @param sendMessage : boolean Specifies whether to send message to Client about this action
	 * @return boolean informing if the action was successfull
	 */
	@Override
	public boolean destroyItem(String process, int objectId, long count, L2Object reference, boolean sendMessage)
	{
        L2ItemInstance item = _inventory.getItemByObjectId(objectId);

		if (item == null)
		{
			if (sendMessage)
            {
                sendPacket(new SystemMessage(SystemMessageId.NOT_ENOUGH_ITEMS));
            }
            
			return false;
		}
        return this.destroyItem(process, item, count, reference, sendMessage);
	}

	/**
	 * Destroys shots from inventory without logging and only occasional saving to database.
	 * Sends a Server->Client InventoryUpdate packet to the L2PcInstance.
	 * @param process : String Identifier of process triggering this action
	 * @param objectId : int Item Instance identifier of the item to be destroyed
	 * @param count : int Quantity of items to be destroyed
	 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
	 * @param sendMessage : boolean Specifies whether to send message to Client about this action
	 * @return boolean informing if the action was successfull
	 */
	public boolean destroyItemWithoutTrace(String process, int objectId, long count, L2Object reference, boolean sendMessage)
	{
        L2ItemInstance item = _inventory.getItemByObjectId(objectId);

        if (item == null || item.getCount() < count)
		{
			if (sendMessage)
            {
                sendPacket(new SystemMessage(SystemMessageId.NOT_ENOUGH_ITEMS));
            }
            
			return false;
		}
        
        return this.destroyItem(null, item, count, reference, sendMessage);
	}

	/**
	 * Destroy item from inventory by using its <B>itemId</B> and send a Server->Client InventoryUpdate packet to the L2PcInstance.
	 * @param process : String Identifier of process triggering this action
	 * @param itemId : int Item identifier of the item to be destroyed
	 * @param count : int Quantity of items to be destroyed
	 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
	 * @param sendMessage : boolean Specifies whether to send message to Client about this action
	 * @return boolean informing if the action was successfull
	 */
	@Override
	public boolean destroyItemByItemId(String process, int itemId, long count, L2Object reference, boolean sendMessage)
	{
        L2ItemInstance item = _inventory.getItemByItemId(itemId);

        if (item == null || item.getCount() < count || _inventory.destroyItemByItemId(process, itemId, count, this, reference) == null)
		{
			if (sendMessage)
                sendPacket(new SystemMessage(SystemMessageId.NOT_ENOUGH_ITEMS));

			return false;
		}

		// Send inventory update packet
		if (!Config.FORCE_INVENTORY_UPDATE)
		{
			InventoryUpdate playerIU = new InventoryUpdate();
			playerIU.addItem(item);
			sendPacket(playerIU);
		}
        else sendPacket(new ItemList(this, false));

		// Update current load as well
		StatusUpdate su = new StatusUpdate(getObjectId());
		su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
		sendPacket(su);

		// Sends message to client if requested
		if (sendMessage)
		{
			SystemMessage sm = new SystemMessage(SystemMessageId.S2_S1_DISAPPEARED);
            sm.addItemName(itemId);
            sm.addItemNumber(count);
			sendPacket(sm);
		}

		return true;
	}

	/**
	 * Destroy all weared items from inventory and send a Server->Client InventoryUpdate packet to the L2PcInstance.
	 * @param process : String Identifier of process triggering this action
	 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
	 * @param sendMessage : boolean Specifies whether to send message to Client about this action
	 * @return boolean informing if the action was successfull
	 */
	public void destroyWearedItems(String process, L2Object reference, boolean sendMessage)
	{

        // Go through all Items of the inventory
        for (L2ItemInstance item : getInventory().getItems())
		{
            // Check if the item is a Try On item in order to remove it
			if (item.isWear())
			{
                if (item.isEquipped())
                    getInventory().unEquipItemInSlotAndRecord(item.getLocationSlot());

				if (_inventory.destroyItem(process, item, this, reference) == null)
				{
					_log.warning("Player " + getName() + " can't destroy weared item: " + item.getName() + "[ " + item.getObjectId() + " ]");
					continue;
				}

				// Send an Unequipped Message in system window of the player for each Item
				SystemMessage sm = new SystemMessage(SystemMessageId.S1_DISARMED);
				sm.addItemName(item);
				sendPacket(sm);

			}
		}


        // Send the StatusUpdate Server->Client Packet to the player with new CUR_LOAD (0x0e) information
		StatusUpdate su = new StatusUpdate(getObjectId());
		su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
		sendPacket(su);

        // Send the ItemList Server->Client Packet to the player in order to refresh its Inventory
        ItemList il = new ItemList(getInventory().getItems(), true);
        sendPacket(il);

        // Send a Server->Client packet UserInfo to this L2PcInstance and CharInfo to all L2PcInstance in its _KnownPlayers
		broadcastUserInfo();

		// Sends message to client if requested
		sendMessage("Trying-on mode has ended.");

	}

	/**
	 * Transfers item to another ItemContainer and send a Server->Client InventoryUpdate packet to the L2PcInstance.
	 * @param process : String Identifier of process triggering this action
	 * @param itemId : int Item Identifier of the item to be transfered
	 * @param count : long Quantity of items to be transfered
	 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
	 * @return L2ItemInstance corresponding to the new item or the updated item in inventory
	 */
	public L2ItemInstance transferItem(String process, int objectId, long count, Inventory target, L2Object reference)
	{
		L2ItemInstance oldItem = checkItemManipulation(objectId, count, "transfer");
		if (oldItem == null) return null;
		L2ItemInstance newItem = getInventory().transferItem(process, objectId, count, target, this, reference);
		if (newItem == null) return null;

		// Send inventory update packet
		if (!Config.FORCE_INVENTORY_UPDATE)
		{
			InventoryUpdate playerIU = new InventoryUpdate();

			if (oldItem.getCount() > 0 && oldItem != newItem)
                playerIU.addModifiedItem(oldItem);
			else
                playerIU.addRemovedItem(oldItem);

			sendPacket(playerIU);
		}
		else sendPacket(new ItemList(this, false));

		// Update current load as well
		StatusUpdate playerSU = new StatusUpdate(getObjectId());
		playerSU.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
		sendPacket(playerSU);

		// Send target update packet
		if (target instanceof PcInventory)
		{
			L2PcInstance targetPlayer = ((PcInventory)target).getOwner();

			if (!Config.FORCE_INVENTORY_UPDATE)
			{
				InventoryUpdate playerIU = new InventoryUpdate();

				if (newItem.getCount() > count)
                    playerIU.addModifiedItem(newItem);
				else
                    playerIU.addNewItem(newItem);

				targetPlayer.sendPacket(playerIU);
			}
			else targetPlayer.sendPacket(new ItemList(targetPlayer, false));

			// Update current load as well
			playerSU = new StatusUpdate(targetPlayer.getObjectId());
			playerSU.addAttribute(StatusUpdate.CUR_LOAD, targetPlayer.getCurrentLoad());
			targetPlayer.sendPacket(playerSU);
		}
		else if (target instanceof PetInventory)
		{
			PetInventoryUpdate petIU = new PetInventoryUpdate();

			if (newItem.getCount() > count)
                petIU.addModifiedItem(newItem);
			else
                petIU.addNewItem(newItem);

			((PetInventory)target).getOwner().getOwner().sendPacket(petIU);
			getPet().getInventory().refreshWeight();
		}
		return newItem;
	}

	/**
	 * Drop item from inventory and send a Server->Client InventoryUpdate packet to the L2PcInstance.
	 * @param process : String Identifier of process triggering this action
	 * @param item : L2ItemInstance to be dropped
	 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
	 * @param sendMessage : boolean Specifies whether to send message to Client about this action
	 * @return boolean informing if the action was successfull
	 */
	public boolean dropItem(String process, L2ItemInstance item, L2Object reference, boolean sendMessage)
	{
		item = _inventory.dropItem(process, item, this, reference);

		if (item == null)
		{
			if (sendMessage)
                sendPacket(new SystemMessage(SystemMessageId.NOT_ENOUGH_ITEMS));

			return false;
		}

		item.dropMe(this, getX() + Rnd.get(50) - 25, getY() + Rnd.get(50) - 25, getZ() + 20);

		 if (Config.AUTODESTROY_ITEM_AFTER >0 && Config.DESTROY_DROPPED_PLAYER_ITEM && !Config.LIST_PROTECTED_ITEMS.contains(item.getItemId()))
			 {
			 if ( (item.isEquipable() && Config.DESTROY_EQUIPABLE_PLAYER_ITEM) || !item.isEquipable())
			 ItemsAutoDestroy.getInstance().addItem(item);
			 }
		 if (Config.DESTROY_DROPPED_PLAYER_ITEM){
		 	if (!item.isEquipable() || (item.isEquipable()  && Config.DESTROY_EQUIPABLE_PLAYER_ITEM ))
		 		item.setProtected(false);
			else
				item.setProtected(true);
		 	}
	   		else
	   			item.setProtected(true);

		// Send inventory update packet
		if (!Config.FORCE_INVENTORY_UPDATE)
		{
			InventoryUpdate playerIU = new InventoryUpdate();
			playerIU.addItem(item);
			sendPacket(playerIU);
		}
		else sendPacket(new ItemList(this, false));

		// Update current load as well
		StatusUpdate su = new StatusUpdate(getObjectId());
		su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
		sendPacket(su);

		// Sends message to client if requested
		if (sendMessage)
		{
			SystemMessage sm = new SystemMessage(SystemMessageId.YOU_DROPPED_S1);
			sm.addItemName(item);
			sendPacket(sm);
		}

		return true;
	}

	/**
	 * Drop item from inventory by using its <B>objectID</B> and send a Server->Client InventoryUpdate packet to the L2PcInstance.
	 * @param process : String Identifier of process triggering this action
	 * @param objectId : int Item Instance identifier of the item to be dropped
	 * @param count : long Quantity of items to be dropped
	 * @param x : int coordinate for drop X
	 * @param y : int coordinate for drop Y
	 * @param z : int coordinate for drop Z
	 * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
	 * @param sendMessage : boolean Specifies whether to send message to Client about this action
	 * @return L2ItemInstance corresponding to the new item or the updated item in inventory
	 */
	public L2ItemInstance dropItem(String process, int objectId, long count, int x, int y, int z, L2Object reference, boolean sendMessage)
	{
		L2ItemInstance invitem = _inventory.getItemByObjectId(objectId);
		L2ItemInstance item = _inventory.dropItem(process, objectId, count, this, reference);

		if (item == null)
		{
			if (sendMessage)
                sendPacket(new SystemMessage(SystemMessageId.NOT_ENOUGH_ITEMS));

			return null;
		}

		item.dropMe(this, x, y, z);

		 if (Config.AUTODESTROY_ITEM_AFTER >0 && Config.DESTROY_DROPPED_PLAYER_ITEM && !Config.LIST_PROTECTED_ITEMS.contains(item.getItemId()))
			 {
			 if ( (item.isEquipable() && Config.DESTROY_EQUIPABLE_PLAYER_ITEM) || !item.isEquipable())
			 ItemsAutoDestroy.getInstance().addItem(item);
			 }
		 if (Config.DESTROY_DROPPED_PLAYER_ITEM){
		 	if (!item.isEquipable() || (item.isEquipable()  && Config.DESTROY_EQUIPABLE_PLAYER_ITEM ))
		 		item.setProtected(false);
		 	else
		 		item.setProtected(true);
		 }
	   	 else
	   		 item.setProtected(true);

		// Send inventory update packet
		if (!Config.FORCE_INVENTORY_UPDATE)
		{
			InventoryUpdate playerIU = new InventoryUpdate();
			playerIU.addItem(invitem);
			sendPacket(playerIU);
		}
		else
		{
		    sendPacket(new ItemList(this, false));
		}

		// Update current load as well
		StatusUpdate su = new StatusUpdate(getObjectId());
		su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
		sendPacket(su);

		// Sends message to client if requested
		if (sendMessage)
		{
			SystemMessage sm = new SystemMessage(SystemMessageId.YOU_DROPPED_S1);
			sm.addItemName(item);
			sendPacket(sm);
		}

		return item;
	}

	public L2ItemInstance checkItemManipulation(int objectId, long count, String action)
	{
        //TODO: if we remove objects that are not visisble from the L2World, we'll have to remove this check
		if (L2World.getInstance().findObject(objectId) == null)
		{
			_log.finest(getObjectId()+": player tried to " + action + " item not available in L2World");
			return null;
		}

		L2ItemInstance item = getInventory().getItemByObjectId(objectId);

		if (item == null || item.getOwnerId() != getObjectId())
		{
			_log.finest(getObjectId()+": player tried to " + action + " item he is not owner of");
			return null;
		}

		if (count < 0 || (count > 1 && !item.isStackable()))
		{
			_log.finest(getObjectId()+": player tried to " + action + " item with invalid count: "+ count);
			return null;
		}

		if (count > item.getCount())
		{
			_log.finest(getObjectId()+": player tried to " + action + " more items than he owns");
			return null;
		}

		// Pet is summoned and not the item that summoned the pet AND not the buggle from strider you're mounting
		if (getPet() != null && getPet().getControlItemId() == objectId || getMountObjectID() == objectId)
		{
			if (Config.DEBUG)
				_log.finest(getObjectId()+": player tried to " + action + " item controling pet");

			return null;
		}

		if (getActiveEnchantItem() != null && getActiveEnchantItem().getObjectId() == objectId)
		{
			if (Config.DEBUG)
				_log.finest(getObjectId()+":player tried to " + action + " an enchant scroll he was using");

			return null;
		}

		if (item.isWear())
		{
			// cannot drop/trade wear-items
			return null;
		}
		
		// We cannot put a Weapon with Augmention in WH while casting (Possible Exploit)
		if (item.isAugmented() && (isCastingNow() || this.isCastingSimultaneouslyNow()))
			return null;

		return item;
	}

	/**
	 * Set _protectEndTime according settings.
	 */
	public void setProtection(boolean protect)
	{
		if (Config.DEVELOPER && (protect || _protectEndTime > 0))
            _log.warning(getName() + ": Protection " + (protect?"ON " + (GameTimeController.getGameTicks() + Config.PLAYER_SPAWN_PROTECTION * GameTimeController.TICKS_PER_SECOND) :"OFF") + " (currently " + GameTimeController.getGameTicks() + ")");

		_protectEndTime = protect ? GameTimeController.getGameTicks() + Config.PLAYER_SPAWN_PROTECTION * GameTimeController.TICKS_PER_SECOND : 0;
	}

	/**
	 * Set protection from agro mobs when getting up from fake death, according settings.
	 */
	public void setRecentFakeDeath(boolean protect)
	{
		_recentFakeDeathEndTime = protect ? GameTimeController.getGameTicks() + Config.PLAYER_FAKEDEATH_UP_PROTECTION * GameTimeController.TICKS_PER_SECOND : 0;
	}

	public boolean isRecentFakeDeath()
	{
		return _recentFakeDeathEndTime > GameTimeController.getGameTicks();
	}
	
	public final boolean isFakeDeath()
	{
		return _isFakeDeath;
	}
	
	public final void setIsFakeDeath(boolean value)
	{
		_isFakeDeath = value;
	}
	
	@Override
	public final boolean isAlikeDead()
	{
		if (super.isAlikeDead())
			return true;
		
		return isFakeDeath();
	}

	/**
	 * Get the client owner of this char.<BR><BR>
	 */
	public L2GameClient getClient()
	{
		return _client;
	}

	public void setClient(L2GameClient client)
	{
		_client = client;
	}

	/**
	 * Close the active connection with the client.<BR><BR>
	 */
	public void closeNetConnection(boolean closeClient)
	{
		L2GameClient client = _client;
		if (client != null)
		{
			if (client.isDetached())
			{
				client.cleanMe(true);
			}
			else
			{
				if (!client.getConnection().isClosed())
				{
					if (closeClient)
						client.close(new LeaveWorld());
					else
						client.close(new ServerClose());
				}
			}
		}
	}
	
	public Point3D getCurrentSkillWorldPosition()
	{
		return _currentSkillWorldPosition;
	}
	 
	public void setCurrentSkillWorldPosition(Point3D worldPosition)
	{
		_currentSkillWorldPosition = worldPosition;
	}
	
	/**
	 * 
	 * @see com.l2jserver.gameserver.model.actor.L2Character#checkDoCastConditions(com.l2jserver.gameserver.model.L2Skill)
	 */
	@Override
	protected boolean checkDoCastConditions(L2Skill skill)
	{
		if (!super.checkDoCastConditions(skill))
			return false;

		switch (skill.getSkillType())
		{
			case SUMMON_TRAP:
			{
				if (isInsideZone(ZONE_PEACE))
				{
					sendPacket(new SystemMessage(SystemMessageId.A_MALICIOUS_SKILL_CANNOT_BE_USED_IN_PEACE_ZONE));
					return false;
				}
				if (getTrap() != null
						&& getTrap().getSkill().getId() == ((L2SkillTrap)skill).getTriggerSkillId())
				{
					SystemMessage sm = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
					sm.addSkillName(skill);
					sendPacket(sm);
					return false;
				}
				break;
			}
			case SUMMON:
			{
				if (!((L2SkillSummon)skill).isCubic() && (getPet() != null || isMounted()))
				{
					if (Config.DEBUG)
						_log.fine("player has a pet already. ignore summon skill");
					
					sendPacket(new SystemMessage(SystemMessageId.YOU_ALREADY_HAVE_A_PET));
					return false;
				}
			}
		}

		// TODO: Should possibly be checked only in L2PcInstance's useMagic
		// Can't use Hero and resurrect skills during Olympiad
		if (isInOlympiadMode() &&
				(skill.isHeroSkill() || skill.getSkillType() == L2SkillType.RESURRECT))
		{
			SystemMessage sm = new SystemMessage(SystemMessageId.THIS_SKILL_IS_NOT_AVAILABLE_FOR_THE_OLYMPIAD_EVENT);
			sendPacket(sm);
			return false;
		}

		final int charges = getCharges();
		// Check if the spell using charges or not in AirShip
		if ((skill.getMaxCharges() == 0 && charges < skill.getNumCharges())
				|| isInAirShip())
		{
			SystemMessage sm = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
			sm.addSkillName(skill);
			sendPacket(sm);
			return false;
		}

		return true;
	}

	/**
	 * Manage actions when a player click on this L2PcInstance.<BR><BR>
	 *
	 * <B><U> Actions on first click on the L2PcInstance (Select it)</U> :</B><BR><BR>
	 * <li>Set the target of the player</li>
	 * <li>Send a Server->Client packet MyTargetSelected to the player (display the select window)</li><BR><BR>
	 *
	 * <B><U> Actions on second click on the L2PcInstance (Follow it/Attack it/Intercat with it)</U> :</B><BR><BR>
	 * <li>Send a Server->Client packet MyTargetSelected to the player (display the select window)</li>
	 * <li>If this L2PcInstance has a Private Store, notify the player AI with AI_INTENTION_INTERACT</li>
	 * <li>If this L2PcInstance is autoAttackable, notify the player AI with AI_INTENTION_ATTACK</li><BR><BR>
	 * <li>If this L2PcInstance is NOT autoAttackable, notify the player AI with AI_INTENTION_FOLLOW</li><BR><BR>
	 *
	 * <B><U> Example of use </U> :</B><BR><BR>
	 * <li> Client packet : Action, AttackRequest</li><BR><BR>
	 *
	 * @param player The player that start an action on this L2PcInstance
	 *
	 */

	public void onAction(L2PcInstance player, boolean interact)
	{
		// See description in TvTEvent.java
		if (!TvTEvent.onAction( player, getObjectId()))
		{
			player.sendPacket(ActionFailed.STATIC_PACKET);
			return;
		}

		// Check if the L2PcInstance is confused
		if (player.isOutOfControl())
		{
			// Send a Server->Client packet ActionFailed to the player
			player.sendPacket(ActionFailed.STATIC_PACKET);
			return;
		}

		// Aggression target lock effect
		if (player.isLockedTarget() && player.getLockedTarget() != this)
		{
			player.sendPacket(new SystemMessage(SystemMessageId.FAILED_CHANGE_TARGET));
			player.sendPacket(ActionFailed.STATIC_PACKET);
			return;
		}

		// Check if the player already target this L2PcInstance
		if (player.getTarget() != this)
		{
			// Set the target of the player
			player.setTarget(this);

			// Send a Server->Client packet MyTargetSelected to the player
			// The color to display in the select window is White
			player.sendPacket(new MyTargetSelected(getObjectId(), 0));
			if (player != this) player.sendPacket(new ValidateLocation(this));
		}
		else if (interact)
		{
			if (player != this) player.sendPacket(new ValidateLocation(this));
			// Check if this L2PcInstance has a Private Store
			if (getPrivateStoreType() != 0)
            {
				player.getAI().setIntention(CtrlIntention.AI_INTENTION_INTERACT, this);
            }
			else
			{
				// Check if this L2PcInstance is autoAttackable
				if (isAutoAttackable(player))
				{
					// Player with lvl < 21 can't attack a cursed weapon holder
					// And a cursed weapon holder  can't attack players with lvl < 21
					if ((isCursedWeaponEquipped() && player.getLevel() < 21)
							|| (player.isCursedWeaponEquipped() && getLevel() < 21))
					{
						player.sendPacket(ActionFailed.STATIC_PACKET);
					} else
					{
						if (Config.GEODATA > 0)
						{
							if (GeoData.getInstance().canSeeTarget(player, this))
							{
								player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
								player.onActionRequest();
							}
						}
						else
						{
							player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
							player.onActionRequest();
						}
					}
				} else
				{
					// This Action Failed packet avoids player getting stuck when clicking three or more times
					player.sendPacket(ActionFailed.STATIC_PACKET);
					if (Config.GEODATA > 0)
					{
						if(GeoData.getInstance().canSeeTarget(player, this))
							player.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, this);
					}
					else
						player.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, this);
				}
			}
		}
		player.sendPacket(ActionFailed.STATIC_PACKET);
	}
	
	@Override
	public void onActionShift(L2PcInstance player)
	{
		if (player == null)
			return;
		
		if (player.isGM())
		{
			// Check if the gm already target this l2pcinstance
			if (player.getTarget() != this)
			{
				// Set the target of the L2PcInstance player
				player.setTarget(this);
				
				// Send a Server->Client packet MyTargetSelected to the L2PcInstance player
				player.sendPacket(new MyTargetSelected(getObjectId(), 0));
			}
			
			// Send a Server->Client packet ValidateLocation to correct the L2PcInstance position and heading on the client
			if (player != this)
				player.sendPacket(new ValidateLocation(this));
			
			IAdminCommandHandler ach = AdminCommandHandler.getInstance().getAdminCommandHandler("admin_character_info");
			if (ach != null)
				ach.useAdminCommand("admin_character_info " + getName(), player);
		}
		player.sendPacket(ActionFailed.STATIC_PACKET);
	}
	
	/**
	 * Returns true if cp update should be done, false if not
	 * @return boolean
	 */
	private boolean needCpUpdate(int barPixels)
	{
		double currentCp = getCurrentCp();

	    if (currentCp <= 1.0 || getMaxCp() < barPixels)
	        return true;

	    if (currentCp <= _cpUpdateDecCheck || currentCp >= _cpUpdateIncCheck)
	    {
	    	if (currentCp == getMaxCp())
	    	{
	    		_cpUpdateIncCheck = currentCp + 1;
	    		_cpUpdateDecCheck = currentCp - _cpUpdateInterval;
	    	}
	    	else
	    	{
	    		double doubleMulti = currentCp / _cpUpdateInterval;
		    	int intMulti = (int)doubleMulti;

	    		_cpUpdateDecCheck = _cpUpdateInterval * (doubleMulti < intMulti ? intMulti-- : intMulti);
	    		_cpUpdateIncCheck = _cpUpdateDecCheck + _cpUpdateInterval;
	    	}

	    	return true;
	    }

	    return false;
	}

	/**
	 * Returns true if mp update should be done, false if not
	 * @return boolean
	 */
	private boolean needMpUpdate(int barPixels)
	{
		double currentMp = getCurrentMp();

	    if (currentMp <= 1.0 || getMaxMp() < barPixels)
	        return true;

	    if (currentMp <= _mpUpdateDecCheck || currentMp >= _mpUpdateIncCheck)
	    {
	    	if (currentMp == getMaxMp())
	    	{
	    		_mpUpdateIncCheck = currentMp + 1;
	    		_mpUpdateDecCheck = currentMp - _mpUpdateInterval;
	    	}
	    	else
	    	{
	    		double doubleMulti = currentMp / _mpUpdateInterval;
		    	int intMulti = (int)doubleMulti;

	    		_mpUpdateDecCheck = _mpUpdateInterval * (doubleMulti < intMulti ? intMulti-- : intMulti);
	    		_mpUpdateIncCheck = _mpUpdateDecCheck + _mpUpdateInterval;
	    	}

	    	return true;
	    }

	    return false;
	}

	/**
	 * Send packet StatusUpdate with current HP,MP and CP to the L2PcInstance and only current HP, MP and Level to all other L2PcInstance of the Party.<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Send the Server->Client packet StatusUpdate with current HP, MP and CP to this L2PcInstance </li><BR>
	 * <li>Send the Server->Client packet PartySmallWindowUpdate with current HP, MP and Level to all other L2PcInstance of the Party </li><BR><BR>
	 *
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND current HP and MP to all L2PcInstance of the _statusListener</B></FONT><BR><BR>
	 *
	 */
	@Override
	public void broadcastStatusUpdate()
	{
		//TODO We mustn't send these informations to other players
		// Send the Server->Client packet StatusUpdate with current HP and MP to all L2PcInstance that must be informed of HP/MP updates of this L2PcInstance
		//super.broadcastStatusUpdate();

		// Send the Server->Client packet StatusUpdate with current HP, MP and CP to this L2PcInstance
		StatusUpdate su = new StatusUpdate(getObjectId());
		su.addAttribute(StatusUpdate.CUR_HP, (int) getCurrentHp());
		su.addAttribute(StatusUpdate.CUR_MP, (int) getCurrentMp());
		su.addAttribute(StatusUpdate.CUR_CP, (int) getCurrentCp());
		su.addAttribute(StatusUpdate.MAX_CP, 	   getMaxCp());
		sendPacket(su);

		final boolean needCpUpdate = needCpUpdate(352);
		final boolean needHpUpdate = needHpUpdate(352);
		// Check if a party is in progress and party window update is usefull
		if (isInParty()
				&& (needCpUpdate
						|| needHpUpdate
						|| needMpUpdate(352)))
		{
			if (Config.DEBUG)
				_log.fine("Send status for party window of " + getObjectId() + "(" + getName() + ") to his party. CP: " + getCurrentCp() + " HP: " + getCurrentHp() + " MP: " + getCurrentMp());
			// Send the Server->Client packet PartySmallWindowUpdate with current HP, MP and Level to all other L2PcInstance of the Party
			PartySmallWindowUpdate update = new PartySmallWindowUpdate(this);
			getParty().broadcastToPartyMembers(this, update);
		}

        if (isInOlympiadMode()
        		&& isOlympiadStart()
        		&& (needCpUpdate || needHpUpdate))
        {
        	Collection<L2PcInstance> players = getKnownList().getKnownPlayers().values();

        	//synchronized (getKnownList().getKnownPlayers())
        	if (players != null && !players.isEmpty())
			{
            	ExOlympiadUserInfo olyInfo = new ExOlympiadUserInfo(this, 2);

            	for (L2PcInstance player : players)
				{
					if (player != null
							&& player.isInOlympiadMode()
							&& player.getOlympiadGameId() == _olympiadGameId)
					{
						player.sendPacket(olyInfo);
					}
				}
			}

        	players = Olympiad.getInstance().getSpectators(_olympiadGameId);
            if(players != null && !players.isEmpty())
            {
            	ExOlympiadUserInfo olyInfo = new ExOlympiadUserInfo(this, getOlympiadSide());

            	for(L2PcInstance spectator : players)
                {
                    if (spectator == null)
                    	continue;
                    spectator.sendPacket(olyInfo);
                }
            }
        }
        // In duel MP updated only with CP or HP
        if (isInDuel()
        		&& (needCpUpdate || needHpUpdate))
        {
        	ExDuelUpdateUserInfo update = new ExDuelUpdateUserInfo(this);
        	DuelManager.getInstance().broadcastToOppositTeam(this, update);
        }
	}
    
	/**
	 * Send a Server->Client packet UserInfo to this L2PcInstance and CharInfo to all L2PcInstance in its _KnownPlayers.<BR><BR>
	 *
	 * <B><U> Concept</U> :</B><BR><BR>
	 * Others L2PcInstance in the detection area of the L2PcInstance are identified in <B>_knownPlayers</B>.
	 * In order to inform other players of this L2PcInstance state modifications, server just need to go through _knownPlayers to send Server->Client Packet<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Send a Server->Client packet UserInfo to this L2PcInstance (Public and Private Data)</li>
	 * <li>Send a Server->Client packet CharInfo to all L2PcInstance in _KnownPlayers of the L2PcInstance (Public data only)</li><BR><BR>
	 *
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : DON'T SEND UserInfo packet to other players instead of CharInfo packet.
	 * Indeed, UserInfo packet contains PRIVATE DATA as MaxHP, STR, DEX...</B></FONT><BR><BR>
	 *
	 */
	public final void broadcastUserInfo()
	{
		// Send a Server->Client packet UserInfo to this L2PcInstance
		sendPacket(new UserInfo(this));

		// Send a Server->Client packet CharInfo to all L2PcInstance in _KnownPlayers of the L2PcInstance
		if (Config.DEBUG)
            _log.fine("players to notify:" + getKnownList().getKnownPlayers().size() + " packet: [S] 03 CharInfo");

		broadcastPacket(new CharInfo(this));
		broadcastPacket(new ExBrExtraUserInfo(this));
	}

	public final void broadcastTitleInfo()
	{
		// Send a Server->Client packet UserInfo to this L2PcInstance
		sendPacket(new UserInfo(this));
		sendPacket(new ExBrExtraUserInfo(this));

		// Send a Server->Client packet TitleUpdate to all L2PcInstance in _KnownPlayers of the L2PcInstance
		if (Config.DEBUG)
            _log.fine("players to notify:" + getKnownList().getKnownPlayers().size() + " packet: [S] cc TitleUpdate");

		broadcastPacket(new NicknameChanged(this));
	}

	@Override
	public final void broadcastPacket(L2GameServerPacket mov)
	{
		if (!(mov instanceof CharInfo))
			sendPacket(mov);

		mov.setInvisible(getAppearance().getInvisible());

		Collection<L2PcInstance> plrs = getKnownList().getKnownPlayers().values();
		//synchronized (getKnownList().getKnownPlayers())
		{
			for (L2PcInstance player : plrs)
			{
				player.sendPacket(mov);
				if (mov instanceof CharInfo)
				{
					int relation = getRelation(player);
					if (getKnownList().getKnownRelations().get(player.getObjectId()) != null
					        && getKnownList().getKnownRelations().get(player.getObjectId()) != relation)
					{
						player.sendPacket(new RelationChanged(this, relation, player.isAutoAttackable(this)));
						if (getPet() != null)
							player.sendPacket(new RelationChanged(getPet(), relation, player.isAutoAttackable(this)));
					}
				}
			}
		}
	}

	@Override
	public void broadcastPacket(L2GameServerPacket mov, int radiusInKnownlist)
	{
		if (!(mov instanceof CharInfo))
			sendPacket(mov);

		mov.setInvisible(getAppearance().getInvisible());

		Collection<L2PcInstance> plrs = getKnownList().getKnownPlayers().values();
		//synchronized (getKnownList().getKnownPlayers())
		{
			for (L2PcInstance player : plrs)
			{
				if (isInsideRadius(player, radiusInKnownlist, false, false))
				{
					player.sendPacket(mov);
					if (mov instanceof CharInfo)
					{
						int relation = getRelation(player);
						if (getKnownList().getKnownRelations().get(player.getObjectId()) != null
						        && getKnownList().getKnownRelations().get(player.getObjectId()) != relation)
						{
							player.sendPacket(new RelationChanged(this, relation, player.isAutoAttackable(this)));
							if (getPet() != null)
								player.sendPacket(new RelationChanged(getPet(), relation, player.isAutoAttackable(this)));
						}
					}
				}
			}
		}
	}

	/**
	 * Return the Alliance Identifier of the L2PcInstance.<BR><BR>
	 */
	public int getAllyId()
	{
		if (_clan == null)
			return 0;
		else
			return _clan.getAllyId();
	}

	public int getAllyCrestId()
	{
		if (getClanId() == 0)
		{
			return 0;
		}
		if (getClan().getAllyId() == 0)
		{
			return 0;
		}
		return getClan().getAllyCrestId();
	}

	/**
	 * Manage hit process (called by Hit Task of L2Character).<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>If the attacker/target is dead or use fake death, notify the AI with EVT_CANCEL and send a Server->Client packet ActionFailed (if attacker is a L2PcInstance)</li>
	 * <li>If attack isn't aborted, send a message system (critical hit, missed...) to attacker/target if they are L2PcInstance </li>
	 * <li>If attack isn't aborted and hit isn't missed, reduce HP of the target and calculate reflection damage to reduce HP of attacker if necessary </li>
	 * <li>if attack isn't aborted and hit isn't missed, manage attack or cast break of the target (calculating rate, sending message...) </li><BR><BR>
	 *
	 * @param target The L2Character targeted
	 * @param damage Nb of HP to reduce
	 * @param crit True if hit is critical
	 * @param miss True if hit is missed
	 * @param soulshot True if SoulShot are charged
	 * @param shld True if shield is efficient
	 *
	 */
	@Override
	protected void onHitTimer(L2Character target, int damage, boolean crit, boolean miss, boolean soulshot, byte shld)
	{
		super.onHitTimer(target, damage, crit, miss, soulshot, shld);
	}
    
    public void queryGameGuard()
    {
        this.getClient().setGameGuardOk(false);
        this.sendPacket(new GameGuardQuery());
        if (Config.GAMEGUARD_ENFORCE)
        {
            ThreadPoolManager.getInstance().scheduleGeneral(new GameGuardCheck(), 30*1000);
        }
    }
    
    class GameGuardCheck implements Runnable
    {
        /**
         * @see java.lang.Runnable#run()
         */
        public void run()
        {
            L2GameClient client = L2PcInstance.this.getClient();
            if (client != null && !client.isAuthedGG() && L2PcInstance.this.isOnline() == 1)
            {
                GmListTable.broadcastMessageToGMs("Client "+client+" failed to reply GameGuard query and is being kicked!");
                _log.info("Client "+client+" failed to reply GameGuard query and is being kicked!");
                client.close(new LeaveWorld());
            }
        }
    }

	/**
	 * Send a Server->Client packet StatusUpdate to the L2PcInstance.<BR><BR>
	 */
	@Override
	public void sendPacket(L2GameServerPacket packet)
	{
		if (_client != null)
		{
			_client.sendPacket(packet);
		}
	}
	
	/**
	 * Send SystemMessage packet.<BR><BR>
	 * @param id: SystemMessageId
	 */
	public void sendPacket(SystemMessageId id)
	{
		sendPacket(new SystemMessage(id));		
	}

	/**
	 * Manage Interact Task with another L2PcInstance.<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>If the private store is a STORE_PRIVATE_SELL, send a Server->Client PrivateBuyListSell packet to the L2PcInstance</li>
	 * <li>If the private store is a STORE_PRIVATE_BUY, send a Server->Client PrivateBuyListBuy packet to the L2PcInstance</li>
	 * <li>If the private store is a STORE_PRIVATE_MANUFACTURE, send a Server->Client RecipeShopSellList packet to the L2PcInstance</li><BR><BR>
	 *
	 * @param target The L2Character targeted
	 *
	 */
	public void doInteract(L2Character target)
	{
		if (target instanceof L2PcInstance)
		{
			L2PcInstance temp = (L2PcInstance) target;
			sendPacket(ActionFailed.STATIC_PACKET);

			if (temp.getPrivateStoreType() == STORE_PRIVATE_SELL || temp.getPrivateStoreType() == STORE_PRIVATE_PACKAGE_SELL)
				sendPacket(new PrivateStoreListSell(this, temp));
			else if (temp.getPrivateStoreType() == STORE_PRIVATE_BUY)
				sendPacket(new PrivateStoreListBuy(this, temp));
			else if (temp.getPrivateStoreType() == STORE_PRIVATE_MANUFACTURE)
				sendPacket(new RecipeShopSellList(this, temp));

		}
		else
		{
			// _interactTarget=null should never happen but one never knows ^^;
			if (target != null)
				target.onAction(this);
		}
	}

	/**
	 * Manage AutoLoot Task.<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Send a System Message to the L2PcInstance : YOU_PICKED_UP_S1_ADENA or YOU_PICKED_UP_S1_S2</li>
	 * <li>Add the Item to the L2PcInstance inventory</li>
	 * <li>Send a Server->Client packet InventoryUpdate to this L2PcInstance with NewItem (use a new slot) or ModifiedItem (increase amount)</li>
	 * <li>Send a Server->Client packet StatusUpdate to this L2PcInstance with current weight</li><BR><BR>
	 *
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : If a Party is in progress, distribute Items between party members</B></FONT><BR><BR>
	 *
	 * @param target The L2ItemInstance dropped
	 *
	 */
	public void doAutoLoot(L2Attackable target, L2Attackable.RewardItem item)
	{
		if (isInParty()&&ItemTable.getInstance().getTemplate(item.getItemId()).getItemType() != L2EtcItemType.HERB)  
			getParty().distributeItem(this, item, false, target);
		else if (item.getItemId() == 57) addAdena("Loot", item.getCount(), target, true);
		else addItem("Loot", item.getItemId(), item.getCount(), target, true);
	}


	/**
	 * Manage Pickup Task.<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Send a Server->Client packet StopMove to this L2PcInstance </li>
	 * <li>Remove the L2ItemInstance from the world and send server->client GetItem packets </li>
	 * <li>Send a System Message to the L2PcInstance : YOU_PICKED_UP_S1_ADENA or YOU_PICKED_UP_S1_S2</li>
	 * <li>Add the Item to the L2PcInstance inventory</li>
	 * <li>Send a Server->Client packet InventoryUpdate to this L2PcInstance with NewItem (use a new slot) or ModifiedItem (increase amount)</li>
	 * <li>Send a Server->Client packet StatusUpdate to this L2PcInstance with current weight</li><BR><BR>
	 *
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : If a Party is in progress, distribute Items between party members</B></FONT><BR><BR>
	 *
	 * @param object The L2ItemInstance to pick up
	 *
	 */
	protected void doPickupItem(L2Object object)
	{
		if (isAlikeDead() || isFakeDeath()) return;

		// Set the AI Intention to AI_INTENTION_IDLE
		getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);

		// Check if the L2Object to pick up is a L2ItemInstance
		if (! (object instanceof L2ItemInstance))
		{
			// dont try to pickup anything that is not an item :)
			_log.warning("trying to pickup wrong target."+getTarget());
			return;
		}

		L2ItemInstance target = (L2ItemInstance) object;

		// Send a Server->Client packet ActionFailed to this L2PcInstance
		sendPacket(ActionFailed.STATIC_PACKET);

		// Send a Server->Client packet StopMove to this L2PcInstance
		StopMove sm = new StopMove(getObjectId(), getX(), getY(), getZ(), getHeading());
		if (Config.DEBUG) _log.fine("pickup pos: "+ target.getX() + " "+target.getY()+ " "+target.getZ() );
		sendPacket(sm);

		synchronized (target)
		{
			// Check if the target to pick up is visible
			if (!target.isVisible())
			{
				// Send a Server->Client packet ActionFailed to this L2PcInstance
				sendPacket(ActionFailed.STATIC_PACKET);
				return;
			}

			if ( ((isInParty() && getParty().getLootDistribution() == L2Party.ITEM_LOOTER) || !isInParty()) && !_inventory.validateCapacity(target))
			{
				sendPacket(ActionFailed.STATIC_PACKET);
				sendPacket(new SystemMessage(SystemMessageId.SLOTS_FULL));
				return;
			}

            if (isInvul() && !isGM())
            {
                sendPacket(ActionFailed.STATIC_PACKET);
                SystemMessage smsg = new SystemMessage(SystemMessageId.FAILED_TO_PICKUP_S1);
                smsg.addItemName(target);
                sendPacket(smsg);
                return;
            }

	        if (target.getOwnerId() != 0 && target.getOwnerId() != getObjectId() && !isInLooterParty(target.getOwnerId()))
            {
                sendPacket(ActionFailed.STATIC_PACKET);

                if (target.getItemId() == 57)
                {
                    SystemMessage smsg = new SystemMessage(SystemMessageId.FAILED_TO_PICKUP_S1_ADENA);
                    smsg.addItemNumber(target.getCount());
                    sendPacket(smsg);
                }
                else if (target.getCount() > 1)
                {
                    SystemMessage smsg = new SystemMessage(SystemMessageId.FAILED_TO_PICKUP_S2_S1_S);
                    smsg.addItemName(target);
                    smsg.addItemNumber(target.getCount());
                    sendPacket(smsg);
                }
                else
                {
                    SystemMessage smsg = new SystemMessage(SystemMessageId.FAILED_TO_PICKUP_S1);
                    smsg.addItemName(target);
                    sendPacket(smsg);
                }

                return;
            }
            
            // You can pickup only 1 combat flag
            if(FortSiegeManager.getInstance().isCombat(target.getItemId()) )
            {
                if (!FortSiegeManager.getInstance().checkIfCanPickup(this))
                    return ;
            }
            
	        if(target.getItemLootShedule() != null
	        		&& (target.getOwnerId() == getObjectId() || isInLooterParty(target.getOwnerId())))
	        	target.resetOwnerTimer();

			// Remove the L2ItemInstance from the world and send server->client GetItem packets
			target.pickupMe(this);
			 if(Config.SAVE_DROPPED_ITEM) // item must be removed from ItemsOnGroundManager if is active
				 ItemsOnGroundManager.getInstance().removeObject(target);

		}

        //Auto use herbs - pick up
		if (target.getItemType() == L2EtcItemType.HERB)
        {
			IItemHandler handler = ItemHandler.getInstance().getItemHandler(target.getEtcItem());
			if (handler == null)
				_log.fine("No item handler registered for item ID " + target.getItemId() + ".");
			else
				handler.useItem(this, target);
            	ItemTable.getInstance().destroyItem("Consume", target, this, null);
        }
		// Cursed Weapons are not distributed
		else if(CursedWeaponsManager.getInstance().isCursed(target.getItemId()))
		{
			addItem("Pickup", target, null, true);
		}
		else if(FortSiegeManager.getInstance().isCombat(target.getItemId()) )
        {
            addItem("Pickup", target, null, true);
        }
		else
		{
			// if item is instance of L2ArmorType or L2WeaponType broadcast an "Attention" system message
			if(target.getItemType() instanceof L2ArmorType || target.getItemType() instanceof L2WeaponType)
			{
				if (target.getEnchantLevel() > 0)
				{
					SystemMessage msg = new SystemMessage(SystemMessageId.ANNOUNCEMENT_C1_PICKED_UP_S2_S3);
					msg.addPcName(this);
					msg.addNumber(target.getEnchantLevel());
					msg.addItemName(target.getItemId());
					broadcastPacket(msg, 1400);
				}
				else
				{
					SystemMessage msg = new SystemMessage(SystemMessageId.ANNOUNCEMENT_C1_PICKED_UP_S2);
					msg.addPcName(this);
					msg.addItemName(target.getItemId());
					broadcastPacket(msg, 1400);
				}
			}

			// Check if a Party is in progress
			if (isInParty()) getParty().distributeItem(this, target);
			// Target is adena
			else if (target.getItemId() == 57 && getInventory().getAdenaInstance() != null)
			{
				addAdena("Pickup", target.getCount(), null, true);
				ItemTable.getInstance().destroyItem("Pickup", target, this, null);
			}
			// Target is regular item
			else addItem("Pickup", target, null, true);
		}
	}
	
	public boolean canOpenPrivateStore()
	{
		return !isAlikeDead() && !isInOlympiadMode() && !isMounted() 
				&& !isInsideZone(ZONE_NOSTORE) && !isCastingNow();
	}
	
	public void tryOpenPrivateBuyStore()
	{
		// Player shouldn't be able to set stores if he/she is alike dead (dead or fake death)
		if (canOpenPrivateStore())
		{
			if (getPrivateStoreType() == L2PcInstance.STORE_PRIVATE_BUY || getPrivateStoreType() == L2PcInstance.STORE_PRIVATE_BUY + 1)
			{
				setPrivateStoreType(L2PcInstance.STORE_PRIVATE_NONE);
			}
			if (getPrivateStoreType() == L2PcInstance.STORE_PRIVATE_NONE)
			{
				if (isSitting())
				{
					standUp();
				}
				setPrivateStoreType(L2PcInstance.STORE_PRIVATE_BUY + 1);
				sendPacket(new PrivateStoreManageListBuy(this));
			}
		}
		else
		{
			if (isInsideZone(ZONE_NOSTORE))
				sendPacket(new SystemMessage(SystemMessageId.NO_PRIVATE_STORE_HERE));
			sendPacket(ActionFailed.STATIC_PACKET);
		}
	}
	
	public void tryOpenPrivateSellStore(boolean isPackageSale)
	{
		// Player shouldn't be able to set stores if he/she is alike dead (dead or fake death)
		if (canOpenPrivateStore())
		{
			if (getPrivateStoreType() == L2PcInstance.STORE_PRIVATE_SELL || getPrivateStoreType() == L2PcInstance.STORE_PRIVATE_SELL + 1 || getPrivateStoreType() == L2PcInstance.STORE_PRIVATE_PACKAGE_SELL)
			{
				this.setPrivateStoreType(L2PcInstance.STORE_PRIVATE_NONE);
			}
			
			if (getPrivateStoreType() == L2PcInstance.STORE_PRIVATE_NONE)
			{
				if (isSitting())
				{
					standUp();
				}
				setPrivateStoreType(L2PcInstance.STORE_PRIVATE_SELL + 1);
				sendPacket(new PrivateStoreManageListSell(this, isPackageSale));
			}
		}
		else
		{
			if (isInsideZone(ZONE_NOSTORE))
				sendPacket(new SystemMessage(SystemMessageId.NO_PRIVATE_STORE_HERE));
			sendPacket(ActionFailed.STATIC_PACKET);
		}
	}
    
    public boolean isTransformed()
    {
        return _transformation != null && !_transformation.isStance();
    }

    public boolean isInStance()
    {
    	return _transformation != null && _transformation.isStance();
    }

    public void transform(L2Transformation transformation)
    {
        if (_transformation != null)
        {
            // You already polymorphed and cannot polymorph again.
            SystemMessage msg = new SystemMessage(SystemMessageId.YOU_ALREADY_POLYMORPHED_AND_CANNOT_POLYMORPH_AGAIN);
            sendPacket(msg);
            return;
        }
        if(isMounted())
        {
        	// Get off the strider or something else if character is mounted
        	dismount();
        }
        
        _transformation = transformation;
        for (L2Effect e : getAllEffects())
        {
        	if (e != null && e.getSkill().isToggle()) e.exit();
        }
        transformation.onTransform();
        sendSkillList();
        sendPacket(new SkillCoolTime(this));
        broadcastUserInfo();
    }
    
    public void untransform()
    {
        if (_transformation != null)
        {
        	setTransformAllowedSkills(new int[]{});
            _transformation.onUntransform();
            _transformation = null;
            stopEffects(L2EffectType.TRANSFORMATION);
            broadcastUserInfo();
            sendSkillList();
            sendPacket(new SkillCoolTime(this));
        }
    }
    
    public L2Transformation getTransformation()
    {
        return _transformation;
    }
    
    /**
     * This returns the transformation Id of the current transformation.
     * For example, if a player is transformed as a Buffalo, and then picks up the Zariche,
     * the transform Id returned will be that of the Zariche, and NOT the Buffalo.
     * @return Transformation Id
     */
    public int getTransformationId()
    {
        return (_transformation == null ? 0 : _transformation.getId());
    }
    
    /**
     * This returns the transformation Id stored inside the character table, selected by the method: transformSelectInfo()
     * For example, if a player is transformed as a Buffalo, and then picks up the Zariche,
     * the transform Id returned will be that of the Buffalo, and NOT the Zariche.
     * @return Transformation Id
     */
    public int transformId()
    {
       return _transformationId;
    }
    
    /**
     * This is a simple query that inserts the transform Id into the character table for future reference.
     */
    public void transformInsertInfo()
    {
    	_transformationId = getTransformationId();
    	
    	if (_transformationId == L2Transformation.TRANSFORM_AKAMANAH
    			|| _transformationId == L2Transformation.TRANSFORM_ZARICHE)
    		return;
    	
    	Connection con = null;
        try
        {
            con = L2DatabaseFactory.getInstance().getConnection();
            PreparedStatement statement = con.prepareStatement(UPDATE_CHAR_TRANSFORM);
            
            statement.setInt(1, _transformationId);
            statement.setInt(2, getObjectId());
            
            statement.execute();
            statement.close();
        }
        catch (Exception e)
        {
        	_log.log(Level.SEVERE, "Transformation insert info: ",e);
        }
        finally
        {
            try { con.close(); } catch (Exception e) {}
        }
    }
    
    /**
     * This selects the current 
     * @return transformation Id
     */
    public int transformSelectInfo()
    {
    	Connection con = null;
        try
        {
            con = L2DatabaseFactory.getInstance().getConnection();
            PreparedStatement statement = con.prepareStatement(SELECT_CHAR_TRANSFORM); 
            
            statement.setInt(1, getObjectId());
            ResultSet rset = statement.executeQuery();
            rset.next();
            _transformationId = rset.getInt("transform_id");
            
            rset.close();
            statement.close();
        }
        catch (Exception e)
        {
        	_log.log(Level.SEVERE, "Transformation select info: ",e);
        }
        finally
        {
            try { con.close(); } catch (Exception e) {}
        }
        return _transformationId;
    }

	/**
	 * Set a target.<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Remove the L2PcInstance from the _statusListener of the old target if it was a L2Character </li>
	 * <li>Add the L2PcInstance to the _statusListener of the new target if it's a L2Character </li>
	 * <li>Target the new L2Object (add the target to the L2PcInstance _target, _knownObject and L2PcInstance to _KnownObject of the L2Object)</li><BR><BR>
	 *
	 * @param newTarget The L2Object to target
	 *
	 */
	@Override
	public void setTarget(L2Object newTarget)
	{
		
		if(newTarget!=null)
		{
			boolean isParty=(( (newTarget instanceof L2PcInstance) && isInParty() && getParty().getPartyMembers().contains(newTarget)));
		
			// Check if the new target is visible
			if (!isParty && !newTarget.isVisible())
				newTarget = null;

			// Prevents /target exploiting
			if (newTarget != null && !isParty && Math.abs(newTarget.getZ() - getZ()) > 1000)
				newTarget = null;
		}
		if(!isGM())
		{
			// Can't target and attack festival monsters if not participant
			if((newTarget instanceof L2FestivalMonsterInstance) && !isFestivalParticipant())
				newTarget = null;

			// Can't target and attack rift invaders if not in the same room
			else if(isInParty() && getParty().isInDimensionalRift())
			{
				byte riftType = getParty().getDimensionalRift().getType();
				byte riftRoom = getParty().getDimensionalRift().getCurrentRoom();

				if (newTarget != null && !DimensionalRiftManager.getInstance().getRoom(riftType, riftRoom).checkIfInZone(newTarget.getX(), newTarget.getY(), newTarget.getZ()))
					newTarget = null;
			}
		}

		// Get the current target
		L2Object oldTarget = getTarget();

		if (oldTarget != null)
		{
			if (oldTarget.equals(newTarget))
				return; // no target change

			// Remove the L2PcInstance from the _statusListener of the old target if it was a L2Character
			if (oldTarget instanceof L2Character)
				((L2Character) oldTarget).removeStatusListener(this);
		}

		// Add the L2PcInstance to the _statusListener of the new target if it's a L2Character
		if (newTarget instanceof L2Character)
		{
			((L2Character) newTarget).addStatusListener(this);
			TargetSelected my = new TargetSelected(getObjectId(), newTarget.getObjectId(), getX(), getY(), getZ());
			broadcastPacket(my);
		}
		if (newTarget == null && getTarget() != null)
		{
			broadcastPacket(new TargetUnselected(this));
		}
		
		// Target the new L2Object (add the target to the L2PcInstance _target, _knownObject and L2PcInstance to _KnownObject of the L2Object)
		super.setTarget(newTarget);
	}

	/**
	 * Return the active weapon instance (always equiped in the right hand).<BR><BR>
	 */
	@Override
	public L2ItemInstance getActiveWeaponInstance()
	{
		return getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
	}

	/**
	 * Return the active weapon item (always equiped in the right hand).<BR><BR>
	 */
	@Override
	public L2Weapon getActiveWeaponItem()
	{
		L2ItemInstance weapon = getActiveWeaponInstance();

		if (weapon == null)
			return getFistsWeaponItem();

		return (L2Weapon) weapon.getItem();
	}

	public L2ItemInstance getChestArmorInstance()
	{
		return getInventory().getPaperdollItem(Inventory.PAPERDOLL_CHEST);
	}

    public L2ItemInstance getLegsArmorInstance()
    {
        return getInventory().getPaperdollItem(Inventory.PAPERDOLL_LEGS);
    }

	public L2Armor getActiveChestArmorItem()
	{
		L2ItemInstance armor = getChestArmorInstance();

		if (armor == null)
			return null;

		return (L2Armor) armor.getItem();
	}

    public L2Armor getActiveLegsArmorItem()
    {
        L2ItemInstance legs = getLegsArmorInstance();

        if (legs == null)
            return null;

        return (L2Armor) legs.getItem();
    }

	public boolean isWearingHeavyArmor()
	{
        L2ItemInstance legs = getLegsArmorInstance();
        L2ItemInstance armor = getChestArmorInstance();
        
	    if (armor != null && legs != null)
        {
            if ((L2ArmorType)legs.getItemType() == L2ArmorType.HEAVY 
                    && ((L2ArmorType)armor.getItemType() == L2ArmorType.HEAVY))
                return true;
        }
	    if (armor != null)
	    {
	        if ((getInventory().getPaperdollItem(Inventory.PAPERDOLL_CHEST).getItem().getBodyPart() == L2Item.SLOT_FULL_ARMOR 
	                && (L2ArmorType)armor.getItemType() == L2ArmorType.HEAVY))
	            return true;
	    }
		return false;
	}

	public boolean isWearingLightArmor()
	{
        L2ItemInstance legs = getLegsArmorInstance();
        L2ItemInstance armor = getChestArmorInstance();

	    if (armor != null && legs != null)
        {
            if ((L2ArmorType)legs.getItemType() == L2ArmorType.LIGHT 
                    && ((L2ArmorType)armor.getItemType() == L2ArmorType.LIGHT))
                return true;
        }
        if (armor != null)
        {
            if ((getInventory().getPaperdollItem(Inventory.PAPERDOLL_CHEST).getItem().getBodyPart() == L2Item.SLOT_FULL_ARMOR 
                    && (L2ArmorType)armor.getItemType() == L2ArmorType.LIGHT))
                return true;
        }
		return false;
	}

	public boolean isWearingMagicArmor()
	{
        L2ItemInstance legs = getLegsArmorInstance();
        L2ItemInstance armor = getChestArmorInstance();

	    if (armor != null && legs != null)
        {
            if ((L2ArmorType)legs.getItemType() == L2ArmorType.MAGIC 
                    && ((L2ArmorType)armor.getItemType() == L2ArmorType.MAGIC))
                return true;
        }
        if (armor != null)
        {
            if ((getInventory().getPaperdollItem(Inventory.PAPERDOLL_CHEST).getItem().getBodyPart() == L2Item.SLOT_FULL_ARMOR 
                    && (L2ArmorType)armor.getItemType() == L2ArmorType.MAGIC))
                return true;
        }
		return false;
	}

	public boolean isWearingFormalWear()
    {
        return _IsWearingFormalWear;
    }

    public void setIsWearingFormalWear(boolean value)
    {
        _IsWearingFormalWear = value;
    }
    public boolean isMarried()
    {
        return _married;
    }

    public void setMarried(boolean state)
    {
        _married = state;
    }

    public boolean isEngageRequest()
    {
        return _engagerequest;
    }

    public void setEngageRequest(boolean state,int playerid)
    {
        _engagerequest = state;
        _engageid = playerid;
    }

    public void setMaryRequest(boolean state)
    {
        _marryrequest = state;
    }

    public boolean isMaryRequest()
    {
        return _marryrequest;
    }

    public void setMarryAccepted(boolean state)
    {
        _marryaccepted = state;
    }

    public boolean isMarryAccepted()
    {
        return _marryaccepted;
    }

    public int getEngageId()
    {
        return _engageid;
    }

    public int getPartnerId()
    {
        return _partnerId;
    }

    public void setPartnerId(int partnerid)
    {
        _partnerId = partnerid;
    }

    public int getCoupleId()
    {
        return _coupleId;
    }

    public void setCoupleId(int coupleId)
    {
        _coupleId = coupleId;
    }

    public void EngageAnswer(int answer)
    {
        if(_engagerequest==false)
            return;
        else if(_engageid==0)
            return;
        else
        {
            L2PcInstance ptarget = (L2PcInstance)L2World.getInstance().findObject(_engageid);
            setEngageRequest(false,0);
            if(ptarget!=null)
            {
                if (answer == 1)
                {
                    CoupleManager.getInstance().createCouple(ptarget, L2PcInstance.this);
                    ptarget.sendMessage("Request to Engage has been >ACCEPTED<");
                }
                else
                    ptarget.sendMessage("Request to Engage has been >DENIED<!");
            }
        }
    }

	/**
	 * Return the secondary weapon instance (always equiped in the left hand).<BR><BR>
	 */
	@Override
	public L2ItemInstance getSecondaryWeaponInstance()
	{
		return getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
	}

	/**
	 * Return the secondary weapon item (always equiped in the left hand) or the fists weapon.<BR><BR>
	 */
	@Override
	public L2Weapon getSecondaryWeaponItem()
	{
		L2ItemInstance weapon = getSecondaryWeaponInstance();

		if (weapon == null)
			return getFistsWeaponItem();

		L2Item item = weapon.getItem();

		if (item instanceof L2Weapon)
			return (L2Weapon) item;

		return null;
	}


	/**
	 *
     * Kill the L2Character, Apply Death Penalty, Manage gain/loss Karma and Item Drop.<BR><BR>
     *
     * <B><U> Actions</U> :</B><BR><BR>
     * <li>Reduce the Experience of the L2PcInstance in function of the calculated Death Penalty </li>
     * <li>If necessary, unsummon the Pet of the killed L2PcInstance </li>
     * <li>Manage Karma gain for attacker and Karam loss for the killed L2PcInstance </li>
     * <li>If the killed L2PcInstance has Karma, manage Drop Item</li>
     * <li>Kill the L2PcInstance </li><BR><BR>
     *
     *
     * @param i The HP decrease value
     * @param attacker The L2Character who attacks
     *
     *
	 * @see com.l2jserver.gameserver.model.actor.L2Playable#doDie(com.l2jserver.gameserver.model.actor.L2Character)
	 */
	@Override
	public boolean doDie(L2Character killer)
	{
		// Kill the L2PcInstance
		if (!super.doDie(killer))
			return false;
		
		if (isMounted())
			stopFeed();
		synchronized (this)
		{
			if (isFakeDeath())
				stopFakeDeath(null);
		}
		
		if (killer != null)
		{
			L2PcInstance pk = killer.getActingPlayer();
			
			TvTEvent.onKill(killer, this);
			
			if (atEvent && pk != null)
			{
				pk.kills.add(getName());
			}
			
			//announce pvp/pk
			if (Config.ANNOUNCE_PK_PVP && pk != null && !pk.isGM())
			{
				String msg = "";
				if (getPvpFlag() == 0)
				{
					msg = Config.ANNOUNCE_PK_MSG.replace("$killer", pk.getName()).replace("$target", getName());
					if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
					{
						SystemMessage sm = new SystemMessage(SystemMessageId.S1);
						sm.addString(msg);
						Announcements.getInstance().announceToAll(sm);
					}
					else	
						Announcements.getInstance().announceToAll(msg);
				}
				else if (getPvpFlag() != 0)
				{
					msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", pk.getName()).replace("$target", getName());
					if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
					{
						SystemMessage sm = new SystemMessage(SystemMessageId.S1);
						sm.addString(msg);
						Announcements.getInstance().announceToAll(sm);
					}
					else
						Announcements.getInstance().announceToAll(msg);
				}
			}
			
			// Clear resurrect xp calculation
			setExpBeforeDeath(0);
			
			// Issues drop of Cursed Weapon.
			if (isCursedWeaponEquipped())
			{
				CursedWeaponsManager.getInstance().drop(_cursedWeaponEquippedId, killer);
			}
			else if (isCombatFlagEquipped())
			{
				FortSiegeManager.getInstance().dropCombatFlag(this);
			}
			else
			{
				if (pk == null || !pk.isCursedWeaponEquipped())
				{
					onDieDropItem(killer); // Check if any item should be dropped
					
					if (!(isInsideZone(ZONE_PVP) && !isInsideZone(ZONE_SIEGE)))
					{
						if (pk != null && pk.getClan() != null && getClan() != null && !isAcademyMember() && !(pk.isAcademyMember()) )
						{
							if ((_clan.isAtWarWith(pk.getClanId()) && pk.getClan().isAtWarWith(_clan.getClanId()))
									|| (isInSiege() && pk.isInSiege()))
							{
								if (AntiFeedManager.getInstance().check(killer, this))
								{
									// 	when your reputation score is 0 or below, the other clan cannot acquire any reputation points
									if (getClan().getReputationScore() > 0)
										pk.getClan().addReputationScore(Config.REPUTATION_SCORE_PER_KILL, false);
									// 	when the opposing sides reputation score is 0 or below, your clans reputation score does not decrease
									if (pk.getClan().getReputationScore() > 0)
										_clan.takeReputationScore(Config.REPUTATION_SCORE_PER_KILL, false);
								}
							}
						}
					}
					if (Config.ALT_GAME_DELEVEL)
					{
						// Reduce the Experience of the L2PcInstance in function of the calculated Death Penalty
						// NOTE: deathPenalty +- Exp will update karma
						// Penalty is lower if the player is at war with the pk (war has to be declared)
						if (getSkillLevel(L2Skill.SKILL_LUCKY) < 0 || getStat().getLevel() > 9)
						{
							boolean siege_npc = false;
							if (killer instanceof L2DefenderInstance || killer instanceof L2FortCommanderInstance)
								siege_npc = true;
							deathPenalty(pk != null && getClan() != null && getClan().isAtWarWith(pk.getClanId()), pk != null, siege_npc);
						}
						
					}
					else
					{
						if (!(isInsideZone(ZONE_PVP) && !isInSiege()) || pk == null)
							onDieUpdateKarma(); // Update karma if delevel is not allowed
					}
				}
			}
		}
		
		setPvpFlag(0); // Clear the pvp flag
		
		// Unsummon Cubics
		if (!_cubics.isEmpty())
		{
			for (L2CubicInstance cubic : _cubics.values())
			{
				cubic.stopAction();
				cubic.cancelDisappear();
			}
			
			_cubics.clear();
		}
		
		if (_fusionSkill != null)
			abortCast();
		
		for (L2Character character : getKnownList().getKnownCharacters())
			if (character.getFusionSkill() != null && character.getFusionSkill().getTarget() == this)
				character.abortCast();
		
		if (isInParty() && getParty().isInDimensionalRift())
			getParty().getDimensionalRift().getDeadMemberList().add(this);
		
		if (getAgathionId() != 0)
			setAgathionId(0);
		
		// calculate death penalty buff
		calculateDeathPenaltyBuffLevel(killer);
		
		stopRentPet();
		stopWaterTask();
		
		AntiFeedManager.getInstance().setLastDeathTime(getObjectId());

		if (isPhoenixBlessed())
			reviveRequest(this, null, false);
		else if (getCharmOfCourage() && this.isInSiege())
		{
			reviveRequest(this, null, false);
		}
		return true;
	}

	private void onDieDropItem(L2Character killer)
	{
		if (atEvent || killer == null)
            return;

		L2PcInstance pk = killer.getActingPlayer();
		if (getKarma() <= 0 && pk != null
                && pk.getClan() != null && getClan() != null
                && (
                		pk.getClan().isAtWarWith(getClanId())
                        // || this.getClan().isAtWarWith(((L2PcInstance)killer).getClanId())
                   )
           )
			return;

		if ((!isInsideZone(ZONE_PVP) || pk == null) && (!isGM() || Config.KARMA_DROP_GM))
		{
			boolean isKarmaDrop = false;
			boolean isKillerNpc = (killer instanceof L2Npc);
			int pkLimit = Config.KARMA_PK_LIMIT;

			int dropEquip           = 0;
			int dropEquipWeapon     = 0;
			int dropItem            = 0;
			int dropLimit           = 0;
			int dropPercent         = 0;

			if (getKarma() > 0 && getPkKills() >= pkLimit)
			{
				isKarmaDrop = true;
				dropPercent = Config.KARMA_RATE_DROP;
				dropEquip = Config.KARMA_RATE_DROP_EQUIP;
				dropEquipWeapon = Config.KARMA_RATE_DROP_EQUIP_WEAPON;
				dropItem = Config.KARMA_RATE_DROP_ITEM;
				dropLimit = Config.KARMA_DROP_LIMIT;
			}
			else if (isKillerNpc && getLevel() > 4 && !isFestivalParticipant())
			{
				dropPercent = Config.PLAYER_RATE_DROP;
				dropEquip = Config.PLAYER_RATE_DROP_EQUIP;
				dropEquipWeapon = Config.PLAYER_RATE_DROP_EQUIP_WEAPON;
				dropItem = Config.PLAYER_RATE_DROP_ITEM;
				dropLimit = Config.PLAYER_DROP_LIMIT;
			}

			if (dropPercent > 0 && Rnd.get(100) < dropPercent)
			{
				int dropCount = 0;

				int itemDropPercent = 0;

				for (L2ItemInstance itemDrop : getInventory().getItems())
				{
					// Don't drop
					if (
							itemDrop.isShadowItem() || // Dont drop Shadow Items
							itemDrop.isTimeLimitedItem() || // Dont drop Time Limited Items
							!itemDrop.isDropable() ||
							itemDrop.getItemId() == 57 || // Adena
							itemDrop.getItem().getType2() == L2Item.TYPE2_QUEST ||                  // Quest Items
							getPet() != null && getPet().getControlItemId() == itemDrop.getItemId() || // Control Item of active pet
							Arrays.binarySearch(Config.KARMA_LIST_NONDROPPABLE_ITEMS, itemDrop.getItemId()) >= 0 || // Item listed in the non droppable item list
							Arrays.binarySearch(Config.KARMA_LIST_NONDROPPABLE_PET_ITEMS, itemDrop.getItemId()) >= 0 // Item listed in the non droppable pet item list
					) continue;

					if (itemDrop.isEquipped())
					{
						// Set proper chance according to Item type of equipped Item
						itemDropPercent = itemDrop.getItem().getType2() == L2Item.TYPE2_WEAPON ? dropEquipWeapon : dropEquip;
						getInventory().unEquipItemInSlotAndRecord(itemDrop.getLocationSlot());
					}
					else itemDropPercent = dropItem; // Item in inventory

					// NOTE: Each time an item is dropped, the chance of another item being dropped gets lesser (dropCount * 2)
					if (Rnd.get(100) < itemDropPercent)
					{
						dropItem("DieDrop", itemDrop, killer, true);

						if (isKarmaDrop)
							_log.warning(getName() + " has karma and dropped id = " + itemDrop.getItemId() + ", count = " + itemDrop.getCount());
						else
							_log.warning(getName() + " dropped id = " + itemDrop.getItemId() + ", count = " + itemDrop.getCount());

						if (++dropCount >= dropLimit)
							break;
					}
				}
			}
		}
	}

	private void onDieUpdateKarma()
	{
		// Karma lose for server that does not allow delevel
		if ( getKarma() > 0 )
		{
			// this formula seems to work relatively well:
			// baseKarma * thisLVL * (thisLVL/100)
			// Calculate the new Karma of the attacker : newKarma = baseKarma*pkCountMulti*lvlDiffMulti
			double karmaLost = Config.KARMA_LOST_BASE;
			karmaLost *= getLevel(); // multiply by char lvl
			karmaLost *= (getLevel() / 100.0); // divide by 0.charLVL
			karmaLost = Math.round(karmaLost);
			if ( karmaLost < 0 ) karmaLost = 1;

			// Decrease Karma of the L2PcInstance and Send it a Server->Client StatusUpdate packet with Karma and PvP Flag if necessary
			setKarma(getKarma() - (int)karmaLost);
		}
	}

	public void onKillUpdatePvPKarma(L2Character target)
	{
		if (target == null) return;
		if (!(target instanceof L2Playable)) return;

		L2PcInstance targetPlayer = target.getActingPlayer();

		if (targetPlayer == null) return;                                          // Target player is null
		if (targetPlayer == this) return;                                          // Target player is self

		if (isCursedWeaponEquipped())
		{
			CursedWeaponsManager.getInstance().increaseKills(_cursedWeaponEquippedId);
			// Custom message for time left
			// CursedWeapon cw = CursedWeaponsManager.getInstance().getCursedWeapon(_cursedWeaponEquipedId);
			// SystemMessage msg = new SystemMessage(SystemMessageId.THERE_IS_S1_HOUR_AND_S2_MINUTE_LEFT_OF_THE_FIXED_USAGE_TIME);
			// int timeLeftInHours = (int)(((cw.getTimeLeft()/60000)/60));
			// msg.addItemName(_cursedWeaponEquipedId);
			// msg.addNumber(timeLeftInHours);
			// sendPacket(msg);
			return;
		}

		// If in duel and you kill (only can kill l2summon), do nothing
		if (isInDuel() && targetPlayer.isInDuel()) return;

        // If in Arena, do nothing
		if (isInsideZone(ZONE_PVP) || targetPlayer.isInsideZone(ZONE_PVP))
			return;

        // Check if it's pvp
		if (
				(
						checkIfPvP(target) &&            //   Can pvp and
						targetPlayer.getPvpFlag() != 0   //   Target player has pvp flag set
				) ||                                     // or
				(
						isInsideZone(ZONE_PVP) &&         		 //   Player is inside pvp zone and
						targetPlayer.isInsideZone(ZONE_PVP) 	 //   Target player is inside pvp zone
				)
		)
			increasePvpKills(target);
		else
		// Target player doesn't have pvp flag set
		{
			// check about wars
			if (targetPlayer.getClan() != null && getClan() != null
					&& getClan().isAtWarWith(targetPlayer.getClanId())
					&& targetPlayer.getClan().isAtWarWith(getClanId())
					&& targetPlayer.getPledgeType() != L2Clan.SUBUNIT_ACADEMY
					&& getPledgeType() != L2Clan.SUBUNIT_ACADEMY)
			{
				// 'Both way war' -> 'PvP Kill'
				increasePvpKills(target);
				return;
			}

            // 'No war' or 'One way war' -> 'Normal PK'
			if (targetPlayer.getKarma() > 0)                                        // Target player has karma
			{
				if (Config.KARMA_AWARD_PK_KILL)
                    increasePvpKills(target);
			}
			else if (targetPlayer.getPvpFlag() == 0)                                                                    // Target player doesn't have karma
			{
				increasePkKillsAndKarma(target);
				//Unequip adventurer items
				if(getInventory().getPaperdollItemId(7) >= 7816 && getInventory().getPaperdollItemId(7) <= 7831) 
				{
					L2ItemInstance invItem = getInventory().getItemByItemId(getInventory().getPaperdollItemId(7));
					if(invItem.isEquipped()) 
					{
						L2ItemInstance[] unequiped = getInventory().unEquipItemInSlotAndRecord(invItem.getLocationSlot());
						InventoryUpdate iu = new InventoryUpdate();
						for(L2ItemInstance itm: unequiped)
							iu.addModifiedItem(itm);
						sendPacket(iu);
					}
					refreshExpertisePenalty();			
					sendPacket(new SystemMessage(SystemMessageId.YOU_ARE_UNABLE_TO_EQUIP_THIS_ITEM_WHEN_YOUR_PK_COUNT_IS_GREATER_THAN_OR_EQUAL_TO_ONE));
				}
			}
		}
	}

	/**
	 * Increase the pvp kills count and send the info to the player
	 *
	 */
	public void increasePvpKills(L2Character target)
	{
		if (target instanceof L2PcInstance
				&& AntiFeedManager.getInstance().check(this, target))
		{
			// Add karma to attacker and increase its PK counter
			setPvpKills(getPvpKills() + 1);

			// Send a Server->Client UserInfo packet to attacker with its Karma and PK Counter
			sendPacket(new UserInfo(this));
			sendPacket(new ExBrExtraUserInfo(this));
		}
	}

	/**
	 * Increase pk count, karma and send the info to the player
	 *
	 * @param targLVL : level of the killed player
	 * @param increasePk : true if PK counter should be increased too
	 */
	public void increasePkKillsAndKarma(L2Character target)
	{
		int baseKarma           = Config.KARMA_MIN_KARMA;
		int newKarma            = baseKarma;
		int karmaLimit          = Config.KARMA_MAX_KARMA;

		int pkLVL               = getLevel();
		int pkPKCount           = getPkKills();

		int targLVL             = target.getLevel();

		int lvlDiffMulti = 0;
		int pkCountMulti = 0;

		// Check if the attacker has a PK counter greater than 0
		if (pkPKCount > 0)
			pkCountMulti = pkPKCount / 2;
		else
			pkCountMulti = 1;

		if (pkCountMulti < 1)
			pkCountMulti = 1;

		// Calculate the level difference Multiplier between attacker and killed L2PcInstance
		if (pkLVL > targLVL)
			lvlDiffMulti = pkLVL / targLVL;
		else
			lvlDiffMulti = 1;

		if (lvlDiffMulti < 1)
			lvlDiffMulti = 1;

		// Calculate the new Karma of the attacker : newKarma = baseKarma*pkCountMulti*lvlDiffMulti
		newKarma *= pkCountMulti;
		newKarma *= lvlDiffMulti;

		// Make sure newKarma is less than karmaLimit and higher than baseKarma
		if (newKarma < baseKarma)
			newKarma = baseKarma;
		if (newKarma > karmaLimit)
			newKarma = karmaLimit;

		// Fix to prevent overflow (=> karma has a  max value of 2 147 483 647)
		if (getKarma() > (Integer.MAX_VALUE - newKarma))
			newKarma = Integer.MAX_VALUE - getKarma();

		// Add karma to attacker and increase its PK counter
		setKarma(getKarma() + newKarma);
		if (target instanceof L2PcInstance
				&& AntiFeedManager.getInstance().check(this, target))
			setPkKills(getPkKills() + 1);

		// Send a Server->Client UserInfo packet to attacker with its Karma and PK Counter
		sendPacket(new UserInfo(this));
		sendPacket(new ExBrExtraUserInfo(this));
	}

	public int calculateKarmaLost(long exp)
	{
		// KARMA LOSS
		// When a PKer gets killed by another player or a L2MonsterInstance, it loses a certain amount of Karma based on their level.
		// this (with defaults) results in a level 1 losing about ~2 karma per death, and a lvl 70 loses about 11760 karma per death...
		// You lose karma as long as you were not in a pvp zone and you did not kill urself.
		// NOTE: exp for death (if delevel is allowed) is based on the players level

		long expGained = Math.abs(exp);
		expGained /= Config.KARMA_XP_DIVIDER;

		// FIXME Micht : Maybe this code should be fixed and karma set to a long value
		int karmaLost = 0;
		if (expGained > Integer.MAX_VALUE)
			karmaLost = Integer.MAX_VALUE;
		else
			karmaLost = (int)expGained;

		if (karmaLost < Config.KARMA_LOST_BASE) karmaLost = Config.KARMA_LOST_BASE;
		if (karmaLost > getKarma()) karmaLost = getKarma();

		return karmaLost;
	}

	public void updatePvPStatus()
	{
		if (isInsideZone(ZONE_PVP)) return;
		setPvpFlagLasts(System.currentTimeMillis() + Config.PVP_NORMAL_TIME);

		if (getPvpFlag() == 0)
			startPvPFlag();
	}

	public void updatePvPStatus(L2Character target)
	{
		L2PcInstance player_target = target.getActingPlayer();

        if (player_target == null)
           return;

        if ((isInDuel() && player_target.getDuelId() == getDuelId())) return;
        if ((!isInsideZone(ZONE_PVP) || !player_target.isInsideZone(ZONE_PVP)) && player_target.getKarma() == 0)
        {
        	if (checkIfPvP(player_target))
        		setPvpFlagLasts(System.currentTimeMillis() + Config.PVP_PVP_TIME);
        	else
        		setPvpFlagLasts(System.currentTimeMillis() + Config.PVP_NORMAL_TIME);
			if (getPvpFlag() == 0)
				startPvPFlag();
        }
	}

	/**
	 * Restore the specified % of experience this L2PcInstance has
	 * lost and sends a Server->Client StatusUpdate packet.<BR><BR>
	 */
	public void restoreExp(double restorePercent)
	{
		if (getExpBeforeDeath() > 0)
		{
			// Restore the specified % of lost experience.
			getStat().addExp((int)Math.round((getExpBeforeDeath() - getExp()) * restorePercent / 100));
			setExpBeforeDeath(0);
		}
	}

	/**
	 * Reduce the Experience (and level if necessary) of the L2PcInstance in function of the calculated Death Penalty.<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Calculate the Experience loss </li>
	 * <li>Set the value of _expBeforeDeath </li>
	 * <li>Set the new Experience value of the L2PcInstance and Decrease its level if necessary </li>
	 * <li>Send a Server->Client StatusUpdate packet with its new Experience </li><BR><BR>
	 *
	 */
	public void deathPenalty(boolean atwar, boolean killed_by_pc, boolean killed_by_siege_npc)
	{
		// TODO Need Correct Penalty
		// Get the level of the L2PcInstance
		final int lvl = getLevel();

		int clan_luck = getSkillLevel(L2Skill.SKILL_CLAN_LUCK);
		
		double clan_luck_modificator = 1.0;	
		
		if (!killed_by_pc)
		{
			switch (clan_luck)
			{
				case 3:
					clan_luck_modificator = 0.8;
					break;
				case 2:
					clan_luck_modificator = 0.8;
					break;
				case 1:
					clan_luck_modificator = 0.88;
					break;
				default:
					clan_luck_modificator = 1.0;
					break;				
			}
		}
		else
		{
			switch (clan_luck)
			{
				case 3:
					clan_luck_modificator = 0.5;
					break;
				case 2:
					clan_luck_modificator = 0.5;
					break;
				case 1:
					clan_luck_modificator = 0.5;
					break;
				default:
					clan_luck_modificator = 1.0;
					break;				
			}
		}	
		
		//The death steal you some Exp
		double percentLost = Config.PLAYER_XP_PERCENT_LOST[getLevel()]*clan_luck_modificator;

		if (getKarma() > 0)
            percentLost *= Config.RATE_KARMA_EXP_LOST;

		if (isFestivalParticipant() || atwar)
            percentLost /= 4.0;

		// Calculate the Experience loss
		long lostExp = 0;
		if (!atEvent)
			if (lvl < Experience.MAX_LEVEL)
				lostExp = Math.round((getStat().getExpForLevel(lvl+1) - getStat().getExpForLevel(lvl)) * percentLost /100);
			else
				lostExp = Math.round((getStat().getExpForLevel(Experience.MAX_LEVEL) - getStat().getExpForLevel(Experience.MAX_LEVEL - 1)) * percentLost /100);

		// Get the Experience before applying penalty
		setExpBeforeDeath(getExp());

		// No xp loss inside pvp zone unless
		// - it's a siege zone and you're NOT participating
		// - you're killed by a non-pc whose not belong to the siege
		if (isInsideZone(ZONE_PVP))
		{
			// No xp loss for siege participants inside siege zone
			if (isInsideZone(ZONE_SIEGE))
			{
				if (isInSiege() && (killed_by_pc || killed_by_siege_npc))
					lostExp = 0;
			}
			else if (killed_by_pc)
				lostExp = 0;
		}

        if (Config.DEBUG)
            _log.fine(getName() + " died and lost " + lostExp + " experience.");

		// Set the new Experience value of the L2PcInstance
		getStat().addExp(-lostExp);
	}

	/**
	 * @param b
	 */
	public void setPartyMatchingAutomaticRegistration(boolean b)
	{
		_partyMatchingAutomaticRegistration = b;
	}

	/**
	 * @param b
	 */
	public void setPartyMatchingShowLevel(boolean b)
	{
		_partyMatchingShowLevel = b;
	}

	/**
	 * @param b
	 */
	public void setPartyMatchingShowClass(boolean b)
	{
		_partyMatchingShowClass = b;
	}

	/**
	 * @param memo
	 */
	public void setPartyMatchingMemo(String memo)
	{
		_partyMatchingMemo = memo;
	}

	public boolean isPartyMatchingAutomaticRegistration()
	{
		return _partyMatchingAutomaticRegistration;
	}

	public String getPartyMatchingMemo()
	{
		return _partyMatchingMemo;
	}

	public boolean isPartyMatchingShowClass()
	{
		return _partyMatchingShowClass;
	}

	public boolean isPartyMatchingShowLevel()
	{
		return _partyMatchingShowLevel;
	}

	/**
	 * Manage the increase level task of a L2PcInstance (Max MP, Max MP, Recommandation, Expertise and beginner skills...).<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Send a Server->Client System Message to the L2PcInstance : YOU_INCREASED_YOUR_LEVEL </li>
	 * <li>Send a Server->Client packet StatusUpdate to the L2PcInstance with new LEVEL, MAX_HP and MAX_MP </li>
	 * <li>Set the current HP and MP of the L2PcInstance, Launch/Stop a HP/MP/CP Regeneration Task and send StatusUpdate packet to all other L2PcInstance to inform (exclusive broadcast)</li>
	 * <li>Recalculate the party level</li>
	 * <li>Recalculate the number of Recommandation that the L2PcInstance can give</li>
	 * <li>Give Expertise skill of this level and remove beginner Lucky skill</li><BR><BR>
	 *
	 */
	public void increaseLevel()
	{
		// Set the current HP and MP of the L2Character, Launch/Stop a HP/MP/CP Regeneration Task and send StatusUpdate packet to all other L2PcInstance to inform (exclusive broadcast)
		setCurrentHpMp(getMaxHp(),getMaxMp());
		setCurrentCp(getMaxCp());
	}

	/**
	 * Stop the HP/MP/CP Regeneration task.<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Set the RegenActive flag to False </li>
	 * <li>Stop the HP/MP/CP Regeneration task </li><BR><BR>
	 *
	 */
	public void stopAllTimers()
	{
		stopHpMpRegeneration();
		stopWarnUserTakeBreak();
		stopWaterTask();
		stopFeed();
		clearPetData();
		storePetFood(_mountNpcId);
		stopRentPet();
		stopPvpRegTask();
		stopPunishTask(true);
		stopSoulTask();
		stopChargeTask();
		stopFameTask();
		stopVitalityTask();
	}

	/**
	 * Return the L2Summon of the L2PcInstance or null.<BR><BR>
	 */
	@Override
	public L2Summon getPet()
	{
		return _summon;
	}
	
	/**
     * Return the L2Decoy of the L2PcInstance or null.<BR><BR>
     */
    public L2Decoy getDecoy()
    {
        return _decoy;
    }
    
     /**
     * Return the L2Trap of the L2PcInstance or null.<BR><BR>
     */
    public L2Trap getTrap()
    {
    	return _trap;
    }

	/**
	 * Set the L2Summon of the L2PcInstance.<BR><BR>
	 */
	public void setPet(L2Summon summon)
	{
		_summon = summon;
		// update attack element value display
		if ((_summon == null || _summon instanceof L2SummonInstance)
				&& getClassId().isSummoner() && getAttackElement() != Elementals.NONE)
			sendPacket(new UserInfo(this));
			
	}
    /**
     * Set the L2Decoy of the L2PcInstance.<BR><BR>
     */
    public void setDecoy(L2Decoy decoy)
    {
        _decoy = decoy;
    }
    
    /**
     * Set the L2Trap of this L2PcInstance<BR><BR>
     * @param trap
     */
    public void setTrap(L2Trap trap)
    {
    	_trap = trap;
    }
    
	/**
	 * Return the L2Summon of the L2PcInstance or null.<BR><BR>
	 */
	public L2TamedBeastInstance getTrainedBeast()
	{
		return _tamedBeast;
	}

	/**
	 * Set the L2Summon of the L2PcInstance.<BR><BR>
	 */
	public void setTrainedBeast(L2TamedBeastInstance tamedBeast)
	{
		_tamedBeast = tamedBeast;
	}

	/**
	 * Return the L2PcInstance requester of a transaction (ex : FriendInvite, JoinAlly, JoinParty...).<BR><BR>
	 */
	public L2Request getRequest()
	{
		return _request;
	}

	/**
	 * Set the L2PcInstance requester of a transaction (ex : FriendInvite, JoinAlly, JoinParty...).<BR><BR>
	 */
	public synchronized void setActiveRequester(L2PcInstance requester)
	{
		_activeRequester = requester;
	}

	/**
	 * Return the L2PcInstance requester of a transaction (ex : FriendInvite, JoinAlly, JoinParty...).<BR><BR>
	 */
	public L2PcInstance getActiveRequester()
	{
		return _activeRequester;
	}

	/**
	 * Return True if a transaction is in progress.<BR><BR>
	 */
	public boolean isProcessingRequest()
	{
		return _activeRequester != null || _requestExpireTime > GameTimeController.getGameTicks();
	}

	/**
	 * Return True if a transaction is in progress.<BR><BR>
	 */
	public boolean isProcessingTransaction() { return _activeRequester != null || _activeTradeList != null || _requestExpireTime > GameTimeController.getGameTicks(); }

	/**
	 * Select the Warehouse to be used in next activity.<BR><BR>
	 */
	public void onTransactionRequest(L2PcInstance partner)
	{
		_requestExpireTime = GameTimeController.getGameTicks() + REQUEST_TIMEOUT * GameTimeController.TICKS_PER_SECOND;
		partner.setActiveRequester(this);
	}
	
	/**
	 * Return true if last request is expired.
	 * @return
	 */
	public boolean isRequestExpired()
	{
		return !(_requestExpireTime > GameTimeController.getGameTicks());
	}

	/**
	 * Select the Warehouse to be used in next activity.<BR><BR>
	 */
	public void onTransactionResponse()
    {
        _requestExpireTime = 0;
    }

	/**
	 * Select the Warehouse to be used in next activity.<BR><BR>
	 */
	public void setActiveWarehouse(ItemContainer warehouse)
    {
        _activeWarehouse = warehouse;
    }

	/**
	 * Return active Warehouse.<BR><BR>
	 */
	public ItemContainer getActiveWarehouse()
    {
        return _activeWarehouse;
    }

	/**
	 * Select the TradeList to be used in next activity.<BR><BR>
	 */
	public void setActiveTradeList(TradeList tradeList)
    {
        _activeTradeList = tradeList;
    }

	/**
	 * Return active TradeList.<BR><BR>
	 */
	public TradeList getActiveTradeList()
    {
        return _activeTradeList;
    }

	public void onTradeStart(L2PcInstance partner)
	{
		_activeTradeList = new TradeList(this);
		_activeTradeList.setPartner(partner);

		SystemMessage msg = new SystemMessage(SystemMessageId.BEGIN_TRADE_WITH_C1);
		msg.addPcName(partner);
		sendPacket(msg);
		sendPacket(new TradeStart(this));
	}

	public void onTradeConfirm(L2PcInstance partner)
	{
		SystemMessage msg = new SystemMessage(SystemMessageId.C1_CONFIRMED_TRADE);
		msg.addPcName(partner);
		sendPacket(msg);
		sendPacket(new TradeOtherDone());
	}

	public void onTradeCancel(L2PcInstance partner)
	{
		if (_activeTradeList == null)
            return;

		_activeTradeList.lock();
		_activeTradeList = null;

		sendPacket(new TradeDone(0));
		SystemMessage msg = new SystemMessage(SystemMessageId.C1_CANCELED_TRADE);
		msg.addPcName(partner);
		sendPacket(msg);
	}

	public void onTradeFinish(boolean successfull)
	{
		_activeTradeList = null;
		sendPacket(new TradeDone(1));
        if (successfull)
            sendPacket(new SystemMessage(SystemMessageId.TRADE_SUCCESSFUL));
	}

	public void startTrade(L2PcInstance partner)
	{
		onTradeStart(partner);
		partner.onTradeStart(this);
	}

	public void cancelActiveTrade()
	{
		if (_activeTradeList == null)
            return;

		L2PcInstance partner = _activeTradeList.getPartner();
		if (partner != null) partner.onTradeCancel(this);
		onTradeCancel(this);
	}

	/**
	 * Return the _createList object of the L2PcInstance.<BR><BR>
	 */
	public L2ManufactureList getCreateList()
	{
		return _createList;
	}

	/**
	 * Set the _createList object of the L2PcInstance.<BR><BR>
	 */
	public void setCreateList(L2ManufactureList x)
	{
		_createList = x;
	}

	/**
	 * Return the _buyList object of the L2PcInstance.<BR><BR>
	 */
	public TradeList getSellList()
	{
		if (_sellList == null) _sellList = new TradeList(this);
		return _sellList;
	}

	/**
	 * Return the _buyList object of the L2PcInstance.<BR><BR>
	 */
	public TradeList getBuyList()
	{
		if (_buyList == null) _buyList = new TradeList(this);
		return _buyList;
	}

	/**
	 * Set the Private Store type of the L2PcInstance.<BR><BR>
	 *
	 * <B><U> Values </U> :</B><BR><BR>
	 * <li>0 : STORE_PRIVATE_NONE</li>
	 * <li>1 : STORE_PRIVATE_SELL</li>
	 * <li>2 : sellmanage</li><BR>
	 * <li>3 : STORE_PRIVATE_BUY</li><BR>
	 * <li>4 : buymanage</li><BR>
	 * <li>5 : STORE_PRIVATE_MANUFACTURE</li><BR>
	 *
	 */
	public void setPrivateStoreType(int type)
	{
		_privatestore = type;
	}

	/**
	 * Return the Private Store type of the L2PcInstance.<BR><BR>
	 *
	 * <B><U> Values </U> :</B><BR><BR>
	 * <li>0 : STORE_PRIVATE_NONE</li>
	 * <li>1 : STORE_PRIVATE_SELL</li>
	 * <li>2 : sellmanage</li><BR>
	 * <li>3 : STORE_PRIVATE_BUY</li><BR>
	 * <li>4 : buymanage</li><BR>
	 * <li>5 : STORE_PRIVATE_MANUFACTURE</li><BR>
	 *
	 */
	public int getPrivateStoreType()
	{
		return _privatestore;
	}

	/**
	 * Set the _skillLearningClassId object of the L2PcInstance.<BR><BR>
	 */
	public void setSkillLearningClassId(ClassId classId)
	{
		_skillLearningClassId = classId;
	}

	/**
	 * Return the _skillLearningClassId object of the L2PcInstance.<BR><BR>
	 */
	public ClassId getSkillLearningClassId()
	{
		return _skillLearningClassId;
	}

	/**
	 * Set the _clan object, _clanId, _clanLeader Flag and title of the L2PcInstance.<BR><BR>
	 */
	public void setClan(L2Clan clan)
	{
		_clan = clan;
		setTitle("");

		if (clan == null)
		{
			_clanId = 0;
			_clanPrivileges = 0;
			_pledgeType = 0;
			_powerGrade = 0;
			_lvlJoinedAcademy = 0;
			_apprentice = 0;
			_sponsor = 0;
			if (_isOnline)
				CommunityServerThread.getInstance().sendPacket(new WorldInfo(this, null, WorldInfo.TYPE_UPDATE_PLAYER_DATA));
			return;
		}

		if (!clan.isMember(getObjectId()))
		{
			// char has been kicked from clan
			setClan(null);
			return;
		}

		_clanId = clan.getClanId();
		if (_isOnline)
			CommunityServerThread.getInstance().sendPacket(new WorldInfo(this, null, WorldInfo.TYPE_UPDATE_PLAYER_DATA));
	}

	/**
	 * Return the _clan object of the L2PcInstance.<BR><BR>
	 */
	public L2Clan getClan()
	{
		return _clan;
	}

	/**
	 * Return True if the L2PcInstance is the leader of its clan.<BR><BR>
	 */
	public boolean isClanLeader()
	{
		if (getClan() == null)
		{
			return false;
		}
		else
		{
			return getObjectId() == getClan().getLeaderId();
		}
	}

	/**
	 * Reduce the number of arrows/bolts owned by the L2PcInstance and send it Server->Client Packet InventoryUpdate or ItemList (to unequip if the last arrow was consummed).<BR><BR>
	 */
	@Override
	protected void reduceArrowCount(boolean bolts)
	{
	    L2ItemInstance arrows = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);

	    if (arrows == null)
        {
            getInventory().unEquipItemInSlot(Inventory.PAPERDOLL_LHAND);
            if (bolts) 
                _boltItem = null;
            else
                _arrowItem = null;
            sendPacket(new ItemList(this,false));
            return;
        }
	    
	    // Adjust item quantity
        if (arrows.getCount() > 1)
        {
            synchronized(arrows)
            {
                arrows.changeCountWithoutTrace(-1, this, null);
                arrows.setLastChange(L2ItemInstance.MODIFIED);

                // could do also without saving, but let's save approx 1 of 10
                if(GameTimeController.getGameTicks() % 10 == 0)
                    arrows.updateDatabase();
                _inventory.refreshWeight();
            }
        }
        else
        {
            // Destroy entire item and save to database
            _inventory.destroyItem("Consume", arrows, this, null);
            
            getInventory().unEquipItemInSlot(Inventory.PAPERDOLL_LHAND);
            if (bolts) 
                _boltItem = null;
            else
                _arrowItem = null;

            if (Config.DEBUG) _log.fine("removed arrows count");
            sendPacket(new ItemList(this,false));
            return;
        }
	    
		if (!Config.FORCE_INVENTORY_UPDATE)
		{
		    InventoryUpdate iu = new InventoryUpdate();
		    iu.addModifiedItem(arrows);
		    sendPacket(iu);
		}
		else sendPacket(new ItemList(this, false));
	}

	/**
	 * Equip arrows needed in left hand and send a Server->Client packet ItemList to the L2PcINstance then return True.<BR><BR>
	 */
	@Override
	protected boolean checkAndEquipArrows()
	{
		// Check if nothing is equiped in left hand
		if (getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND) == null)
		{
			// Get the L2ItemInstance of the arrows needed for this bow
			_arrowItem = getInventory().findArrowForBow(getActiveWeaponItem());

			if (_arrowItem != null)
			{
				// Equip arrows needed in left hand
				getInventory().setPaperdollItem(Inventory.PAPERDOLL_LHAND, _arrowItem);

				// Send a Server->Client packet ItemList to this L2PcINstance to update left hand equipement
				ItemList il = new ItemList(this, false);
				sendPacket(il);
			}
		}
		else
		{
			// Get the L2ItemInstance of arrows equiped in left hand
			_arrowItem = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
		}

		return _arrowItem != null;
	}

    /**
     * Equip bolts needed in left hand and send a Server->Client packet ItemList to the L2PcINstance then return True.<BR><BR>
     */
    @Override
    protected boolean checkAndEquipBolts()
    {
        // Check if nothing is equiped in left hand
        if (getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND) == null)
        {
            // Get the L2ItemInstance of the arrows needed for this bow
            _boltItem = getInventory().findBoltForCrossBow(getActiveWeaponItem());

            if (_boltItem != null)
            {
                // Equip arrows needed in left hand
                getInventory().setPaperdollItem(Inventory.PAPERDOLL_LHAND, _boltItem);

                // Send a Server->Client packet ItemList to this L2PcINstance to update left hand equipement
                ItemList il = new ItemList(this, false);
                sendPacket(il);
            }
        }
        else
        {
            // Get the L2ItemInstance of arrows equiped in left hand
            _boltItem = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
        }

        return _boltItem != null;
    }
	/**
	 * Disarm the player's weapon.<BR><BR>
	 */
	public boolean disarmWeapons()
	{
        // Don't allow disarming a cursed weapon
        if (isCursedWeaponEquipped()) return false;

        // Unequip the weapon
        L2ItemInstance wpn = getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
        if (wpn == null) wpn = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LRHAND);
        if (wpn != null)
        {
        	if (wpn.isWear())
        		return false;

            L2ItemInstance[] unequiped = getInventory().unEquipItemInBodySlotAndRecord(wpn.getItem().getBodyPart());
            InventoryUpdate iu = new InventoryUpdate();
            for (L2ItemInstance itm: unequiped)
                iu.addModifiedItem(itm);
            sendPacket(iu);

            abortAttack();
            broadcastUserInfo();

            // this can be 0 if the user pressed the right mousebutton twice very fast
            if (unequiped.length > 0)
            {
                SystemMessage sm = null;
                if (unequiped[0].getEnchantLevel() > 0)
                {
                    sm = new SystemMessage(SystemMessageId.EQUIPMENT_S1_S2_REMOVED);
                    sm.addNumber(unequiped[0].getEnchantLevel());
                    sm.addItemName(unequiped[0]);
                }
                else
                {
                    sm = new SystemMessage(SystemMessageId.S1_DISARMED);
                    sm.addItemName(unequiped[0]);
                }
                sendPacket(sm);
            }
        }
        return true;
	}

	/**
	 * Disarm the player's shield.<BR><BR>
	 */
	public boolean disarmShield()
	{
		L2ItemInstance sld = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
		if (sld != null)
		{
			if (sld.isWear())
				return false;

			L2ItemInstance[] unequiped = getInventory().unEquipItemInBodySlotAndRecord(sld.getItem().getBodyPart());
			InventoryUpdate iu = new InventoryUpdate();
			for (L2ItemInstance itm: unequiped)
				iu.addModifiedItem(itm);
			sendPacket(iu);

			abortAttack();
			broadcastUserInfo();

			// this can be 0 if the user pressed the right mousebutton twice very fast
			if (unequiped.length > 0)
			{
				SystemMessage sm = null;
				if (unequiped[0].getEnchantLevel() > 0)
				{
					sm = new SystemMessage(SystemMessageId.EQUIPMENT_S1_S2_REMOVED);
					sm.addNumber(unequiped[0].getEnchantLevel());
					sm.addItemName(unequiped[0]);
				}
				else
				{
					sm = new SystemMessage(SystemMessageId.S1_DISARMED);
					sm.addItemName(unequiped[0]);
				}
				sendPacket(sm);
			}
		}
		return true;
	}

    public boolean mount(L2Summon pet)
    {
        if (!disarmWeapons())
            return false;
        if (!disarmShield())
        	return false;
        if (isTransformed())
        	return false;
        
        for (L2Effect e : getAllEffects())
        {
        	if (e != null && e.getSkill().isToggle())
        		e.exit();
        }
        Ride mount = new Ride(this, true, pet.getTemplate().npcId);
        setMount(pet.getNpcId(), pet.getLevel(), mount.getMountType());
        setMountObjectID(pet.getControlItemId());
        clearPetData();
        startFeed(pet.getNpcId());
        broadcastPacket(mount);
        
        // Notify self and others about speed change
        broadcastUserInfo();
        
        pet.unSummon(this);
        
        return true;
    }
    
    public boolean mount(int npcId, int controlItemObjId,boolean useFood)
    {
        if (!disarmWeapons())
            return false;
        if (!disarmShield())
        	return false;
        if (isTransformed())
        	return false;
        
        for (L2Effect e : getAllEffects())
        {
        	if (e != null && e.getSkill().isToggle())
        		e.exit();
        }
        Ride mount = new Ride(this, true, npcId);
        if (setMount(npcId, getLevel(), mount.getMountType()))
        {
        	clearPetData();
        	setMountObjectID(controlItemObjId);
        	broadcastPacket(mount);
        
        	// Notify self and others about speed change
        	broadcastUserInfo();
        	if (useFood)
        		startFeed(npcId);
        	return true;
        }
        return false;
    }
    
    public boolean mountPlayer(L2Summon pet)
    {
    	if (pet != null && pet.isMountable() && !isMounted() && !isBetrayed())
    	{
    		if (isDead())
    		{
    			//A strider cannot be ridden when dead
    			sendPacket(ActionFailed.STATIC_PACKET);
    			sendPacket(new SystemMessage(SystemMessageId.STRIDER_CANT_BE_RIDDEN_WHILE_DEAD));
    			return false;
    		}
    		else if (pet.isDead())
    		{
    			//A dead strider cannot be ridden.
    			sendPacket(ActionFailed.STATIC_PACKET);
    			sendPacket(new SystemMessage(SystemMessageId.DEAD_STRIDER_CANT_BE_RIDDEN));
    			return false;
    		}
    		else if (pet.isInCombat() || pet.isRooted())
    		{
    			//A strider in battle cannot be ridden
    			sendPacket(ActionFailed.STATIC_PACKET);
    			sendPacket(new SystemMessage(SystemMessageId.STRIDER_IN_BATLLE_CANT_BE_RIDDEN));
    			return false;
    			
    		}
    		else if (isInCombat())
    		{
    			//A strider cannot be ridden while in battle
    			sendPacket(ActionFailed.STATIC_PACKET);
    			sendPacket(new SystemMessage(SystemMessageId.STRIDER_CANT_BE_RIDDEN_WHILE_IN_BATTLE));
    			return false;
    		}
    		else if (isSitting())
    		{
    			//A strider can be ridden only when standing
    			sendPacket(ActionFailed.STATIC_PACKET);
    			sendPacket(new SystemMessage(SystemMessageId.STRIDER_CAN_BE_RIDDEN_ONLY_WHILE_STANDING));
    			return false;
    		}
    		else if (isFishing())
    		{
    			//You can't mount, dismount, break and drop items while fishing
    			sendPacket(ActionFailed.STATIC_PACKET);
    			sendPacket(new SystemMessage(SystemMessageId.CANNOT_DO_WHILE_FISHING_2));
    			return false;
    		}
    		else if (isTransformed() || isCursedWeaponEquipped())
    		{
    			// no message needed, player while transformed doesn't have mount action
    			sendPacket(ActionFailed.STATIC_PACKET);
    			return false;
    		}
    		else if (getInventory().getItemByItemId(9819) != null)
    		{
    			sendPacket(ActionFailed.STATIC_PACKET);
    			sendPacket(new SystemMessage(SystemMessageId.YOU_CANNOT_MOUNT_A_STEED_WHILE_HOLDING_A_FLAG)); // TODO: confirm this message
    			return false;
    		}
    		else if (pet.isHungry())
    		{
    			sendPacket(ActionFailed.STATIC_PACKET);
    			sendPacket(new SystemMessage(SystemMessageId.HUNGRY_STRIDER_NOT_MOUNT));
    			return false;
    		}
    		else if (!Util.checkIfInRange(200, this, pet, true))
    		{
    			sendPacket(ActionFailed.STATIC_PACKET);
    			sendPacket(new SystemMessage(SystemMessageId.TOO_FAR_AWAY_FROM_FENRIR_TO_MOUNT));
    			return false;				
    		}
    		else if (!pet.isDead() && !isMounted())
    		{
    			mount(pet);
    		}
    	}
    	else if (isRentedPet())
    	{
    		stopRentPet();
    	}
    	else if (isMounted())
    	{
    		if (getMountType() == 2 && this.isInsideZone(L2Character.ZONE_NOLANDING))
    		{
    			sendPacket(ActionFailed.STATIC_PACKET);
    			sendPacket(new SystemMessage(SystemMessageId.NO_DISMOUNT_HERE));
    			return false;
    		}
    		else if (isHungry())
    		{
    			sendPacket(ActionFailed.STATIC_PACKET);
    			sendPacket(new SystemMessage(SystemMessageId.HUNGRY_STRIDER_NOT_MOUNT));
    			return false;
    		}
    		else
    			dismount();
    	}
    	return true;
    }
    
	public boolean dismount()
	{
		boolean wasFlying = isFlying();
		
		sendPacket(new SetupGauge(3, 0, 0));
		int petId = _mountNpcId;
	    if (setMount(0, 0, 0))
	    {
	    	stopFeed();
	    	clearPetData();
	        if (wasFlying) 
	            removeSkill(SkillTable.getInstance().getInfo(4289, 1));
	        Ride dismount = new Ride(this, false, 0);
	        broadcastPacket(dismount);
	        setMountObjectID(0);
	        storePetFood(petId);
            // Notify self and others about speed change
            this.broadcastUserInfo();
	        return true;
	    }
        return false;
	}

	/**
	 * Return True if the L2PcInstance use a dual weapon.<BR><BR>
	 */
	@Override
	public boolean isUsingDualWeapon()
	{
		L2Weapon weaponItem = getActiveWeaponItem();
		if (weaponItem == null) return false;

		if (weaponItem.getItemType() == L2WeaponType.DUAL)
			return true;
		else if (weaponItem.getItemType() == L2WeaponType.DUALFIST)
			return true;
		else if (weaponItem.getItemId() == 248) // orc fighter fists
			return true;
		else if (weaponItem.getItemId() == 252) // orc mage fists
			return true;
		else
			return false;
	}

	public void setUptime(long time)
	{
		_uptime = time;
	}

	public long getUptime()
	{
		return System.currentTimeMillis()-_uptime;
	}

	/**
	 * Return True if the L2PcInstance is invulnerable.<BR><BR>
	 */
	@Override
	public boolean isInvul()
	{
		return _isInvul  || _isTeleporting ||  _protectEndTime > GameTimeController.getGameTicks();
	}

	/**
	 * Return True if the L2PcInstance has a Party in progress.<BR><BR>
	 */
	@Override
	public boolean isInParty()
	{
		return _party != null;
	}

	/**
	 * Set the _party object of the L2PcInstance (without joining it).<BR><BR>
	 */
	public void setParty(L2Party party)
	{
		_party = party;
	}

	/**
	 * Set the _party object of the L2PcInstance AND join it.<BR><BR>
	 */
	public void joinParty(L2Party party)
	{
		if (party != null)
		{
            // First set the party otherwise this wouldn't be considered
            // as in a party into the L2Character.updateEffectIcons() call.
            _party = party;
			party.addPartyMember(this);
		}
	}


	/**
	 * Manage the Leave Party task of the L2PcInstance.<BR><BR>
	 */
	public void leaveParty()
	{
		if (isInParty())
		{
			_party.removePartyMember(this);
			_party = null;
		}
	}

	/**
	 * Return the _party object of the L2PcInstance.<BR><BR>
	 */
	@Override
	public L2Party getParty()
	{
		return _party;
	}

	/**
	 * Return True if the L2PcInstance is a GM.<BR><BR>
	 */
	public boolean isGM()
	{
		return getAccessLevel().isGm();
	}

	/**
	 * Set the _accessLevel of the L2PcInstance.<BR><BR>
	 */
	public void setAccessLevel(int level)
	{
		if (level == AccessLevels._masterAccessLevelNum)
		{
			_log.warning( "Master access level set for character " + getName() + "! Just a warning to be careful ;)" );
			_accessLevel = AccessLevels._masterAccessLevel;
		}
		else if (level == AccessLevels._userAccessLevelNum)
			_accessLevel = AccessLevels._userAccessLevel;
		else
		{
			L2AccessLevel accessLevel = AccessLevels.getInstance().getAccessLevel(level);

			if (accessLevel == null)
			{
				if (level < 0)
				{
					AccessLevels.getInstance().addBanAccessLevel(level);
					_accessLevel = AccessLevels.getInstance().getAccessLevel(level);
				}
				else
				{
					_log.warning( "Tryed to set unregistered access level " + level + " to character " + getName() + ". Setting access level without privileges!" );
					_accessLevel = AccessLevels._userAccessLevel;
				}
			}
			else
				_accessLevel = accessLevel;
		}

		if (_accessLevel != AccessLevels._userAccessLevel)
		{
			getAppearance().setNameColor(_accessLevel.getNameColor());
			getAppearance().setTitleColor(_accessLevel.getTitleColor());
			broadcastUserInfo();
		}
		CharNameTable.getInstance().addName(this);
	}

	public void setAccountAccesslevel(int level)
	{
		LoginServerThread.getInstance().sendAccessLevel(getAccountName(),level);
	}

	/**
	 * Return the _accessLevel of the L2PcInstance.<BR><BR>
	 */
	public L2AccessLevel getAccessLevel()
	{
		if (Config.EVERYBODY_HAS_ADMIN_RIGHTS)
			return AccessLevels._masterAccessLevel;
		else if ( _accessLevel == null ) /* This is here because inventory etc. is loaded before access level on login, so it is not null */
			setAccessLevel(AccessLevels._userAccessLevelNum);

		return _accessLevel;
	}

	@Override
	public double getLevelMod()
	{
		return (100.0 - 11 + getLevel()) / 100.0;
	}

	/**
	 * Update Stats of the L2PcInstance client side by sending Server->Client packet UserInfo/StatusUpdate to this L2PcInstance and CharInfo/StatusUpdate to all L2PcInstance in its _KnownPlayers (broadcast).<BR><BR>
	 */
	public void updateAndBroadcastStatus(int broadcastType)
	{
		refreshOverloaded();
		refreshExpertisePenalty();
		// Send a Server->Client packet UserInfo to this L2PcInstance and CharInfo to all L2PcInstance in its _KnownPlayers (broadcast)
		if (broadcastType == 1)
		{
			sendPacket(new UserInfo(this));
			sendPacket(new ExBrExtraUserInfo(this));
		}
		if (broadcastType == 2) broadcastUserInfo();
	}

	/**
	 * Send a Server->Client StatusUpdate packet with Karma and PvP Flag to the L2PcInstance and all L2PcInstance to inform (broadcast).<BR><BR>
	 */
	public void setKarmaFlag(int flag)
	{
		sendPacket(new UserInfo(this));
		sendPacket(new ExBrExtraUserInfo(this));
		Collection<L2PcInstance> plrs = getKnownList().getKnownPlayers().values();
		//synchronized (getKnownList().getKnownPlayers())
		{
			for (L2PcInstance player : plrs)
			{
				player.sendPacket(new RelationChanged(this, getRelation(player), isAutoAttackable(player)));
				if (getPet() != null)
					player.sendPacket(new RelationChanged(getPet(), getRelation(player), isAutoAttackable(player)));
			}
		}
	}

	/**
	 * Send a Server->Client StatusUpdate packet with Karma to the L2PcInstance and all L2PcInstance to inform (broadcast).<BR><BR>
	 */
	public void broadcastKarma()
	{
        StatusUpdate su = new StatusUpdate(getObjectId());
        su.addAttribute(StatusUpdate.KARMA, getKarma());
        sendPacket(su);

        Collection<L2PcInstance> plrs = getKnownList().getKnownPlayers().values();
        //synchronized (getKnownList().getKnownPlayers())
		{
			for (L2PcInstance player : plrs)
			{
				player.sendPacket(new RelationChanged(this, getRelation(player), isAutoAttackable(player)));
				if (getPet() != null)
					player.sendPacket(new RelationChanged(getPet(), getRelation(player), isAutoAttackable(player)));
			}
		}
	}

	/**
	 * Set the online Flag to True or False and update the characters table of the database with online status and lastAccess (called when login and logout).<BR><BR>
	 */
	public void setOnlineStatus(boolean isOnline)
	{
		if (_isOnline != isOnline)
			_isOnline = isOnline;

		// Update the characters table of the database with online status and lastAccess (called when login and logout)
		updateOnlineStatus();
	}
    
    public void setIsIn7sDungeon(boolean isIn7sDungeon)
    {
        _isIn7sDungeon = isIn7sDungeon;
    }

	/**
	 * Update the characters table of the database with online status and lastAccess of this L2PcInstance (called when login and logout).<BR><BR>
	 */
	public void updateOnlineStatus()
	{
		Connection con = null;
		try
        {
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement("UPDATE characters SET online=?, lastAccess=? WHERE charId=?");
			statement.setInt(1, isOnline());
			statement.setLong(2, System.currentTimeMillis());
			statement.setInt(3, getObjectId());
			statement.execute();
			statement.close();
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "Failed updating character online status.", e);
		}
		finally
		{
			try { con.close(); } catch (Exception e) {}
		}
	}

	/**
	 * Create a new player in the characters table of the database.<BR><BR>
	 */
	private boolean createDb()
	{
		Connection con = null;
		try
		{
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement(INSERT_CHARACTER);
			
			statement.setString(1, _accountName);
			statement.setInt(2, getObjectId());
			statement.setString(3, getName());
			statement.setInt(4, getLevel());
			statement.setInt(5, getMaxHp());
			statement.setDouble(6, getCurrentHp());
			statement.setInt(7, getMaxCp());
			statement.setDouble(8, getCurrentCp());
			statement.setInt(9, getMaxMp());
			statement.setDouble(10, getCurrentMp());
			statement.setInt(11, getAppearance().getFace());
			statement.setInt(12, getAppearance().getHairStyle());
			statement.setInt(13, getAppearance().getHairColor());
			statement.setInt(14, getAppearance().getSex()? 1 : 0);
			statement.setLong(15, getExp());
			statement.setInt(16, getSp());
			statement.setInt(17, getKarma());
			statement.setInt(18, getFame());
			statement.setInt(19, getPvpKills());
			statement.setInt(20, getPkKills());
			statement.setInt(21, getClanId());
			statement.setInt(22, getRace().ordinal());
			statement.setInt(23, getClassId().getId());
			statement.setLong(24, getDeleteTimer());
			statement.setInt(25, hasDwarvenCraft() ? 1 : 0);
			statement.setString(26, getTitle());
			statement.setInt(27, getAppearance().getTitleColor());
			statement.setInt(28, getAccessLevel().getLevel());
			statement.setInt(29, isOnline());
            statement.setInt(30, isIn7sDungeon() ? 1 : 0);
			statement.setInt(31, getClanPrivileges());
			statement.setInt(32, getWantsPeace());
			statement.setInt(33, getBaseClass());
			statement.setInt(34, getNewbie());
			statement.setInt(35, isNoble() ? 1 :0);
			statement.setLong(36, 0);
			statement.setLong(37,System.currentTimeMillis());
			statement.setLong(38,getCreateTime()); 
			
			statement.executeUpdate();
			statement.close();
		}
		catch (Exception e)
		{
			_log.severe("Could not insert char data: " + e);
			return false;
		}
		finally
		{
			try { con.close(); } catch (Exception e) {}
		}
		return true;
	}

	/**
	 * Retrieve a L2PcInstance from the characters table of the database and add it in _allObjects of the L2world.<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Retrieve the L2PcInstance from the characters table of the database </li>
	 * <li>Add the L2PcInstance object in _allObjects </li>
	 * <li>Set the x,y,z position of the L2PcInstance and make it invisible</li>
	 * <li>Update the overloaded status of the L2PcInstance</li><BR><BR>
	 *
	 * @param objectId Identifier of the object to initialized
	 *
	 * @return The L2PcInstance loaded from the database
	 *
	 */
	private static L2PcInstance restore(int objectId)
	{
		L2PcInstance player = null;
		Connection con = null;

		try
		{
			// Retrieve the L2PcInstance from the characters table of the database
			con = L2DatabaseFactory.getInstance().getConnection();

			PreparedStatement statement = con.prepareStatement(RESTORE_CHARACTER);
			statement.setInt(1, objectId);
			ResultSet rset = statement.executeQuery();

			double currentCp = 0;
			double currentHp = 0;
			double currentMp = 0;

			while (rset.next())
			{
				final int activeClassId = rset.getInt("classid");
				final boolean female = rset.getInt("sex")!=0;
				final L2PcTemplate template = CharTemplateTable.getInstance().getTemplate(activeClassId);
				PcAppearance app = new PcAppearance(rset.getByte("face"), rset.getByte("hairColor"), rset.getByte("hairStyle"), female);

				player = new L2PcInstance(objectId, template, rset.getString("account_name"), app);
				player.setName(rset.getString("char_name"));
				player._lastAccess = rset.getLong("lastAccess");

				player.getStat().setExp(rset.getLong("exp"));
				player.setExpBeforeDeath(rset.getLong("expBeforeDeath"));
				player.getStat().setLevel(rset.getByte("level"));
				player.getStat().setSp(rset.getInt("sp"));

				player.setWantsPeace(rset.getInt("wantspeace"));

				player.setHeading(rset.getInt("heading"));

				player.setKarma(rset.getInt("karma"));
				player.setFame(rset.getInt("fame"));
				player.setPvpKills(rset.getInt("pvpkills"));
				player.setPkKills(rset.getInt("pkkills"));
				player.setOnlineTime(rset.getLong("onlinetime"));
				player.setNewbie(rset.getInt("newbie"));
				player.setNoble(rset.getInt("nobless")==1);

				player.setClanJoinExpiryTime(rset.getLong("clan_join_expiry_time"));
				if (player.getClanJoinExpiryTime() < System.currentTimeMillis())
				{
					player.setClanJoinExpiryTime(0);
				}
				player.setClanCreateExpiryTime(rset.getLong("clan_create_expiry_time"));
				if (player.getClanCreateExpiryTime() < System.currentTimeMillis())
				{
					player.setClanCreateExpiryTime(0);
				}

				int clanId	= rset.getInt("clanid");
				player.setPowerGrade((int)rset.getLong("power_grade"));
				player.setPledgeType(rset.getInt("subpledge"));
				player.setLastRecomUpdate(rset.getLong("last_recom_date"));
				//player.setApprentice(rset.getInt("apprentice"));

				if (clanId > 0)
				{
					player.setClan(ClanTable.getInstance().getClan(clanId));
				}

				if (player.getClan() != null)
                {
                    if (player.getClan().getLeaderId() != player.getObjectId())
                    {
                        if (player.getPowerGrade() == 0)
                        {
                        	player.setPowerGrade(5);
                        }
                    	player.setClanPrivileges(player.getClan().getRankPrivs(player.getPowerGrade()));
                    }
                    else
                    {
                    	player.setClanPrivileges(L2Clan.CP_ALL);
                    	player.setPowerGrade(1);
                    }
                }
                else
            	{
                	player.setClanPrivileges(L2Clan.CP_NOTHING);
            	}

				player.setDeleteTimer(rset.getLong("deletetime"));

				player.setTitle(rset.getString("title"));
				player.getAppearance().setTitleColor(rset.getInt("title_color"));
				player.setAccessLevel(rset.getInt("accesslevel"));
				player.setFistsWeaponItem(player.findFistsWeaponItem(activeClassId));
				player.setUptime(System.currentTimeMillis());

				currentHp = rset.getDouble("curHp");
				currentCp = rset.getDouble("curCp");
				currentMp = rset.getDouble("curMp");

				//Check recs
				player.checkRecom(rset.getInt("rec_have"),rset.getInt("rec_left"));

				player._classIndex = 0;
				try { player.setBaseClass(rset.getInt("base_class")); }
				catch (Exception e) { player.setBaseClass(activeClassId); }

				// Restore Subclass Data (cannot be done earlier in function)
                if (restoreSubClassData(player))
                {
                	if (activeClassId != player.getBaseClass())
                	{
                    	for (SubClass subClass : player.getSubClasses().values())
                    		if (subClass.getClassId() == activeClassId)
                    			player._classIndex = subClass.getClassIndex();
                	}
                }
                if (player.getClassIndex() == 0 && activeClassId != player.getBaseClass())
                {
                	// Subclass in use but doesn't exist in DB -
                	// a possible restart-while-modifysubclass cheat has been attempted.
                	// Switching to use base class
                	player.setClassId(player.getBaseClass());
                	_log.warning("Player "+player.getName()+" reverted to base class. Possibly has tried a relogin exploit while subclassing.");
                }
                else player._activeClass = activeClassId;

                player.setApprentice(rset.getInt("apprentice"));
                player.setSponsor(rset.getInt("sponsor"));
                player.setLvlJoinedAcademy(rset.getInt("lvl_joined_academy"));
                player.setIsIn7sDungeon(rset.getInt("isin7sdungeon") == 1);
                player.setPunishLevel(rset.getInt("punish_level"));
                if (player.getPunishLevel() != PunishLevel.NONE)
                	player.setPunishTimer(rset.getLong("punish_timer"));
                else
                	player.setPunishTimer(0);
                
                CursedWeaponsManager.getInstance().checkPlayer(player);

                player.setAllianceWithVarkaKetra(rset.getInt("varka_ketra_ally"));

                player.setDeathPenaltyBuffLevel(rset.getInt("death_penalty_level"));

                player.setVitalityPoints(rset.getInt("vitality_points"), true);

                // Add the L2PcInstance object in _allObjects
				//L2World.getInstance().storeObject(player);

				// Set the x,y,z position of the L2PcInstance and make it invisible
				player.setXYZInvisible(rset.getInt("x"), rset.getInt("y"), rset.getInt("z"));

				// Set Teleport Bookmark Slot
				player.setBookMarkSlot(rset.getInt("BookmarkSlot"));
				
				//character creation Time 
				player.setCreateTime(rset.getLong("createTime")); 
				
				// Retrieve the name and ID of the other characters assigned to this account.
				PreparedStatement stmt = con.prepareStatement("SELECT charId, char_name FROM characters WHERE account_name=? AND charId<>?");
				stmt.setString(1, player._accountName);
				stmt.setInt(2, objectId);
				ResultSet chars = stmt.executeQuery();

				while (chars.next())
				{
					Integer charId = chars.getInt("charId");
					String charName = chars.getString("char_name");
					player._chars.put(charId, charName);
				}

				chars.close();
				stmt.close();
				break;
			}

			rset.close();
			statement.close();

			// Retrieve from the database all secondary data of this L2PcInstance
			// and reward expertise/lucky skills if necessary.
			// Note that Clan, Noblesse and Hero skills are given separately and not here.
			player.restoreCharData();
			player.rewardSkills();
			
		    // buff and status icons
	        if (Config.STORE_SKILL_COOLTIME)
	            player.restoreEffects();

			// Restore current Cp, HP and MP values
			player.setCurrentCp(currentCp);
			player.setCurrentHp(currentHp);
			player.setCurrentMp(currentMp);
			
			if (currentHp < 0.5) {
				player.setIsDead(true);
				player.stopHpMpRegeneration();
			}

			// Restore pet if exists in the world
			player.setPet(L2World.getInstance().getPet(player.getObjectId()));
			if(player.getPet() != null) player.getPet().setOwner(player);

			// Update the overloaded status of the L2PcInstance
			player.refreshOverloaded();
	        // Update the expertise status of the L2PcInstance
	        player.refreshExpertisePenalty();
	        
	        player.restoreFriendList(); 
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "Failed loading character.", e);
		}
		finally
		{
			try { con.close(); } catch (Exception e) {}
		}

		return player;
	}

	/**
	 * @return
	 */
	public Forum getMail()
	{
		if (_forumMail == null)
		{
			setMail(ForumsBBSManager.getInstance().getForumByName("MailRoot").getChildByName(getName()));

			if (_forumMail == null)
			{
				ForumsBBSManager.getInstance().createNewForum(getName(),ForumsBBSManager.getInstance().getForumByName("MailRoot"),Forum.MAIL,Forum.OWNERONLY,getObjectId());
				setMail(ForumsBBSManager.getInstance().getForumByName("MailRoot").getChildByName(getName()));
			}
		}

		return _forumMail;
	}

	/**
	 * @param forum
	 */
	public void setMail(Forum forum)
	{
		_forumMail = forum;
	}

	/**
	 * @return
	 */
	public Forum getMemo()
	{
		if (_forumMemo == null)
		{
			setMemo(ForumsBBSManager.getInstance().getForumByName("MemoRoot").getChildByName(_accountName));
			
			if (_forumMemo == null)
			{
				ForumsBBSManager.getInstance().createNewForum(_accountName, ForumsBBSManager.getInstance().getForumByName("MemoRoot"), Forum.MEMO, Forum.OWNERONLY, getObjectId());
				setMemo(ForumsBBSManager.getInstance().getForumByName("MemoRoot").getChildByName(_accountName));
			}
		}

		return _forumMemo;
	}

	/**
	 * @param forum
	 */
	public void setMemo(Forum forum)
	{
		_forumMemo = forum;
	}

    /**
     * Restores sub-class data for the L2PcInstance, used to check the current
     * class index for the character.
     */
    private static boolean restoreSubClassData(L2PcInstance player)
    {
        Connection con = null;

        try
        {
            con = L2DatabaseFactory.getInstance().getConnection();
            PreparedStatement statement = con.prepareStatement(RESTORE_CHAR_SUBCLASSES);
            statement.setInt(1, player.getObjectId());

            ResultSet rset = statement.executeQuery();

            while (rset.next())
            {
                SubClass subClass = new SubClass();
                subClass.setClassId(rset.getInt("class_id"));
                subClass.setLevel(rset.getByte("level"));
                subClass.setExp(rset.getLong("exp"));
                subClass.setSp(rset.getInt("sp"));
                subClass.setClassIndex(rset.getInt("class_index"));

                // Enforce the correct indexing of _subClasses against their class indexes.
                player.getSubClasses().put(subClass.getClassIndex(), subClass);
            }

            statement.close();
        }
        catch (Exception e) {
            _log.warning("Could not restore classes for " + player.getName() + ": " + e);
            e.printStackTrace();
        }
        finally {
            try { con.close(); } catch (Exception e) {}
        }

        return true;
    }

	/**
	 * Restores secondary data for the L2PcInstance, based on the current class index.
	 */
	private void restoreCharData()
	{
		// Retrieve from the database all skills of this L2PcInstance and add them to _skills.
		restoreSkills();

		// Retrieve from the database all macroses of this L2PcInstance and add them to _macroses.
		_macroses.restore();

		// Retrieve from the database all shortCuts of this L2PcInstance and add them to _shortCuts.
		_shortCuts.restore();

		// Retrieve from the database all henna of this L2PcInstance and add them to _henna.
		restoreHenna();

		// Retrieve from the database all teleport bookmark of this L2PcInstance and add them to _tpbookmark.
		restoreTeleportBookmark();

		// Retrieve from the database all recom data of this L2PcInstance and add to _recomChars.
		if (Config.ALT_RECOMMEND) restoreRecom();

		// Retrieve from the database the recipe book of this L2PcInstance.
		restoreRecipeBook(true);
		
		// Restore Recipe Shop list
		if(Config.STORE_RECIPE_SHOPLIST)
			restoreRecipeShopList();
	}

	/**
	 * Restore recipe book data for this L2PcInstance.
	 */
	private void restoreRecipeBook(boolean loadCommon)
	{
		Connection con = null;

		try {
			con = L2DatabaseFactory.getInstance().getConnection();
			String sql = loadCommon ? "SELECT id, type, classIndex FROM character_recipebook WHERE charId=?" :
											"SELECT id FROM character_recipebook WHERE charId=? AND classIndex=? AND type = 1";
			PreparedStatement statement = con.prepareStatement(sql);
			statement.setInt(1, getObjectId());
			if (!loadCommon)
				statement.setInt(2, _classIndex);
			ResultSet rset = statement.executeQuery();

			_dwarvenRecipeBook.clear();
			
			L2RecipeList recipe;
			while (rset.next()) {
				recipe = RecipeController.getInstance().getRecipeList(rset.getInt("id"));

				if (loadCommon)
				{
					if (rset.getInt(2) == 1)
					{
						if (rset.getInt(3) == _classIndex)
							registerDwarvenRecipeList(recipe, false);
					}
					else
						registerCommonRecipeList(recipe, false);
				}
				else
					registerDwarvenRecipeList(recipe, false);
			}

			rset.close();
			statement.close();
		}
		catch (Exception e)
		{
			if (_log.isLoggable(Level.SEVERE))
				_log.warning("Could not restore recipe book data:" + e);
		}
		finally {
			try { con.close(); } catch (Exception e) {}
		}
	}

	/**
	 * Update L2PcInstance stats in the characters table of the database.<BR><BR>
	 */
	public synchronized void store(boolean storeActiveEffects)
	{
		//update client coords, if these look like true
        // if (isInsideRadius(getClientX(), getClientY(), 1000, true))
        //    setXYZ(getClientX(), getClientY(), getClientZ());

		storeCharBase();
		storeCharSub();
		storeEffect(storeActiveEffects);
		transformInsertInfo();
		if(Config.STORE_RECIPE_SHOPLIST)
			storeRecipeShopList();
	}
	
	public void store()
	{
		store(true);
	}

	private void storeCharBase()
	{
		Connection con = null;

		try
		{
			// Get the exp, level, and sp of base class to store in base table
			int currentClassIndex = getClassIndex();
			_classIndex = 0;
			long exp     = getStat().getExp();
			int level   = getStat().getLevel();
			int sp      = getStat().getSp();
			_classIndex = currentClassIndex;

			con = L2DatabaseFactory.getInstance().getConnection();
			// Update base class
			PreparedStatement statement = con.prepareStatement(UPDATE_CHARACTER);
			
			statement.setInt(1, level);
			statement.setInt(2, getMaxHp());
			statement.setDouble(3, getCurrentHp());
			statement.setInt(4, getMaxCp());
			statement.setDouble(5, getCurrentCp());
			statement.setInt(6, getMaxMp());
			statement.setDouble(7, getCurrentMp());
			statement.setInt(8, getAppearance().getFace());
			statement.setInt(9, getAppearance().getHairStyle());
			statement.setInt(10, getAppearance().getHairColor());
			statement.setInt(11, getAppearance().getSex()? 1 : 0);
			statement.setInt(12, getHeading());
			statement.setInt(13, _observerMode ? _obsX : getX());
			statement.setInt(14, _observerMode ? _obsY : getY());
			statement.setInt(15, _observerMode ? _obsZ : getZ());
			statement.setLong(16, exp);
			statement.setLong(17, getExpBeforeDeath());
			statement.setInt(18, sp);
			statement.setInt(19, getKarma());
			statement.setInt(20, getFame());
			statement.setInt(21, getPvpKills());
			statement.setInt(22, getPkKills());
			statement.setInt(23, getRecomHave());
			statement.setInt(24, getRecomLeft());
			statement.setInt(25, getClanId());
			statement.setInt(26, getRace().ordinal());
			statement.setInt(27, getClassId().getId());
			statement.setLong(28, getDeleteTimer());
			statement.setString(29, getTitle());
			statement.setInt(30, getAppearance().getTitleColor());
			statement.setInt(31, getAccessLevel().getLevel());
			statement.setInt(32, isOnline());
            statement.setInt(33, isIn7sDungeon() ? 1 : 0);
			statement.setInt(34, getClanPrivileges());
			statement.setInt(35, getWantsPeace());
			statement.setInt(36, getBaseClass());

			long totalOnlineTime = _onlineTime;

			if (_onlineBeginTime > 0)
				totalOnlineTime += (System.currentTimeMillis()-_onlineBeginTime)/1000;

            statement.setLong(37, totalOnlineTime);
            statement.setInt(38, getPunishLevel().value());
            statement.setLong(39, getPunishTimer());
            statement.setInt(40, getNewbie());
            statement.setInt(41, isNoble() ? 1 : 0);
            statement.setLong(42, getPowerGrade());
            statement.setInt(43, getPledgeType());
            statement.setLong(44,getLastRecomUpdate());
            statement.setInt(45,getLvlJoinedAcademy());
            statement.setLong(46,getApprentice());
            statement.setLong(47,getSponsor());
            statement.setInt(48, getAllianceWithVarkaKetra());
			statement.setLong(49, getClanJoinExpiryTime());
			statement.setLong(50, getClanCreateExpiryTime());
			statement.setString(51, getName());
			statement.setLong(52, getDeathPenaltyBuffLevel());
			statement.setInt(53, getBookMarkSlot());
			statement.setInt(54, getVitalityPoints());
            statement.setInt(55, getObjectId());

			statement.execute();
			statement.close();
		}
		catch (Exception e) { _log.warning("Could not store char base data: "+ e); }
		finally { try { con.close(); } catch (Exception e) {} }
	}

    private void storeCharSub()
    {
        Connection con = null;

        try
        {
            con = L2DatabaseFactory.getInstance().getConnection();
            PreparedStatement statement = con.prepareStatement(UPDATE_CHAR_SUBCLASS);
            
            if (getTotalSubClasses() > 0)
            {
            	for (SubClass subClass : getSubClasses().values())
            	{
                    statement.setLong(1, subClass.getExp());
                    statement.setInt(2, subClass.getSp());
                    statement.setInt(3, subClass.getLevel());
                    statement.setInt(4, subClass.getClassId());
                    statement.setInt(5, getObjectId());
                    statement.setInt(6, subClass.getClassIndex());

                    statement.execute();
                }
            	statement.close();
            }
        }
        catch (Exception e) {
        	_log.warning("Could not store sub class data for " + getName() + ": "+ e);
		}
        finally { try { con.close(); } catch (Exception e) {} }
    }
    
    private void storeEffect(boolean storeEffects)
	{
		if (!Config.STORE_SKILL_COOLTIME)
			return;
		
		Connection con = null;
		try
		{
			con = L2DatabaseFactory.getInstance().getConnection();
			
			
			// Delete all current stored effects for char to avoid dupe
			PreparedStatement statement = con.prepareStatement(DELETE_SKILL_SAVE);
			
			statement.setInt(1, getObjectId());
			statement.setInt(2, getClassIndex());
			statement.execute();
			statement.close();
			
			int buff_index = 0;
			
			final List<Integer> storedSkills = new FastList<Integer>();
			
			// Store all effect data along with calulated remaining
			// reuse delays for matching skills. 'restore_type'= 0.
			statement = con.prepareStatement(ADD_SKILL_SAVE);

			if (storeEffects)
			{
				for (L2Effect effect : getAllEffects())
				{
					if (effect == null)
						continue;
					
					switch (effect.getEffectType())
					{
						case HEAL_OVER_TIME:
						case COMBAT_POINT_HEAL_OVER_TIME:
						// TODO: Fix me.
						case HIDE:
							continue;
					}
					
					L2Skill skill = effect.getSkill();
					int skillId = skill.getId();
					
					if (storedSkills.contains(skillId))
						continue;
					
					storedSkills.add(skillId);
					
					if (effect != null && !effect.isHerbEffect() && effect.getInUse()
					        && !skill.isToggle())
					{
						
						statement.setInt(1, getObjectId());
						statement.setInt(2, skillId);
						statement.setInt(3, skill.getLevel());
						statement.setInt(4, effect.getCount());
						statement.setInt(5, effect.getTime());
						
						if (_reuseTimeStamps.containsKey(skillId))
						{
							TimeStamp t = _reuseTimeStamps.get(skillId);
							statement.setLong(6, t.hasNotPassed() ? t.getReuse() : 0);
							statement.setDouble(7, t.hasNotPassed() ? t.getStamp() : 0);
						}
						else
						{
							statement.setLong(6, 0);
							statement.setDouble(7, 0);
						}
						
						statement.setInt(8, 0);
						statement.setInt(9, getClassIndex());
						statement.setInt(10, ++buff_index);
						statement.execute();
					}
				}
			}
			
			// Store the reuse delays of remaining skills which
			// lost effect but still under reuse delay. 'restore_type' 1.
			for (TimeStamp t : _reuseTimeStamps.values())
			{
				if (t.hasNotPassed())
				{
					int skillId = t.getSkill();
					if (storedSkills.contains(skillId))
						continue;
					storedSkills.add(skillId);

					statement.setInt(1, getObjectId());
					statement.setInt(2, skillId);
					statement.setInt(3, -1);
					statement.setInt(4, -1);
					statement.setInt(5, -1);
					statement.setLong(6, t.getReuse());
					statement.setDouble(7, t.getStamp());
					statement.setInt(8, 1);
					statement.setInt(9, getClassIndex());
					statement.setInt(10, ++buff_index);
					statement.execute();
					
				}
			}
			statement.close();
		}
		catch (Exception e)
		{
			_log.log(Level.WARNING, "Could not store char effect data: ", e);
		}
		finally
		{
			try
			{
				con.close();
			}
			catch (Exception e)
			{
			}
		}
	}

	/**
	 * Return True if the L2PcInstance is on line.<BR>
	 * <BR>
	 */
	public int isOnline()
	{
		return (_isOnline ? 1 : 0);
	}

    public boolean isIn7sDungeon()
    {
        return _isIn7sDungeon;
    }

	/**
	 * Add a skill to the L2PcInstance _skills and its Func objects to the calculator set of the L2PcInstance and save update in the character_skills table of the database.<BR><BR>
	 *
	 * <B><U> Concept</U> :</B><BR><BR>
	 * All skills own by a L2PcInstance are identified in <B>_skills</B><BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Replace oldSkill by newSkill or Add the newSkill </li>
	 * <li>If an old skill has been replaced, remove all its Func objects of L2Character calculator set</li>
	 * <li>Add Func objects of newSkill to the calculator set of the L2Character </li><BR><BR>
	 *
	 * @param newSkill The L2Skill to add to the L2Character
	 *
	 * @return The L2Skill replaced or null if just added a new L2Skill
	 *
	 */
	public L2Skill addSkill(L2Skill newSkill, boolean store)
	{
		// Add a skill to the L2PcInstance _skills and its Func objects to the calculator set of the L2PcInstance
		L2Skill oldSkill = super.addSkill(newSkill);

		// Add or update a L2PcInstance skill in the character_skills table of the database
		if (store) storeSkill(newSkill, oldSkill, -1);

		return oldSkill;
	}
	
	public L2Skill removeSkill(L2Skill skill, boolean store)
	{
		if (store)
			return removeSkill(skill);
		else
			return super.removeSkill(skill, true);
	}
	
	public L2Skill removeSkill(L2Skill skill, boolean store, boolean cancelEffect)
	{
		if (store)
			return removeSkill(skill);
		else
			return super.removeSkill(skill, cancelEffect);
	}

	/**
	 * Remove a skill from the L2Character and its Func objects from calculator set of the L2Character and save update in the character_skills table of the database.<BR><BR>
	 *
	 * <B><U> Concept</U> :</B><BR><BR>
	 * All skills own by a L2Character are identified in <B>_skills</B><BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Remove the skill from the L2Character _skills </li>
	 * <li>Remove all its Func objects from the L2Character calculator set</li><BR><BR>
	 *
	 * <B><U> Overridden in </U> :</B><BR><BR>
	 * <li> L2PcInstance : Save update in the character_skills table of the database</li><BR><BR>
	 *
	 * @param skill The L2Skill to remove from the L2Character
	 *
	 * @return The L2Skill removed
	 *
	 */
	@Override
	public L2Skill removeSkill(L2Skill skill)
	{
		// Remove a skill from the L2Character and its Func objects from calculator set of the L2Character
		L2Skill oldSkill = super.removeSkill(skill);

		Connection con = null;

		try
		{
			// Remove or update a L2PcInstance skill from the character_skills table of the database
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement(DELETE_SKILL_FROM_CHAR);

			if (oldSkill != null)
			{
				statement.setInt(1, oldSkill.getId());
				statement.setInt(2, getObjectId());
				statement.setInt(3, getClassIndex());
				statement.execute();
			}
			statement.close();
		}
		catch (Exception e)
		{
			_log.warning("Error could not delete skill: " + e);
		}
		finally
		{
			try { con.close(); } catch (Exception e) {}
		}

		if (this.transformId() > 0 || this.isCursedWeaponEquipped())
			return oldSkill;

		    L2ShortCut[] allShortCuts = getAllShortCuts();

		    for (L2ShortCut sc : allShortCuts)
		    {
			    if (sc != null && skill != null && sc.getId() == skill.getId() && sc.getType() == L2ShortCut.TYPE_SKILL)
			        deleteShortCut(sc.getSlot(), sc.getPage());
		    }

		return oldSkill;
	}

	/**
	 * Add or update a L2PcInstance skill in the character_skills table of the database.
	 * <BR><BR>
	 * If newClassIndex > -1, the skill will be stored with that class index, not the current one.
	 */
	private void storeSkill(L2Skill newSkill, L2Skill oldSkill, int newClassIndex)
	{
		int classIndex = _classIndex;

		if (newClassIndex > -1)
			classIndex = newClassIndex;

		Connection con = null;

		try
		{
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement;

			if (oldSkill != null && newSkill != null)
			{
				statement = con.prepareStatement(UPDATE_CHARACTER_SKILL_LEVEL);
				statement.setInt(1, newSkill.getLevel());
				statement.setInt(2, oldSkill.getId());
				statement.setInt(3, getObjectId());
				statement.setInt(4, classIndex);
				statement.execute();
				statement.close();
			}
			else if (newSkill != null)
			{
				statement = con.prepareStatement(ADD_NEW_SKILL);
				statement.setInt(1, getObjectId());
				statement.setInt(2, newSkill.getId());
				statement.setInt(3, newSkill.getLevel());
				statement.setInt(4, classIndex);
				statement.execute();
				statement.close();
			}
			else
			{
				_log.warning("could not store new skill. its NULL");
			}
		}
		catch (Exception e)
		{
			_log.warning("Error could not store char skills: " + e);
		}
		finally
		{
			try { con.close(); } catch (Exception e) {}
		}
	}

	/**
	 * Retrieve from the database all skills of this L2PcInstance and add them to _skills.<BR><BR>
	 */
	private void restoreSkills()
	{
		Connection con = null;

		try
		{
			// Retrieve all skills of this L2PcInstance from the database
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement(RESTORE_SKILLS_FOR_CHAR);
			
			statement.setInt(1, getObjectId());
			statement.setInt(2, getClassIndex());
			ResultSet rset = statement.executeQuery();

			// Go though the recordset of this SQL query
			while (rset.next())
			{
				int id = rset.getInt("skill_id");
				int level = rset.getInt("skill_level");

				if (id > 9000 && id < 9007)
					continue; // fake skills for base stats

				// Create a L2Skill object for each record
				L2Skill skill = SkillTable.getInstance().getInfo(id, level);

				// Add the L2Skill object to the L2Character _skills and its Func objects to the calculator set of the L2Character
				super.addSkill(skill);
			}

			rset.close();
			statement.close();
		}
		catch (Exception e)
		{
			_log.warning("Could not restore character "+this+ " skills: " + e);
		}
		finally
		{
			try { con.close(); } catch (Exception e) {}
		}
	}

    /**
     * Retrieve from the database all skill effects of this L2PcInstance and add them to the player.<BR><BR>
     */
	public void restoreEffects()
	{
		Connection con = null;
		
		try
		{
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement;
			ResultSet rset;

			/**
			*  Restore Type 0
			*  These skill were still in effect on the character
			*  upon logout. Some of which were self casted and
			*  might still have had a long reuse delay which also
			*  is restored.
			*/
			statement = con.prepareStatement(RESTORE_SKILL_SAVE);
			statement.setInt(1, getObjectId());
			statement.setInt(2, getClassIndex());
			statement.setInt(3, 0);
			rset = statement.executeQuery();

			while (rset.next())
			{
				int skillId = rset.getInt("skill_id");
				int skillLvl = rset.getInt("skill_level");
				int effectCount = rset.getInt("effect_count");
				int effectCurTime = rset.getInt("effect_cur_time");
				double reuseDelay = rset.getInt("reuse_delay");
				double systime = rset.getDouble("systime");

				double remainingTime = systime - System.currentTimeMillis();

				// Just incase the admin minipulated this table incorrectly :x
				if(skillId == -1 || effectCount == -1 || effectCurTime == -1 || reuseDelay < 0)
					continue;

				L2Skill skill = SkillTable.getInstance().getInfo(skillId, skillLvl);
				L2Effect[] effects = skill.getEffects(this, this);

				if (remainingTime > 10)
				{
					disableSkill(skillId, (long)remainingTime);
					addTimeStamp(new TimeStamp(skillId, (long)reuseDelay, (long)systime));
				}

				for (L2Effect effect : effects)
                {
					effect.setCount(effectCount);
					effect.setFirstTime(effectCurTime);
                }
			}
			rset.close();
			statement.close();

			/**
			 * Restore Type 1
			 * The remaning skills lost effect upon logout but
			 * were still under a high reuse delay.
			 */
			statement = con.prepareStatement(RESTORE_SKILL_SAVE);
			statement.setInt(1, getObjectId());
			statement.setInt(2, getClassIndex());
			statement.setInt(3, 1);
			rset = statement.executeQuery();

			while (rset.next())
			{
				int skillId = rset.getInt("skill_id");
				double reuseDelay = rset.getDouble("reuse_delay");
				double systime = rset.getDouble("systime");

				double remainingTime = systime - System.currentTimeMillis();

				if (remainingTime < 10)
					continue;

				disableSkill(skillId, (long)remainingTime);
				addTimeStamp(new TimeStamp(skillId, (long)reuseDelay, (long)systime));
			}
			rset.close();
			statement.close();

			statement = con.prepareStatement(DELETE_SKILL_SAVE);
			statement.setInt(1, getObjectId());
			statement.setInt(2, getClassIndex());
			statement.executeUpdate();
			statement.close();
		}
		catch (Exception e) {
			_log.warning("Could not restore "+this+" active effect data: " + e);
			e.printStackTrace();
		}
		finally {
			try {con.close();} catch (Exception e) {}
		}
	}

	/**
	 * Retrieve from the database all Henna of this L2PcInstance, add them to _henna and calculate stats of the L2PcInstance.<BR><BR>
	 */
	private void restoreHenna()
	{
		Connection con = null;

		try
		{
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement(RESTORE_CHAR_HENNAS);
			statement.setInt(1, getObjectId());
			statement.setInt(2, getClassIndex());
			ResultSet rset = statement.executeQuery();

			for (int i=0;i<3;i++)
				_henna[i]=null;

			while (rset.next())
			{
				int slot = rset.getInt("slot");

				if (slot<1 || slot>3)
                    continue;

				int symbol_id = rset.getInt("symbol_id");

				L2HennaInstance sym = null;

				if (symbol_id != 0)
				{
					L2Henna tpl = HennaTable.getInstance().getTemplate(symbol_id);

					if (tpl != null)
					{
						sym = new L2HennaInstance(tpl);
						_henna[slot-1] = sym;
					}
				}
			}

			rset.close();
			statement.close();
		}
		catch (Exception e)
		{
		    _log.log(Level.SEVERE, "Failed restoing character "+this+" hennas.", e);
		}
		finally
		{
			try { con.close(); } catch (Exception e) {}
		}

		// Calculate Henna modifiers of this L2PcInstance
		recalcHennaStats();
	}

	/**
	 * Retrieve from the database all Recommendation data of this L2PcInstance, add to _recomChars and calculate stats of the L2PcInstance.<BR><BR>
	 */
	private void restoreRecom()
	{
		Connection con = null;

		try
		{
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement(RESTORE_CHAR_RECOMS);
			statement.setInt(1, getObjectId());
			ResultSet rset = statement.executeQuery();
			while (rset.next())
			{
				_recomChars.add(rset.getInt("target_id"));
			}

			rset.close();
			statement.close();
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "Failed restoring character "+this+" recommendations.", e);
		}
		finally
		{
			try { con.close(); } catch (Exception e) {}
		}
	}

	/**
	 * Return the number of Henna empty slot of the L2PcInstance.<BR><BR>
	 */
	public int getHennaEmptySlots()
	{
		int totalSlots = 0;
		if (getClassId().level() == 1)
			totalSlots = 2;
		else
			totalSlots = 3;

		for (int i = 0; i < 3; i++)
		{
			if (_henna[i] != null)
				totalSlots--;
		}

		if (totalSlots <= 0)
			return 0;

		return totalSlots;
	}

	/**
	 * Remove a Henna of the L2PcInstance, save update in the character_hennas table of the database and send Server->Client HennaInfo/UserInfo packet to this L2PcInstance.<BR><BR>
	 */
	public boolean removeHenna(int slot)
	{
		if (slot < 1 || slot > 3)
			return false;

		slot--;

		if (_henna[slot] == null)
			return false;

		L2HennaInstance henna = _henna[slot];
		_henna[slot] = null;

		Connection con = null;

		try
		{
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement(DELETE_CHAR_HENNA);

			statement.setInt(1, getObjectId());
			statement.setInt(2, slot+1);
			statement.setInt(3, getClassIndex());

			statement.execute();
			statement.close();
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "Failed remocing character henna.", e);
		}
		finally
		{
			try { con.close(); } catch (Exception e) {}
		}

		// Calculate Henna modifiers of this L2PcInstance
		recalcHennaStats();

		// Send Server->Client HennaInfo packet to this L2PcInstance
		sendPacket(new HennaInfo(this));

		// Send Server->Client UserInfo packet to this L2PcInstance
		sendPacket(new UserInfo(this));
		sendPacket(new ExBrExtraUserInfo(this));
		// Add the recovered dyes to the player's inventory and notify them.
		getInventory().addItem("Henna", henna.getItemIdDye(), henna.getAmountDyeRequire() / 2, this, null);

		reduceAdena("Henna", henna.getPrice() / 5, this, false);

		SystemMessage sm = new SystemMessage(SystemMessageId.EARNED_S2_S1_S);
        sm.addItemName(henna.getItemIdDye());
        sm.addItemNumber(henna.getAmountDyeRequire() / 2);
		sendPacket(sm);

		sendPacket(new SystemMessage(SystemMessageId.SYMBOL_DELETED));

		return true;
	}

	/**
	 * Add a Henna to the L2PcInstance, save update in the character_hennas table of the database and send Server->Client HennaInfo/UserInfo packet to this L2PcInstance.<BR><BR>
	 */
	public boolean addHenna(L2HennaInstance henna)
	{
		for (int i = 0; i < 3; i++)
		{
			if (_henna[i] == null)
			{
				_henna[i] = henna;

				// Calculate Henna modifiers of this L2PcInstance
				recalcHennaStats();

				Connection con = null;

				try
				{
					con = L2DatabaseFactory.getInstance().getConnection();
					PreparedStatement statement = con.prepareStatement(ADD_CHAR_HENNA);
					
					statement.setInt(1, getObjectId());
					statement.setInt(2, henna.getSymbolId());
					statement.setInt(3, i+1);
					statement.setInt(4, getClassIndex());
					
					statement.execute();
					statement.close();
				}
				catch (Exception e)
				{
					_log.log(Level.SEVERE, "Failed saving character henna.", e);
				}
				finally
				{
					try { con.close(); } catch (Exception e) {}
				}

				// Send Server->Client HennaInfo packet to this L2PcInstance
				sendPacket(new HennaInfo(this));

				// Send Server->Client UserInfo packet to this L2PcInstance
				sendPacket(new UserInfo(this));
				sendPacket(new ExBrExtraUserInfo(this));

				return true;
			}
		}
		return false;
	}

	/**
	 * Calculate Henna modifiers of this L2PcInstance.<BR><BR>
	 */
	private void recalcHennaStats()
	{
		_hennaINT = 0;
		_hennaSTR = 0;
		_hennaCON = 0;
		_hennaMEN = 0;
		_hennaWIT = 0;
		_hennaDEX = 0;

		for (int i=0;i<3;i++)
		{
			if (_henna[i]==null)continue;
			_hennaINT += _henna[i].getStatINT();
			_hennaSTR += _henna[i].getStatSTR();
			_hennaMEN += _henna[i].getStatMEM();
			_hennaCON += _henna[i].getStatCON();
			_hennaWIT += _henna[i].getStatWIT();
			_hennaDEX += _henna[i].getStatDEX();
		}

		if (_hennaINT>5)_hennaINT=5;
		if (_hennaSTR>5)_hennaSTR=5;
		if (_hennaMEN>5)_hennaMEN=5;
		if (_hennaCON>5)_hennaCON=5;
		if (_hennaWIT>5)_hennaWIT=5;
		if (_hennaDEX>5)_hennaDEX=5;
	}

	/**
	 * Return the Henna of this L2PcInstance corresponding to the selected slot.<BR><BR>
	 */
	public L2HennaInstance getHenna(int slot)
	{
		if (slot < 1 || slot > 3)
            return null;

		return _henna[slot - 1];
	}

	/**
	 * Return the INT Henna modifier of this L2PcInstance.<BR><BR>
	 */
	public int getHennaStatINT()
	{
		return _hennaINT;
	}

	/**
	 * Return the STR Henna modifier of this L2PcInstance.<BR><BR>
	 */
	public int getHennaStatSTR()
	{
		return _hennaSTR;
	}

	/**
	 * Return the CON Henna modifier of this L2PcInstance.<BR><BR>
	 */
	public int getHennaStatCON()
	{
		return _hennaCON;
	}

	/**
	 * Return the MEN Henna modifier of this L2PcInstance.<BR><BR>
	 */
	public int getHennaStatMEN()
	{
		return _hennaMEN;
	}

	/**
	 * Return the WIT Henna modifier of this L2PcInstance.<BR><BR>
	 */
	public int getHennaStatWIT()
	{
		return _hennaWIT;
	}

	/**
	 * Return the DEX Henna modifier of this L2PcInstance.<BR><BR>
	 */
	public int getHennaStatDEX()
	{
		return _hennaDEX;
	}

	/**
	 * Return True if the L2PcInstance is autoAttackable.<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Check if the attacker isn't the L2PcInstance Pet </li>
	 * <li>Check if the attacker is L2MonsterInstance</li>
	 * <li>If the attacker is a L2PcInstance, check if it is not in the same party </li>
	 * <li>Check if the L2PcInstance has Karma </li>
	 * <li>If the attacker is a L2PcInstance, check if it is not in the same siege clan (Attacker, Defender) </li><BR><BR>
	 *
	 */
	@Override
	public boolean isAutoAttackable(L2Character attacker)
	{
		// Check if the attacker isn't the L2PcInstance Pet
		if (attacker == this || attacker == getPet())
			return false;

		// TODO: check for friendly mobs
		// Check if the attacker is a L2MonsterInstance
		if (attacker instanceof L2MonsterInstance)
			return true;

		// Check if the attacker is not in the same party
		if (getParty() != null && getParty().getPartyMembers().contains(attacker))
			return false;

		// Check if the attacker is in olympia and olympia start
		if (attacker instanceof L2PcInstance && ((L2PcInstance)attacker).isInOlympiadMode() ){
			if (isInOlympiadMode() && isOlympiadStart() && ((L2PcInstance)attacker).getOlympiadGameId()==getOlympiadGameId())
				return true;
			else
				return false;
		}

		// Check if the attacker is in TvT and TvT is started
		if (TvTEvent.isStarted() && TvTEvent.isPlayerParticipant(getObjectId()))
			return true;

		// Check if the attacker is not in the same clan
		if (getClan() != null && attacker != null && getClan().isMember(attacker.getObjectId()))
			return false;

        if(attacker instanceof L2Playable && isInsideZone(ZONE_PEACE))
            return false;

		// Check if the L2PcInstance has Karma
		if (getKarma() > 0 || getPvpFlag() > 0)
			return true;

		// Check if the attacker is a L2Playable
		if (attacker instanceof L2Playable)
		{
			// Get L2PcInstance
			L2PcInstance cha = attacker.getActingPlayer();
			
			// is AutoAttackable if both players are in the same duel and the duel is still going on
			if ( getDuelState() == Duel.DUELSTATE_DUELLING
					&& getDuelId() == cha.getDuelId())
				return true;
			// Check if the L2PcInstance is in an arena or a siege area
			if (isInsideZone(ZONE_PVP) && cha.isInsideZone(ZONE_PVP))
				return true;

			if (getClan() != null)
			{
				Siege siege = SiegeManager.getInstance().getSiege(getX(), getY(), getZ());
				if (siege != null)
				{
					// Check if a siege is in progress and if attacker and the L2PcInstance aren't in the Defender clan
					if (siege.checkIsDefender(cha.getClan()) &&
							siege.checkIsDefender(getClan()))
						return false;

					// Check if a siege is in progress and if attacker and the L2PcInstance aren't in the Attacker clan
					if (siege.checkIsAttacker(cha.getClan()) &&
							siege.checkIsAttacker(getClan()))
						return false;
				}

				// Check if clan is at war
				if (getClan() != null && cha.getClan() != null
				                           && getClan().isAtWarWith(cha.getClanId())
				                           && cha.getClan().isAtWarWith(getClanId())
				                           && getWantsPeace() == 0
				                           && cha.getWantsPeace() == 0
				                           && !isAcademyMember())
				return true;
			}
		}
		else if (attacker instanceof L2DefenderInstance)
		{
			if (getClan() != null)
			{
				Siege siege = SiegeManager.getInstance().getSiege(this);
				return (siege != null && siege.checkIsAttacker(getClan()));
			}
		}

		return false;
	}


	/**
	 * Check if the active L2Skill can be casted.<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Check if the skill isn't toggle and is offensive </li>
	 * <li>Check if the target is in the skill cast range </li>
	 * <li>Check if the skill is Spoil type and if the target isn't already spoiled </li>
	 * <li>Check if the caster owns enought consummed Item, enough HP and MP to cast the skill </li>
	 * <li>Check if the caster isn't sitting </li>
	 * <li>Check if all skills are enabled and this skill is enabled </li><BR><BR>
	 * <li>Check if the caster own the weapon needed </li><BR><BR>
	 * <li>Check if the skill is active </li><BR><BR>
	 * <li>Check if all casting conditions are completed</li><BR><BR>
	 * <li>Notify the AI with AI_INTENTION_CAST and target</li><BR><BR>
	 *
	 * @param skill The L2Skill to use
	 * @param forceUse used to force ATTACK on players
	 * @param dontMove used to prevent movement, if not in range
	 *
	 */
	public void useMagic(L2Skill skill, boolean forceUse, boolean dontMove)
	{
		// Check if the skill is active
        if (skill.isPassive())
        {
            // just ignore the passive skill request. why does the client send it anyway ??
            // Send a Server->Client packet ActionFailed to the L2PcInstance
            sendPacket(ActionFailed.STATIC_PACKET);
            return;
        }
		
		//************************************* Check Casting in Progress *******************************************

		// If a skill is currently being used, queue this one if this is not the same
        if (isCastingNow())
        {
        	SkillDat currentSkill = getCurrentSkill();
        	// Check if new skill different from current skill in progress
        	if (currentSkill != null && skill.getId() == currentSkill.getSkillId())
            {
            	sendPacket(ActionFailed.STATIC_PACKET);
            	return;
            }

            if (Config.DEBUG && getQueuedSkill() != null)
                _log.info(getQueuedSkill().getSkill().getName() + " is already queued for " + getName() + ".");

            // Create a new SkillDat object and queue it in the player _queuedSkill
            setQueuedSkill(skill, forceUse, dontMove);
            sendPacket(ActionFailed.STATIC_PACKET);
            return;
        }
        setIsCastingNow(true);
        // Create a new SkillDat object and set the player _currentSkill
        // This is used mainly to save & queue the button presses, since L2Character has
        // _lastSkillCast which could otherwise replace it
        setCurrentSkill(skill, forceUse, dontMove);

        if (getQueuedSkill() != null) // wiping out previous values, after casting has been aborted
        	setQueuedSkill(null, false, false);
        
        if (!checkUseMagicConditions(skill, forceUse, dontMove))
        {
        	setIsCastingNow(false);
        	return;
        }
        
		// Check if the target is correct and Notify the AI with AI_INTENTION_CAST and target
		L2Object target = null;

		switch (skill.getTargetType())
		{
			case TARGET_AURA:    // AURA, SELF should be cast even if no target has been found
			case TARGET_FRONT_AURA:
			case TARGET_BEHIND_AURA:
			case TARGET_GROUND:
			case TARGET_SELF:
				target = this;
				break;
			default:

                // Get the first target of the list
			    target = skill.getFirstOfTargetList(this);
			    break;
		}

		// Notify the AI with AI_INTENTION_CAST and target
		getAI().setIntention(CtrlIntention.AI_INTENTION_CAST, skill, target);
    }
	
	private boolean checkUseMagicConditions(L2Skill skill, boolean forceUse, boolean dontMove)
	{
		L2SkillType sklType = skill.getSkillType();
	    
        //************************************* Check Player State *******************************************

        // Abnormal effects(ex : Stun, Sleep...) are checked in L2Character useMagic()

      	if (isOutOfControl())
		{
			sendPacket(ActionFailed.STATIC_PACKET);
			return false;
		}

    	// Check if the player is dead
        if (isDead())
        {
        	abortCast();
        	// Send a Server->Client packet ActionFailed to the L2PcInstance
            sendPacket(ActionFailed.STATIC_PACKET);
            return false;
        }
        
        if (isFishing() && (sklType != L2SkillType.PUMPING &&
        		sklType != L2SkillType.REELING && sklType != L2SkillType.FISHING))
        {
            //Only fishing skills are available
            sendPacket(new SystemMessage(SystemMessageId.ONLY_FISHING_SKILLS_NOW));
            return false;
        }
        
        if (inObserverMode())
        {
        	sendPacket(new SystemMessage(SystemMessageId.OBSERVERS_CANNOT_PARTICIPATE));
            abortCast();
            sendPacket(ActionFailed.STATIC_PACKET);
            return false;
        }
        
        // Check if the caster is sitting
        if (isSitting())
        {
            // Send a System Message to the caster
            sendPacket(new SystemMessage(SystemMessageId.CANT_MOVE_SITTING));

            // Send a Server->Client packet ActionFailed to the L2PcInstance
            sendPacket(ActionFailed.STATIC_PACKET);
            return false;
        }

		// Check if the skill type is TOGGLE
		if (skill.isToggle())
		{
			// Get effects of the skill
			L2Effect effect = getFirstEffect(skill.getId());

			if (effect != null)
			{
				effect.exit();

				// Send a Server->Client packet ActionFailed to the L2PcInstance
				sendPacket(ActionFailed.STATIC_PACKET);
				return false;
			}
		}
		
    	// Check if the player uses "Fake Death" skill 
		// Note: do not check this before TOGGLE reset
        if (isFakeDeath())
        {
        	// Send a Server->Client packet ActionFailed to the L2PcInstance
            sendPacket(ActionFailed.STATIC_PACKET);
            return false;
        }

	    //************************************* Check Target *******************************************
        // Create and set a L2Object containing the target of the skill
        L2Object target = null;
        SkillTargetType sklTargetType = skill.getTargetType();
        Point3D worldPosition = getCurrentSkillWorldPosition();
        
        if (sklTargetType == SkillTargetType.TARGET_GROUND && worldPosition == null)
        {
        	_log.info("WorldPosition is null for skill: "+skill.getName() + ", player: " + getName() + ".");
        	sendPacket(ActionFailed.STATIC_PACKET);
        	return false;
        }
        
        switch (sklTargetType)
        {
        	// Target the player if skill type is AURA, PARTY, CLAN or SELF
        	case TARGET_AURA:
        	case TARGET_FRONT_AURA:
        	case TARGET_BEHIND_AURA:
        	case TARGET_PARTY:
        	case TARGET_ALLY:
        	case TARGET_CLAN:
        	case TARGET_PARTY_CLAN:
        	case TARGET_GROUND:
        	case TARGET_SELF:
        		target = this;
        		break;
        	case TARGET_PET:
        	case TARGET_SUMMON:
        		target = getPet();
        		break;
        	default:
        		target = getTarget();
        	break;
        }

        // Check the validity of the target
        if (target == null)
        {
            sendPacket(ActionFailed.STATIC_PACKET);
            return false;
        }

        // skills can be used on Walls and Doors only during siege
        if(target instanceof L2DoorInstance )
        {
        	boolean isCastle = (((L2DoorInstance) target).getCastle() != null
                    && ((L2DoorInstance) target).getCastle().getCastleId() > 0
                    && ((L2DoorInstance) target).getCastle().getSiege().getIsInProgress());
        	boolean isFort = (((L2DoorInstance) target).getFort() != null
                    && ((L2DoorInstance) target).getFort().getFortId() > 0
                    && ((L2DoorInstance) target).getFort().getSiege().getIsInProgress()
                    && !((L2DoorInstance) target).getIsCommanderDoor());
        	if ((!isCastle && !isFort)&&(((L2DoorInstance) target).isUnlockable() && skill.getSkillType() != L2SkillType.UNLOCK))
        		return false;
        }

        // Are the target and the player in the same duel?
        if (isInDuel())
        {        	
        	// Get L2PcInstance
    		if (target instanceof L2Playable)
    		{
    			// Get L2PcInstance
    			L2PcInstance cha = target.getActingPlayer();
    			if (cha.getDuelId() != getDuelId())
    			{
            		sendMessage("You cannot do this while duelling.");
            		sendPacket(ActionFailed.STATIC_PACKET);
            		return false;    				
    			}
    		}
        }

        //************************************* Check skill availability *******************************************

  		// Check if it's ok to summon
        // siege golem (13), Wild Hog Cannon (299), Swoop Cannon (448)
        if ((skill.getId() == 13 || skill.getId() == 299 || skill.getId() == 448)
        		&& ((!SiegeManager.getInstance().checkIfOkToSummon(this, false) 
                && !FortSiegeManager.getInstance().checkIfOkToSummon(this, false))||(SevenSigns.getInstance().CheckSummonConditions(this))))
			return false;
        
        // Check if this skill is enabled (ex : reuse time)
        if (isSkillDisabled(skill.getId()))
        {
        	SystemMessage sm = null;
        	FastMap<Integer, TimeStamp> timeStamp = getReuseTimeStamp();
				
        	if (timeStamp != null && timeStamp.containsKey(skill.getId()))
        	{
        		int remainingTime = (int)(_reuseTimeStamps.get(skill.getId()).getRemaining()/1000);
        		int hours = remainingTime/3600;
        		int minutes = (remainingTime%3600)/60;
        		int seconds = (remainingTime%60);
        		if (hours > 0)
        		{
        			sm = new SystemMessage(SystemMessageId.S2_HOURS_S3_MINUTES_S4_SECONDS_REMAINING_FOR_REUSE_S1);
        			sm.addSkillName(skill);
        			sm.addNumber(hours);
        			sm.addNumber(minutes);
        		}
        		else if (minutes > 0)
        		{
        			sm = new SystemMessage(SystemMessageId.S2_MINUTES_S3_SECONDS_REMAINING_FOR_REUSE_S1);
        			sm.addSkillName(skill);
        			sm.addNumber(minutes);
        		}
        		else
        		{
        			sm = new SystemMessage(SystemMessageId.S2_SECONDS_REMAINING_FOR_REUSE_S1);
        			sm.addSkillName(skill);
        		}
					
        		sm.addNumber(seconds);
        	}
        	else
        	{
        		sm = new SystemMessage(SystemMessageId.S1_PREPARED_FOR_REUSE);
        		sm.addSkillName(skill);
        	}
				
        	sendPacket(sm);
        	return false;
        }

        //************************************* Check Consumables *******************************************

        // Check if spell consumes a Soul
        if (skill.getSoulConsumeCount() > 0)
        {
            if (getSouls() < skill.getSoulConsumeCount())
            {
                sendPacket(new SystemMessage(SystemMessageId.THERE_IS_NOT_ENOUGH_SOUL));
                sendPacket(ActionFailed.STATIC_PACKET);
                return false;
            }
        }
        //************************************* Check casting conditions *******************************************

        // Check if all casting conditions are completed
        if (!skill.checkCondition(this, target, false))
        {
        	// Send a Server->Client packet ActionFailed to the L2PcInstance
        	sendPacket(ActionFailed.STATIC_PACKET);
        	return false;
        }

        //************************************* Check Skill Type *******************************************

        // Check if this is offensive magic skill
        if (skill.isOffensive())
		{
			if ((isInsidePeaceZone(this, target)) && !getAccessLevel().allowPeaceAttack())
			{
				// If L2Character or target is in a peace zone, send a system message TARGET_IN_PEACEZONE a Server->Client packet ActionFailed
				sendPacket(new SystemMessage(SystemMessageId.TARGET_IN_PEACEZONE));
				sendPacket(ActionFailed.STATIC_PACKET);
				return false;
			}

			if (isInOlympiadMode() && !isOlympiadStart()){
				// if L2PcInstance is in Olympia and the match isn't already start, send a Server->Client packet ActionFailed
				sendPacket(ActionFailed.STATIC_PACKET);
				return false;
			}

            // Check if the target is attackable
            if (!target.isAttackable() && !getAccessLevel().allowPeaceAttack())
			{
				// If target is not attackable, send a Server->Client packet ActionFailed
				sendPacket(ActionFailed.STATIC_PACKET);
				return false;
			}

			// Check if a Forced ATTACK is in progress on non-attackable target
			if (!target.isAutoAttackable(this) && !forceUse)
			{
				switch (sklTargetType)
				{
					case TARGET_AURA:
					case TARGET_FRONT_AURA:
					case TARGET_BEHIND_AURA:
					case TARGET_CLAN:
					case TARGET_PARTY_CLAN:
					case TARGET_ALLY:
					case TARGET_PARTY:
					case TARGET_SELF:
					case TARGET_GROUND:
						break;
					default: // Send a Server->Client packet ActionFailed to the L2PcInstance
						sendPacket(ActionFailed.STATIC_PACKET);
						return false;
				}
			}

			// Check if the target is in the skill cast range
			if (dontMove)
			{
				// Calculate the distance between the L2PcInstance and the target
				if (sklTargetType == SkillTargetType.TARGET_GROUND)
				{
					if (!isInsideRadius(worldPosition.getX(), worldPosition.getY(), worldPosition.getZ(), skill.getCastRange()+getTemplate().collisionRadius, false, false))
					{
						// Send a System Message to the caster
						sendPacket(new SystemMessage(SystemMessageId.TARGET_TOO_FAR));

						// Send a Server->Client packet ActionFailed to the L2PcInstance
						sendPacket(ActionFailed.STATIC_PACKET);
						return false;
					}
				}
				else if (skill.getCastRange() > 0 && !isInsideRadius(target, skill.getCastRange()+getTemplate().collisionRadius, false, false))
				{
					// Send a System Message to the caster
					sendPacket(new SystemMessage(SystemMessageId.TARGET_TOO_FAR));

					// Send a Server->Client packet ActionFailed to the L2PcInstance
					sendPacket(ActionFailed.STATIC_PACKET);
					return false;
				}
			}
		}
        
        if(skill.getSkillType() == L2SkillType.INSTANT_JUMP)
        {
        	// You cannot jump while rooted right ;)
        	if(isMovementDisabled())
        	{
        		// Sends message that skill cannot be used...
        		SystemMessage sm = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
        		sm.addSkillName(skill.getId());
        		sendPacket(sm);
        		
        		// Send a Server->Client packet ActionFailed to the L2PcInstance
        		sendPacket(ActionFailed.STATIC_PACKET);
        		
				return false;
        	}
        	// And this skill cannot be used in peace zone, not even on NPCs!
        	if(this.isInsideZone(L2Character.ZONE_PEACE))
        	{
        		//Sends a sys msg to client
        		sendPacket(new SystemMessage(SystemMessageId.TARGET_IN_PEACEZONE));
        		
        		// Send a Server->Client packet ActionFailed to the L2PcInstance
				sendPacket(ActionFailed.STATIC_PACKET);
				
				return false;
        	}
        	
        }
		// Check if the skill is defensive
        if (!skill.isOffensive() && target instanceof L2MonsterInstance && !forceUse && !skill.isNeutral())
		{
			// check if the target is a monster and if force attack is set.. if not then we don't want to cast.
        	switch (sklTargetType)
			{
				case TARGET_PET:
				case TARGET_SUMMON:
				case TARGET_AURA:
				case TARGET_FRONT_AURA:
				case TARGET_BEHIND_AURA:
				case TARGET_CLAN:
				case TARGET_PARTY_CLAN:
				case TARGET_SELF:
				case TARGET_PARTY:
				case TARGET_ALLY:
				case TARGET_CORPSE_MOB:
				case TARGET_AREA_CORPSE_MOB:
				case TARGET_GROUND:
					break;
				default:
				{
					switch (sklType)
					{
						case BEAST_FEED:
						case DELUXE_KEY_UNLOCK:
						case UNLOCK:
							break;
						default:
							sendPacket(ActionFailed.STATIC_PACKET);
						return false;
					}
					break;
				}
			}
		}

		// Check if the skill is Spoil type and if the target isn't already spoiled
		if (sklType == L2SkillType.SPOIL)
		{
			if (!(target instanceof L2MonsterInstance))
			{
				// Send a System Message to the L2PcInstance
				sendPacket(new SystemMessage(SystemMessageId.TARGET_IS_INCORRECT));

				// Send a Server->Client packet ActionFailed to the L2PcInstance
				sendPacket(ActionFailed.STATIC_PACKET);
				return false;
			}
		}
		
		// Check if the skill is Sweep type and if conditions not apply
		if (sklType == L2SkillType.SWEEP && target instanceof L2Attackable)
		{
			int spoilerId = ((L2Attackable) target).getIsSpoiledBy();
			
			if (((L2Attackable) target).isDead())
			{
				if (!((L2Attackable) target).isSpoil())
				{
					// Send a System Message to the L2PcInstance
					sendPacket(new SystemMessage(SystemMessageId.SWEEPER_FAILED_TARGET_NOT_SPOILED));
					
					// Send a Server->Client packet ActionFailed to the L2PcInstance
					sendPacket(ActionFailed.STATIC_PACKET);
					return false;
				}
				
				if (getObjectId() != spoilerId && !isInLooterParty(spoilerId))
				{
					// Send a System Message to the L2PcInstance
					sendPacket(new SystemMessage(SystemMessageId.SWEEP_NOT_ALLOWED));
					
					// Send a Server->Client packet ActionFailed to the L2PcInstance
					sendPacket(ActionFailed.STATIC_PACKET);
					return false;
				}
			}
		}

		// Check if the skill is Drain Soul (Soul Crystals) and if the target is a MOB
		if (sklType == L2SkillType.DRAIN_SOUL)
		{
			if (!(target instanceof L2MonsterInstance))
			{
				// Send a System Message to the L2PcInstance
				sendPacket(new SystemMessage(SystemMessageId.TARGET_IS_INCORRECT));

				// Send a Server->Client packet ActionFailed to the L2PcInstance
				sendPacket(ActionFailed.STATIC_PACKET);
				return false;
			}
		}

		// Check if this is a Pvp skill and target isn't a non-flagged/non-karma player
		switch (sklTargetType)
		{
			case TARGET_PARTY:
			case TARGET_ALLY:   // For such skills, checkPvpSkill() is called from L2Skill.getTargetList()
			case TARGET_CLAN:   // For such skills, checkPvpSkill() is called from L2Skill.getTargetList()
			case TARGET_PARTY_CLAN:   // For such skills, checkPvpSkill() is called from L2Skill.getTargetList()
			case TARGET_AURA:
			case TARGET_FRONT_AURA:
			case TARGET_BEHIND_AURA:
			case TARGET_GROUND:
			case TARGET_SELF:
				break;
			default:
				if (!checkPvpSkill(target, skill) && !getAccessLevel().allowPeaceAttack())
				{
					// Send a System Message to the L2PcInstance
					sendPacket(new SystemMessage(SystemMessageId.TARGET_IS_INCORRECT));

					// Send a Server->Client packet ActionFailed to the L2PcInstance
					sendPacket(ActionFailed.STATIC_PACKET);
					return false;
				}
		}

		if ((sklTargetType == SkillTargetType.TARGET_HOLY && !checkIfOkToCastSealOfRule(CastleManager.getInstance().getCastle(this), false, skill))
				|| (sklTargetType == SkillTargetType.TARGET_FLAGPOLE && !checkIfOkToCastFlagDisplay(FortManager.getInstance().getFort(this), false, skill))
				|| (sklType == L2SkillType.SIEGEFLAG && !L2SkillSiegeFlag.checkIfOkToPlaceFlag(this, false))
				|| (sklType == L2SkillType.STRSIEGEASSAULT && !checkIfOkToUseStriderSiegeAssault())
				|| (sklType == L2SkillType.SUMMON_FRIEND && !(checkSummonerStatus(this) && checkSummonTargetStatus(target, this))))
		{
			sendPacket(ActionFailed.STATIC_PACKET);
			abortCast();
			return false;
		}

		// GeoData Los Check here
		if (skill.getCastRange() > 0)
		{
			if (sklTargetType == SkillTargetType.TARGET_GROUND)
			{
				if (!GeoData.getInstance().canSeeTarget(this, worldPosition))
				{
					sendPacket(new SystemMessage(SystemMessageId.CANT_SEE_TARGET));
					sendPacket(ActionFailed.STATIC_PACKET);
					return false;
				}
			}
			else if (!GeoData.getInstance().canSeeTarget(this, target))
			{
				sendPacket(new SystemMessage(SystemMessageId.CANT_SEE_TARGET));
				sendPacket(ActionFailed.STATIC_PACKET);
				return false;
			}
		}
		// finally, after passing all conditions
		return true;
	}
	
	public boolean checkIfOkToUseStriderSiegeAssault()
	{
		Castle castle = CastleManager.getInstance().getCastle(this);
		Fort fort = FortManager.getInstance().getFort(this);
		
		if ((castle == null) && (fort == null))
			return false;
		
		if (castle != null)
			return checkIfOkToUseStriderSiegeAssault(castle);
		else
			return checkIfOkToUseStriderSiegeAssault(fort);
		
	}
	
	public boolean checkIfOkToUseStriderSiegeAssault(Castle castle)
	{
		String text = "";
		
		if (castle == null || castle.getCastleId() <= 0)
			text = "You must be on castle ground to use strider siege assault";
		else if (!castle.getSiege().getIsInProgress())
			text = "You can only use strider siege assault during a siege.";
		else if (!(getTarget() instanceof L2DoorInstance))
			text = "You can only use strider siege assault on doors and walls.";
		else if (!isRidingStrider())
			text = "You can only use strider siege assault when on strider.";
		else
			return true;
		
		sendMessage(text);
		
		return false;
	}
	
	public boolean checkIfOkToUseStriderSiegeAssault(Fort fort)
	{
		String text = "";
		
		if (fort == null || fort.getFortId() <= 0)
			text = "You must be on fort ground to use strider siege assault";
		else if (!fort.getSiege().getIsInProgress())
			text = "You can only use strider siege assault during a siege.";
		else if (!(getTarget() instanceof L2DoorInstance))
			text = "You can only use strider siege assault on doors and walls.";
		else if (!isRidingStrider())
			text = "You can only use strider siege assault when on strider.";
		else
			return true;
		
		sendMessage(text);
		
		return false;
	}
	
	public boolean checkIfOkToCastSealOfRule(Castle castle, boolean isCheckOnly, L2Skill skill)
	{
		SystemMessage sm;
	
		if (castle == null || castle.getCastleId() <= 0)
		{
			sm = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
			sm.addSkillName(skill);
		}
		else if (!castle.getArtefacts().contains(getTarget()))
		{
			sm = new SystemMessage(SystemMessageId.INCORRECT_TARGET);
		}
		else if (!castle.getSiege().getIsInProgress())
		{
			sm = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
			sm.addSkillName(skill);
		}
		else if (!Util.checkIfInRange(200, this, getTarget(), true))
		{
			sm = new SystemMessage(SystemMessageId.DIST_TOO_FAR_CASTING_STOPPED);
		}
		else if (castle.getSiege().getAttackerClan(getClan()) == null)
		{
			sm = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
			sm.addSkillName(skill);
		}
		else
		{
			if (!isCheckOnly)
			{
				sm = new SystemMessage(SystemMessageId.OPPONENT_STARTED_ENGRAVING);
				castle.getSiege().announceToPlayer(sm, false);
			}
			return true;
		}
		
		sendPacket(sm);
		return false;
	}
	
	public boolean checkIfOkToCastFlagDisplay(Fort fort, boolean isCheckOnly,L2Skill skill)
	{
		SystemMessage sm;
	
		if (fort == null || fort.getFortId() <= 0)
		{
			sm = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
			sm.addSkillName(skill);
		}
		else if (fort.getFlagPole() != getTarget())
		{
			sm = new SystemMessage(SystemMessageId.INCORRECT_TARGET);
			sm.addSkillName(skill);
		}
		else if (!fort.getSiege().getIsInProgress())
		{
			sm = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
			sm.addSkillName(skill);
		}
		else if (!Util.checkIfInRange(200, this, getTarget(), true))
		{
			sm = new SystemMessage(SystemMessageId.DIST_TOO_FAR_CASTING_STOPPED);
		}
		else if (fort.getSiege().getAttackerClan(getClan()) == null)
		{
			sm = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
			sm.addSkillName(skill);
		}
		else
		{
			if (!isCheckOnly)
				fort.getSiege().announceToPlayer(new SystemMessage(SystemMessageId.S1_TRYING_RAISE_FLAG),getClan().getName());
			return true;
		}
		
		sendPacket(sm);
		return false;
	}

    public boolean isInLooterParty(int LooterId)
    {
    	L2PcInstance looter = (L2PcInstance)L2World.getInstance().findObject(LooterId);

    	// if L2PcInstance is in a CommandChannel
    	if (isInParty() && getParty().isInCommandChannel() && looter != null)
    		return getParty().getCommandChannel().getMembers().contains(looter);

    	if (isInParty() && looter != null)
            return getParty().getPartyMembers().contains(looter);

		return false;
    }

	/**
	 * Check if the requested casting is a Pc->Pc skill cast and if it's a valid pvp condition
	 * @param target L2Object instance containing the target
	 * @param skill L2Skill instance with the skill being casted
	 * @return False if the skill is a pvpSkill and target is not a valid pvp target
	 */
	public boolean checkPvpSkill(L2Object target, L2Skill skill)
	{
		return checkPvpSkill(target, skill, false);
	}
	
	/**
	 * Check if the requested casting is a Pc->Pc skill cast and if it's a valid pvp condition
	 * @param target L2Object instance containing the target
	 * @param skill L2Skill instance with the skill being casted
	 * @param srcIsSummon is L2Summon - caster?
	 * @return False if the skill is a pvpSkill and target is not a valid pvp target
	 */
	public boolean checkPvpSkill(L2Object target, L2Skill skill, boolean srcIsSummon)
	{
		// check for PC->PC Pvp status
		if(target instanceof L2Summon)
			target = target.getActingPlayer();
		if (
				target != null &&                                           			// target not null and
				target != this &&                                           			// target is not self and
				target instanceof L2PcInstance &&                           			// target is L2PcInstance and
				!(isInDuel() && ((L2PcInstance)target).getDuelId() == getDuelId()) &&	// self is not in a duel and attacking opponent
				!isInsideZone(ZONE_PVP) &&        						// Pc is not in PvP zone
				!((L2PcInstance)target).isInsideZone(ZONE_PVP)         	// target is not in PvP zone
		)
		{
			if(skill.isPvpSkill()) // pvp skill
			{
				if(getClan() != null && ((L2PcInstance)target).getClan() != null)
				{
					if(getClan().isAtWarWith(((L2PcInstance)target).getClan().getClanId()) && ((L2PcInstance)target).getClan().isAtWarWith(getClan().getClanId()))
						return true; // in clan war player can attack whites even with sleep etc.
				}
				if (
						((L2PcInstance)target).getPvpFlag() == 0 &&             //   target's pvp flag is not set and
						((L2PcInstance)target).getKarma() == 0                  //   target has no karma
					)
					return false;
			}
			else if ((getCurrentSkill() != null && !getCurrentSkill().isCtrlPressed() && skill.isOffensive() && !srcIsSummon) 
					|| (getCurrentPetSkill() != null && !getCurrentPetSkill().isCtrlPressed() && skill.isOffensive() && srcIsSummon))
			{
				if(getClan() != null && ((L2PcInstance)target).getClan() != null)
				{
					if(getClan().isAtWarWith(((L2PcInstance)target).getClan().getClanId()) && ((L2PcInstance)target).getClan().isAtWarWith(getClan().getClanId()))
						return true; // in clan war player can attack whites even without ctrl
				}
				if (
						((L2PcInstance)target).getPvpFlag() == 0 &&             //   target's pvp flag is not set and
						((L2PcInstance)target).getKarma() == 0                  //   target has no karma
					)
					return false;
			}
		}

		return true;
	}

	/**
	 * Return True if the L2PcInstance is a Mage.<BR><BR>
	 */
	public boolean isMageClass()
	{
		return getClassId().isMage();
	}


	public boolean isMounted()
	{
		return _mountType > 0;
	}

	/**
	 * Set the type of Pet mounted (0 : none, 1 : Stridder, 2 : Wyvern) and send a Server->Client packet InventoryUpdate to the L2PcInstance.<BR><BR>
	 */
	public boolean checkLandingState()
	{
		// Check if char is in a no landing zone
		if (isInsideZone(ZONE_NOLANDING))
			return true;
		else
			// if this is a castle that is currently being sieged, and the rider is NOT a castle owner
			// he cannot land.
			// castle owner is the leader of the clan that owns the castle where the pc is
			if (isInsideZone(ZONE_SIEGE) && !(getClan()!= null &&
							CastleManager.getInstance().getCastle(this) == CastleManager.getInstance().getCastleByOwner(getClan()) &&
							this == getClan().getLeader().getPlayerInstance()))
				return true;

		return false;
	}

	// returns false if the change of mount type fails.
	public boolean setMount(int npcId, int npcLevel, int mountType)
	{
		switch(mountType)
		{
			case 0:
                setIsFlying(false);
                /* not used any more
				setIsRidingFenrirWolf(false);
				setIsRidingWFenrirWolf(false);
				setIsRidingGreatSnowWolf(false);*/
				setIsRidingStrider(false);
                break; //Dismounted
			case 1:
                setIsRidingStrider(true);
                if(isNoble())
                {
                	L2Skill striderAssaultSkill = SkillTable.getInstance().getInfo(325, 1);
                	addSkill(striderAssaultSkill, false); // not saved to DB
                }
                break;
			case 2:
                setIsFlying(true);
                break; //Flying Wyvern
			case 3:
				/* not used any more
				switch (npcId)
				{
					case 16041:
						setIsRidingFenrirWolf(true);
						break;
					case 16042:
						setIsRidingWFenrirWolf(true);
						break;
					case 16037:
						setIsRidingGreatSnowWolf(true);
						break;
				}*/
				break;
		}

		_mountType = mountType;
        _mountNpcId = npcId;
        _mountLevel = npcLevel;

		return true;
	}

	/**
	 * Return the type of Pet mounted (0 : none, 1 : Strider, 2 : Wyvern, 3: Wolf).<BR><BR>
	 */
	public int getMountType()
	{
		return _mountType;
	}
	
	@Override
	public final void stopAllEffects()
	{
		super.stopAllEffects();
		updateAndBroadcastStatus(2);
 	}

	@Override
	public final void stopAllEffectsExceptThoseThatLastThroughDeath()
	{
		super.stopAllEffectsExceptThoseThatLastThroughDeath();
		updateAndBroadcastStatus(2);
	}

	public final void stopCubics()
	{
		if (getCubics() != null)
		{
			boolean removed = false;
			for (L2CubicInstance cubic : getCubics().values())
			{
				cubic.stopAction();
				delCubic(cubic.getId());
				removed = true;
			}
			if (removed)
				broadcastUserInfo();
		}
	}

	public final void stopCubicsByOthers()
	{
		if (getCubics() != null)
		{
			boolean removed = false;
			for (L2CubicInstance cubic : getCubics().values())
			{
				if (cubic.givenByOther())
				{
					cubic.stopAction();
					delCubic(cubic.getId());
					removed = true;
				}
			}
			if (removed)
				broadcastUserInfo();
		}
	}

	/**
	 * Send a Server->Client packet UserInfo to this L2PcInstance and CharInfo to all L2PcInstance in its _KnownPlayers.<BR><BR>
	 *
	 * <B><U> Concept</U> :</B><BR><BR>
	 * Others L2PcInstance in the detection area of the L2PcInstance are identified in <B>_knownPlayers</B>.
	 * In order to inform other players of this L2PcInstance state modifications, server just need to go through _knownPlayers to send Server->Client Packet<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>Send a Server->Client packet UserInfo to this L2PcInstance (Public and Private Data)</li>
	 * <li>Send a Server->Client packet CharInfo to all L2PcInstance in _KnownPlayers of the L2PcInstance (Public data only)</li><BR><BR>
	 *
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : DON'T SEND UserInfo packet to other players instead of CharInfo packet.
	 * Indeed, UserInfo packet contains PRIVATE DATA as MaxHP, STR, DEX...</B></FONT><BR><BR>
	 *
	 */
	@Override
	public void updateAbnormalEffect()
	{
		broadcastUserInfo();
	}

	/**
	 * Disable the Inventory and create a new task to enable it after 1.5s.<BR><BR>
	 */
	public void tempInventoryDisable()
	{
		_inventoryDisable  = true;

		ThreadPoolManager.getInstance().scheduleGeneral(new InventoryEnable(), 1500);
	}

	/**
	 * Return True if the Inventory is disabled.<BR><BR>
	 */
	public boolean isInventoryDisabled()
	{
		return _inventoryDisable;
	}

	class InventoryEnable implements Runnable
	{
		public void run()
		{
			_inventoryDisable = false;
		}
	}

	public Map<Integer, L2CubicInstance> getCubics()
	{
		return _cubics;
	}

	/**
	 * Add a L2CubicInstance to the L2PcInstance _cubics.<BR><BR>
	 */
	public void addCubic(int id, int level, double matk, int activationtime, int activationchance, int totalLifetime, boolean givenByOther)
	{
		if (Config.DEBUG)
			_log.info("L2PcInstance(" + getName() + "): addCubic(" + id + "|" + level + "|" + matk + ")");
		L2CubicInstance cubic = new L2CubicInstance(this, id, level, (int) matk, activationtime, activationchance, totalLifetime, givenByOther);

		_cubics.put(id, cubic);
	}

	/**
	 * Remove a L2CubicInstance from the L2PcInstance _cubics.<BR><BR>
	 */
	public void delCubic(int id)
	{
		_cubics.remove(id);
	}

	/**
	 * Return the L2CubicInstance corresponding to the Identifier of the L2PcInstance _cubics.<BR><BR>
	 */
	public L2CubicInstance getCubic(int id)
	{
		return _cubics.get(id);
	}

	/**
	 * Return the modifier corresponding to the Enchant Effect of the Active Weapon (Min : 127).<BR><BR>
	 */
	public int getEnchantEffect()
	{
		L2ItemInstance wpn = getActiveWeaponInstance();

		if (wpn == null)
			return 0;

		return Math.min(127, wpn.getEnchantLevel());
	}

	/**
	 * Set the _lastFolkNpc of the L2PcInstance corresponding to the last Folk wich one the player talked.<BR><BR>
	 */
	public void setLastFolkNPC(L2Npc folkNpc)
	{
		_lastFolkNpc = folkNpc;
	}

	/**
	 * Return the _lastFolkNpc of the L2PcInstance corresponding to the last Folk wich one the player talked.<BR><BR>
	 */
	public L2Npc getLastFolkNPC()
	{
		return _lastFolkNpc;
	}

	/**
	 * Return True if L2PcInstance is a participant in the Festival of Darkness.<BR><BR>
	 */
	public boolean isFestivalParticipant()
	{
		return SevenSignsFestival.getInstance().isParticipant(this);
	}

	public void addAutoSoulShot(int itemId)
	{
		_activeSoulShots.put(itemId, itemId);
	}

	public void removeAutoSoulShot(int itemId)
	{
		_activeSoulShots.remove(itemId);
	}

	public Map<Integer, Integer> getAutoSoulShot()
	{
		return _activeSoulShots;
	}

	public void rechargeAutoSoulShot(boolean physical, boolean magic, boolean summon)
	{
		L2ItemInstance item;
		IItemHandler handler;
		
		if (_activeSoulShots == null || _activeSoulShots.isEmpty())
			return;
		
		try
		{
			Collection<Integer> vals = _activeSoulShots.values();
			
			for (int itemId : vals)
			{
				item = getInventory().getItemByItemId(itemId);
				
				if (item != null)
				{
					if (magic)
					{
						if (!summon)
						{
							switch(itemId)
							{
								case 2509: case 2510: case 2511: case 2512:
								case 2513: case 2514: case 3947:
								case 3948: case 3949: case 3950:
								case 3951: case 3952: case 5790:
								case 22072: case 22073: case 22074:
								case 22075: case 22076: case 22077:
								case 22078: case 22079: case 22080:
								case 22081:
									handler = ItemHandler.getInstance().getItemHandler(item.getEtcItem());
									
									if (handler != null)
										handler.useItem(this, item);
									
									break;
							}
						}
						else
						{
							switch(itemId)
							{
								case 6646: case 6647:
								case 20333: case 20334:
									handler = ItemHandler.getInstance().getItemHandler(item.getEtcItem());
									
									if (handler != null)
										handler.useItem(this, item);
									break;
							}
						}
					}
					
					if (physical)
					{
						if (!summon)
						{
							switch(itemId)
							{
								case 1463: case 1464: case 1465:
								case 1466: case 1467: case 1835:
								case 5789: case 22082: case 22083:
								case 22084: case 22085: case 22086:
									
									handler = ItemHandler.getInstance().getItemHandler(item.getEtcItem());
									
									if (handler != null)
										handler.useItem(this, item);
									
									break;
							}
						}
						else
						{
							if (itemId == 6645 || itemId == 20332)
							{
								handler = ItemHandler.getInstance().getItemHandler(item.getEtcItem());
								
								if (handler != null)
									handler.useItem(this, item);
							}
						}
					}
				}
				else
				{
					removeAutoSoulShot(itemId);
				}
			}
		}
		catch (NullPointerException npe)
		{
			
		}
	}
	
	public boolean disableAutoShot(int itemId)
	{
		if (getAutoSoulShot().containsKey(itemId))
		{
			removeAutoSoulShot(itemId);
			sendPacket(new ExAutoSoulShot(itemId, 0));
			
			SystemMessage sm = new SystemMessage(SystemMessageId.AUTO_USE_OF_S1_CANCELLED);
			sm.addString(ItemTable.getInstance().getTemplate(itemId).getName());
			sendPacket(sm);
			return true;
		}
		else return false;
	}

	private ScheduledFuture<?> _taskWarnUserTakeBreak;

	class WarnUserTakeBreak implements Runnable
	{
		public void run()
		{
			if (L2PcInstance.this.isOnline() == 1)
			{
				SystemMessage msg = new SystemMessage(SystemMessageId.PLAYING_FOR_LONG_TIME);
				L2PcInstance.this.sendPacket(msg);
			}
			else
				stopWarnUserTakeBreak();
		}
	}

	class RentPetTask implements Runnable
	{
		public void run()
		{
			stopRentPet();
		}
	}

	class WaterTask implements Runnable
	{
		public void run()
		{
			double reduceHp = getMaxHp()/100.0;

			if (reduceHp < 1)
				reduceHp = 1;

			reduceCurrentHp(reduceHp,L2PcInstance.this,false, false, null);
			//reduced hp, becouse not rest
			SystemMessage sm = new SystemMessage(SystemMessageId.DROWN_DAMAGE_S1);
			sm.addNumber((int)reduceHp);
			sendPacket(sm);

		}
	}

    class LookingForFishTask implements Runnable
    {
    	boolean _isNoob, _isUpperGrade;
    	int _fishType, _fishGutsCheck, _gutsCheckTime;
    	long _endTaskTime;

    	protected LookingForFishTask(int fishWaitTime, int fishGutsCheck, int fishType, boolean isNoob, boolean isUpperGrade)
    	{
    		_fishGutsCheck = fishGutsCheck;
    		_endTaskTime = System.currentTimeMillis() + fishWaitTime + 10000;
    		_fishType = fishType;
    		_isNoob = isNoob;
    		_isUpperGrade = isUpperGrade;
    	}

        public void run()
        {
            if (System.currentTimeMillis() >= _endTaskTime) {
            	endFishing(false);
            	return;
            }
        	if (_fishType == -1)
        		return;
            int check = Rnd.get(1000);
            if(_fishGutsCheck > check)
            {
                stopLookingForFishTask();
                startFishCombat(_isNoob, _isUpperGrade);
            }
        }

    }

	public int getClanPrivileges()
    {
		return _clanPrivileges;
	}

	public void setClanPrivileges(int n)
    {
		_clanPrivileges = n;
	}

    // baron etc
	public void setPledgeClass(int classId)
    {
        _pledgeClass = classId;
		checkItemRestriction();
    }

    public int getPledgeClass()
    {
        return _pledgeClass;
    }

    public void setPledgeType(int typeId)
    {
        _pledgeType = typeId;
    }

    public int getPledgeType()
    {
        return _pledgeType;
    }

    public int getApprentice()
    {
    	return _apprentice;
    }

    public void setApprentice(int apprentice_id)
    {
    	_apprentice = apprentice_id;
    }

    public int getSponsor()
    {
    	return _sponsor;
    }

    public void setSponsor(int sponsor_id)
    {
    	_sponsor = sponsor_id;
    }
    
    public int getBookMarkSlot()
    {
    	return _bookmarkslot;
    }
    
    public void setBookMarkSlot(int slot)
    {
    	_bookmarkslot = slot;
    	sendPacket(new ExGetBookMarkInfoPacket(this));
    }

	@Override
	public void sendMessage(String message)
	{
		sendPacket(SystemMessage.sendString(message));
	}

	public void enterObserverMode(int x, int y, int z)
	{
		_obsX = getX();
		_obsY = getY();
		_obsZ = getZ();

		_observerMode = true;
        setTarget(null);
		stopMove(null);
		setIsParalyzed(true);
        setIsInvul(true);
		getAppearance().setInvisible();
		sendPacket(new GMHide(1));
		sendPacket(new ObservationMode(x, y, z));
		setXYZ(x, y, z);

		broadcastUserInfo();
	}

	public void enterOlympiadObserverMode(int x, int y, int z, int id, boolean storeCoords)
    {
        if (getPet() != null)
            getPet().unSummon(this);

        if (!getCubics().isEmpty())
        {
            for (L2CubicInstance cubic : getCubics().values())
            {
                cubic.stopAction();
                cubic.cancelDisappear();
            }

            getCubics().clear();
        }
        
        if (getParty() != null)
        	getParty().removePartyMember(this);

    	_olympiadGameId = id;
        if (isSitting())
            standUp();
        if (storeCoords)
        {
	        _obsX = getX();
	        _obsY = getY();
	        _obsZ = getZ();
        }

        _observerMode = true;
        setTarget(null);
        setIsInvul(true);
        getAppearance().setInvisible();
        sendPacket(new GMHide(1));
        teleToLocation(x, y, z, false);
        sendPacket(new ExOlympiadMode(3));

        broadcastUserInfo();
    }

	public void leaveObserverMode()
	{
		setTarget(null);
		setXYZ(_obsX, _obsY, _obsZ);
		setIsParalyzed(false);
		sendPacket(new GMHide(0));
		if (!AdminCommandAccessRights.getInstance().hasAccess("admin_invis", getAccessLevel()))
			getAppearance().setVisible();
		if (!AdminCommandAccessRights.getInstance().hasAccess("admin_invul", getAccessLevel()))
			setIsInvul(false);
		if (getAI() != null)
			getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);

        _observerMode = false;
		sendPacket(new ObservationReturn(this));
		broadcastUserInfo();
	}

	public void leaveOlympiadObserverMode()
    {
		setTarget(null);
		sendPacket(new ExOlympiadMode(0));
        teleToLocation(_obsX, _obsY, _obsZ, true);
        sendPacket(new GMHide(0));
        if (!AdminCommandAccessRights.getInstance().hasAccess("admin_invis", getAccessLevel()))
			getAppearance().setVisible();
		if (!AdminCommandAccessRights.getInstance().hasAccess("admin_invul", getAccessLevel()))
			setIsInvul(false);
		if (getAI() != null)
            getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);

        Olympiad.removeSpectator(_olympiadGameId, this);
        _olympiadGameId = -1;
        _observerMode = false;
		broadcastUserInfo();
    }

    public void setOlympiadSide(int i)
    {
        _olympiadSide = i;
    }

    public int getOlympiadSide()
    {
        return _olympiadSide;
    }

    public void setOlympiadGameId(int id)
    {
        _olympiadGameId = id;
    }

    public int getOlympiadGameId()
    {
        return _olympiadGameId;
    }

	public int getObsX()
	{
		return _obsX;
	}

	public int getObsY()
	{
		return _obsY;
	}

	public int getObsZ()
	{
		return _obsZ;
	}

	public boolean inObserverMode()
	{
		return _observerMode;
	}

	public int getTeleMode()
	{
		return _telemode;
	}

	public void setTeleMode(int mode)
	{
		_telemode = mode;
	}

	public void setLoto(int i, int val)
	{
		_loto[i] = val;
	}

	public int getLoto(int i)
	{
		return _loto[i];
	}

	public void setRace(int i, int val)
	{
		_race[i] = val;
	}

	public int getRace(int i)
	{
		return _race[i];
	}

	public boolean getMessageRefusal()
	{
		return _messageRefusal;
	}

	public void setMessageRefusal(boolean mode)
	{
		_messageRefusal = mode;
		sendPacket(new EtcStatusUpdate(this));
	}

	public void setDietMode(boolean mode)
	{
		_dietMode = mode;
	}

	public boolean getDietMode()
	{
		return _dietMode;
	}

	public void setTradeRefusal(boolean mode)
	{
		_tradeRefusal = mode;
	}

	public boolean getTradeRefusal()
	{
		return _tradeRefusal;
	}

	public void setExchangeRefusal(boolean mode)
	{
		_exchangeRefusal = mode;
	}

	public boolean getExchangeRefusal()
	{
		return _exchangeRefusal;
	}

	public BlockList getBlockList()
	{
		return _blockList;
	}

	public void setHero(boolean hero)
	{
		if (hero && _baseClass == _activeClass)
		{
			for (L2Skill s : HeroSkillTable.getHeroSkills())
				addSkill(s, false); //Dont Save Hero skills to database
		}
		else
		{
			for (L2Skill s : HeroSkillTable.getHeroSkills())
				super.removeSkill(s); //Just Remove skills from nonHero characters
		}
		_hero = hero;
		
		sendSkillList();
	}

	public void setIsInOlympiadMode(boolean b)
    {
    	_inOlympiadMode = b;
    }

	public void setIsOlympiadStart(boolean b)
    {
    	_OlympiadStart = b;
    }

	public boolean isOlympiadStart(){
		return _OlympiadStart;
	}

    public boolean isHero()
    {
        return _hero;
    }

    public boolean isInOlympiadMode()
    {
    	return _inOlympiadMode;
    }

	public boolean isInDuel()
	{
		return _isInDuel;
	}

	public int getDuelId()
	{
		return _duelId;
	}

	public void setDuelState(int mode)
	{
		_duelState = mode;
	}

	public int getDuelState()
	{
		return _duelState;
	}

	/**
	 * Sets up the duel state using a non 0 duelId.
	 * @param duelId 0=not in a duel
	 */
	public void setIsInDuel(int duelId)
	{
		if (duelId > 0)
		{
			_isInDuel = true;
			_duelState = Duel.DUELSTATE_DUELLING;
			_duelId = duelId;
		}
		else
		{
			if (_duelState == Duel.DUELSTATE_DEAD) 
			{ 
				enableAllSkills(); 
				getStatus().startHpMpRegeneration(); 
			}
			_isInDuel = false;
			_duelState = Duel.DUELSTATE_NODUEL;
			_duelId = 0;
		}
	}

	/**
	 * This returns a SystemMessage stating why
	 * the player is not available for duelling.
	 * @return S1_CANNOT_DUEL... message
	 */
	public SystemMessage getNoDuelReason()
	{
		SystemMessage sm = new SystemMessage(_noDuelReason);
		sm.addPcName(this);
		_noDuelReason = SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL;
		return sm;
	}

	/**
	 * Checks if this player might join / start a duel.
	 * To get the reason use getNoDuelReason() after calling this function.
	 * @return true if the player might join/start a duel.
	 */
	public boolean canDuel()
	{
		if (isInCombat() || getPunishLevel() == PunishLevel.JAIL) { _noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_IS_CURRENTLY_ENGAGED_IN_BATTLE; return false; }
		if (isDead() || isAlikeDead() || (getCurrentHp() < getMaxHp()/2 || getCurrentMp() < getMaxMp()/2)) { _noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_HP_OR_MP_IS_BELOW_50_PERCENT; return false; }
		if (isInDuel()) { _noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_IS_ALREADY_ENGAGED_IN_A_DUEL; return false;}
		if (isInOlympiadMode()) { _noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_IS_PARTICIPATING_IN_THE_OLYMPIAD; return false; }
		if (isCursedWeaponEquipped()) { _noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_IS_IN_A_CHAOTIC_STATE; return false; }
		if (getPrivateStoreType() != STORE_PRIVATE_NONE) { _noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_IS_CURRENTLY_ENGAGED_IN_A_PRIVATE_STORE_OR_MANUFACTURE; return false; }
		if (isMounted() || isInBoat()) { _noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_IS_CURRENTLY_RIDING_A_BOAT_WYVERN_OR_STRIDER; return false; }
		if (isFishing()) { _noDuelReason = SystemMessageId.C1_CANNOT_DUEL_BECAUSE_C1_IS_CURRENTLY_FISHING; return false; }
		if (isInsideZone(ZONE_PVP) || isInsideZone(ZONE_PEACE) || isInsideZone(ZONE_SIEGE))
		{
			_noDuelReason = SystemMessageId.C1_CANNOT_MAKE_A_CHALLANGE_TO_A_DUEL_BECAUSE_C1_IS_CURRENTLY_IN_A_DUEL_PROHIBITED_AREA;
			return false;
		}
		return true;
	}

    public boolean isNoble()
    {
    	return _noble;
    }

    public void setNoble(boolean val)
    {
    	if (val)
    		for (L2Skill s : NobleSkillTable.getInstance().getNobleSkills())
    			addSkill(s, false); //Dont Save Noble skills to Sql
    	else
    		for (L2Skill s : NobleSkillTable.getInstance().getNobleSkills())
    			super.removeSkill(s); //Just Remove skills without deleting from Sql
    	_noble = val;
    	
    	sendSkillList();
    }

    public void setLvlJoinedAcademy(int lvl)
    {
    	_lvlJoinedAcademy = lvl;
    }

    public int getLvlJoinedAcademy()
    {
    	return _lvlJoinedAcademy;
    }

    public boolean isAcademyMember()
    {
      return _lvlJoinedAcademy > 0;
    }

	public void setTeam(int team)
	{
		_team = team;
		if (getPet() != null)
			getPet().broadcastStatusUpdate();
	}

	public int getTeam()
	{
		return _team;
	}

	public void setWantsPeace(int wantsPeace)
	{
		_wantsPeace = wantsPeace;
	}

	public int getWantsPeace()
	{
		return _wantsPeace;
	}

    public boolean isFishing()
    {
        return _fishing;
    }

    public void setFishing(boolean fishing)
    {
        _fishing = fishing;
    }

    public void setAllianceWithVarkaKetra(int sideAndLvlOfAlliance)
    {
    	// [-5,-1] varka, 0 neutral, [1,5] ketra
    	_alliedVarkaKetra = sideAndLvlOfAlliance;
    }

    public int getAllianceWithVarkaKetra()
    {
    	return _alliedVarkaKetra;
    }

    public boolean isAlliedWithVarka()
    {
        return (_alliedVarkaKetra < 0);
    }

    public boolean isAlliedWithKetra()
    {
        return (_alliedVarkaKetra > 0);
    }

	public void sendSkillList()
	{
		sendSkillList(this);
	}

	public void sendSkillList(L2PcInstance player)
	{
		boolean isDisabled = false;
		SkillList sl = new SkillList();
		if (player != null)
		{
			for (L2Skill s : player.getAllSkills())
			{
				if (s == null)
					continue;
				if (s.getId() > 9000 && s.getId() < 9007)
					continue; // Fake skills to change base stats
				if (_transformation != null && (!containsAllowedTransformSkill(s.getId()) && !s.allowOnTransform()))
					continue;
				if (player.getClan() != null)
					isDisabled = s.isClanSkill() && player.getClan().getReputationScore() < 0;

				int skillMaxLevel = SkillTable.getInstance().getMaxLevel(s.getId());
				boolean isEnchantable = skillMaxLevel > 100;
				if (isEnchantable)
				{
					L2EnchantSkillLearn esl = SkillTreeTable.getInstance().getSkillEnchantmentBySkillId(s.getId());
					if (esl != null)
					{
						//if player dont have min level to enchant 
						if (s.getLevel() < esl.getBaseLevel())
							isEnchantable = false;
					}
					// if no enchant data
					else
						isEnchantable = false;
				}

				sl.addSkill(s.getId(), s.getLevel(), s.isPassive(), isDisabled, isEnchantable);
			}
		}

		sendPacket(sl);
	}
    
    /**
     * 1. Add the specified class ID as a subclass (up to the maximum number of <b>three</b>)
     * for this character.<BR>
     * 2. This method no longer changes the active _classIndex of the player. This is only
     * done by the calling of setActiveClass() method as that should be the only way to do so.
	 *
     * @param int classId
     * @param int classIndex
     * @return boolean subclassAdded
     */
    public boolean addSubClass(int classId, int classIndex)
    {
    	if (!_subclassLock.tryLock())
    		return false;

    	try
    	{
        	if (getTotalSubClasses() == Config.MAX_SUBCLASS || classIndex == 0)
        		return false;

        	if (getSubClasses().containsKey(classIndex))
        		return false;

        	// Note: Never change _classIndex in any method other than setActiveClass().

            SubClass newClass = new SubClass();
            newClass.setClassId(classId);
            newClass.setClassIndex(classIndex);

            Connection con = null;
            PreparedStatement statement = null;

            try
            {
                // Store the basic info about this new sub-class.
                con = L2DatabaseFactory.getInstance().getConnection();
                statement = con.prepareStatement(ADD_CHAR_SUBCLASS);
                
                statement.setInt(1, getObjectId());
                statement.setInt(2, newClass.getClassId());
                statement.setLong(3, newClass.getExp());
                statement.setInt(4, newClass.getSp());
                statement.setInt(5, newClass.getLevel());
                statement.setInt(6, newClass.getClassIndex()); // <-- Added
                
                statement.execute();
            }
            catch (Exception e) {
                _log.warning("WARNING: Could not add character sub class for " + getName() + ": " + e);
                return false;
            }
            finally
            {
            	try
            	{
            		statement.close();
            	}
            	catch (Exception e)
            	{
            	}
                try
                {
                	con.close();
                }
                catch (Exception e)
                {
                }
            }

            // Commit after database INSERT incase exception is thrown.
            getSubClasses().put(newClass.getClassIndex(), newClass);

            if (Config.DEBUG)
                _log.info(getName() + " added class ID " + classId + " as a sub class at index " + classIndex + ".");

    		ClassId subTemplate = ClassId.values()[classId];
    		Collection<L2SkillLearn> skillTree = SkillTreeTable.getInstance().getAllowedSkills(subTemplate);

    		if (skillTree == null)
    			return true;

    		Map<Integer, L2Skill> prevSkillList = new FastMap<Integer, L2Skill>();

    		for (L2SkillLearn skillInfo : skillTree)
    		{
    			if (skillInfo.getMinLevel() <= 40)
    			{
    				L2Skill prevSkill = prevSkillList.get(skillInfo.getId());
    				L2Skill newSkill = SkillTable.getInstance().getInfo(skillInfo.getId(), skillInfo.getLevel());

    				if (prevSkill != null && (prevSkill.getLevel() > newSkill.getLevel()))
    					continue;

    				prevSkillList.put(newSkill.getId(), newSkill);
    				storeSkill(newSkill, prevSkill, classIndex);
    			}
    		}

            if (Config.DEBUG)
                _log.info(getName() + " was given " + getAllSkills().length + " skills for their new sub class.");

            return true;
    	}
    	finally
    	{
    		_subclassLock.unlock();
    	}
    }

    /**
     * 1. Completely erase all existance of the subClass linked to the classIndex.<BR>
     * 2. Send over the newClassId to addSubClass()to create a new instance on this classIndex.<BR>
     * 3. Upon Exception, revert the player to their BaseClass to avoid further problems.<BR>
     *
     * @param int classIndex
     * @param int newClassId
     * @return boolean subclassAdded
     */
    public boolean modifySubClass(int classIndex, int newClassId)
    {
    	if (!_subclassLock.tryLock())
    		return false;

    	try
    	{
        	int oldClassId = getSubClasses().get(classIndex).getClassId();

            if (Config.DEBUG)
    	    	_log.info(getName() + " has requested to modify sub class index " + classIndex + " from class ID " + oldClassId + " to " + newClassId + ".");

        	Connection con = null;
            PreparedStatement statement = null;

            try
            {
                con = L2DatabaseFactory.getInstance().getConnection();

                // Remove all henna info stored for this sub-class.
                statement = con.prepareStatement(DELETE_CHAR_HENNAS);
                statement.setInt(1, getObjectId());
                statement.setInt(2, classIndex);
                statement.execute();
                statement.close();

                // Remove all shortcuts info stored for this sub-class.
                statement = con.prepareStatement(DELETE_CHAR_SHORTCUTS);
                statement.setInt(1, getObjectId());
                statement.setInt(2, classIndex);
                statement.execute();
                statement.close();

                // Remove all effects info stored for this sub-class.
                statement = con.prepareStatement(DELETE_SKILL_SAVE);
                statement.setInt(1, getObjectId());
                statement.setInt(2, classIndex);
                statement.execute();
                statement.close();

                // Remove all skill info stored for this sub-class.
                statement = con.prepareStatement(DELETE_CHAR_SKILLS);
                statement.setInt(1, getObjectId());
                statement.setInt(2, classIndex);
                statement.execute();
                statement.close();

                // Remove all basic info stored about this sub-class.
                statement = con.prepareStatement(DELETE_CHAR_SUBCLASS);
                statement.setInt(1, getObjectId());
                statement.setInt(2, classIndex);
                statement.execute();
                statement.close();
            }
            catch (Exception e)
            {
            	_log.warning("Could not modify sub class for " + getName() + " to class index " + classIndex + ": " + e);

            	// This must be done in order to maintain data consistency.
                getSubClasses().remove(classIndex);
            	return false;
            }
            finally
            {
            	try
            	{
            		statement.close();
            	}
            	catch (Exception e)
            	{
            	}
                try
                {
                	con.close();
                }
                catch (Exception e)
                {
                }
            }

            getSubClasses().remove(classIndex);
    	}
    	finally
    	{
    		_subclassLock.unlock();
    	}

    	return addSubClass(newClassId, classIndex);
    }

    public boolean isSubClassActive()
    {
        return _classIndex > 0;
    }

    public Map<Integer, SubClass> getSubClasses()
    {
        if (_subClasses == null)
            _subClasses = new FastMap<Integer, SubClass>();

        return _subClasses;
    }

    public int getTotalSubClasses()
    {
        return getSubClasses().size();
    }

	public int getBaseClass()
	{
		return _baseClass;
	}

	public int getActiveClass()
	{
		return _activeClass;
	}

	public int getClassIndex()
	{
		return _classIndex;
	}

	private void setClassTemplate(int classId)
	{
		_activeClass = classId;

		L2PcTemplate t = CharTemplateTable.getInstance().getTemplate(classId);

		if (t == null)
		{
			_log.severe("Missing template for classId: "+classId);
			throw new Error();
		}

		// Set the template of the L2PcInstance
		setTemplate(t);
	}

	/**
	 * Changes the character's class based on the given class index.
	 * <BR><BR>
	 * An index of zero specifies the character's original (base) class,
	 * while indexes 1-3 specifies the character's sub-classes respectively.
	 * <br><br>
	 * <font color="00FF00"/>WARNING: Use only on subclase change</font>
	 *
	 * @param classIndex
	 */
	public boolean setActiveClass(int classIndex)
	{
		if (!_subclassLock.tryLock())
			return false;

		try
		{
			// Cannot switch or change subclasses while transformed
			if (_transformation != null)
				return false;

			// Remove active item skills before saving char to database
			// because next time when choosing this class, weared items can
			// be different
			for (L2ItemInstance item : getInventory().getAugmentedItems())
			{
				if (item != null && item.isEquipped())
					item.getAugmentation().removeBonus(this);
			}

			// abort any kind of cast.
			abortCast();

			// Stop casting for any player that may be casting a force buff on this l2pcinstance.
			for (L2Character character : getKnownList().getKnownCharacters())
			{
				if (character.getFusionSkill() != null && character.getFusionSkill().getTarget() == this)
					character.abortCast();
			}

			/*
			 * 1. Call store() before modifying _classIndex to avoid skill effects rollover.
			 * 2. Register the correct _classId against applied 'classIndex'.
			 */
			store(Config.SUBCLASS_STORE_SKILL_COOLTIME);
			_reuseTimeStamps.clear();

			// clear charges
			_charges.set(0);
			stopChargeTask();

			if (classIndex == 0)
			{
				setClassTemplate(getBaseClass());
			}
			else
			{
				try
				{
					setClassTemplate(getSubClasses().get(classIndex).getClassId());
				}
				catch (Exception e)
				{
					_log.info("Could not switch " + getName() + "'s sub class to class index " + classIndex + ": " + e);
					return false;
				}
			}
			_classIndex = classIndex;

			if (isInParty())
				getParty().recalculatePartyLevel();

			/*
			 * Update the character's change in class status.
			 *
			 * 1. Remove any active cubics from the player.
			 * 2. Renovate the characters table in the database with the new class info, storing also buff/effect data.
			 * 3. Remove all existing skills.
			 * 4. Restore all the learned skills for the current class from the database.
			 * 5. Restore effect/buff data for the new class.
			 * 6. Restore henna data for the class, applying the new stat modifiers while removing existing ones.
			 * 7. Reset HP/MP/CP stats and send Server->Client character status packet to reflect changes.
			 * 8. Restore shortcut data related to this class.
			 * 9. Resend a class change animation effect to broadcast to all nearby players.
			 * 10.Unsummon any active servitor from the player.
			 */

			if (getPet() instanceof L2SummonInstance)
				getPet().unSummon(this);

			for (L2Skill oldSkill : getAllSkills())
				super.removeSkill(oldSkill);

			stopAllEffectsExceptThoseThatLastThroughDeath();
			stopCubics();

			restoreRecipeBook(false);

			// Restore any Death Penalty Buff
			restoreDeathPenaltyBuffLevel();

			restoreSkills();
			regiveTemporarySkills();
			rewardSkills();

			// Prevents some issues when changing between subclases that shares skills
			if (_disabledSkills != null && !_disabledSkills.isEmpty()) 
				_disabledSkills.clear();

			restoreEffects();
			updateEffectIcons();
			sendPacket(new EtcStatusUpdate(this));

			// if player has quest 422: Repent Your Sins, remove it
			QuestState st = getQuestState("422_RepentYourSins");
			if (st != null)
				st.exitQuest(true);

			for (int i = 0; i < 3; i++)
				_henna[i] = null;

			restoreHenna();
			sendPacket(new HennaInfo(this));

			if (getCurrentHp() > getMaxHp())
				setCurrentHp(getMaxHp());
			if (getCurrentMp() > getMaxMp())
				setCurrentMp(getMaxMp());
			if (getCurrentCp() > getMaxCp())
				setCurrentCp(getMaxCp());

			refreshOverloaded();
			refreshExpertisePenalty();
			broadcastUserInfo();

			// Clear resurrect xp calculation
			setExpBeforeDeath(0);

			_shortCuts.restore();
			sendPacket(new ShortCutInit(this));            

			broadcastPacket(new SocialAction(getObjectId(), SocialAction.LEVEL_UP));
			sendPacket(new SkillCoolTime(this));
			sendPacket(new ExStorageMaxCount(this));

			return true;
		}
		finally
		{
			_subclassLock.unlock();
		}
	}

    public boolean isLocked()
    {
    	return _subclassLock.isLocked();
    }

	public void stopWarnUserTakeBreak()
	{
		if (_taskWarnUserTakeBreak != null)
		{
			_taskWarnUserTakeBreak.cancel(true);
			ThreadPoolManager.getInstance().removeGeneral((Runnable)_taskWarnUserTakeBreak);
			_taskWarnUserTakeBreak = null;
		}
	}

	public void startWarnUserTakeBreak()
	{
		if (_taskWarnUserTakeBreak == null)
			_taskWarnUserTakeBreak = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new WarnUserTakeBreak(), 7200000, 7200000);
	}

	public void stopRentPet()
	{
		if (_taskRentPet != null)
		{
			// if the rent of a wyvern expires while over a flying zone, tp to down before unmounting
			if (checkLandingState() && getMountType()==2)
				teleToLocation(MapRegionTable.TeleportWhereType.Town);
			
			if (this.dismount())  // this should always be true now, since we teleported already
			{
				_taskRentPet.cancel(true);
				_taskRentPet = null;
			}
		}
	}

	public void startRentPet(int seconds)
	{
		if (_taskRentPet == null)
			_taskRentPet = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new RentPetTask(), seconds * 1000L, seconds * 1000L);
	}

	public boolean isRentedPet()
	{
		if (_taskRentPet != null)
			return true;

		return false;
	}

	public void stopWaterTask()
	{
		if (_taskWater != null)
		{
			_taskWater.cancel(false);

			_taskWater = null;
			sendPacket(new SetupGauge(2, 0));
		}
	}

	public void startWaterTask()
	{
		if (!isDead() && _taskWater == null)
		{
			int timeinwater = (int)calcStat(Stats.BREATH, 60000, this, null);

			sendPacket(new SetupGauge(2, timeinwater));
			_taskWater = ThreadPoolManager.getInstance().scheduleEffectAtFixedRate(new WaterTask(), timeinwater, 1000);
		}
	}

	public boolean isInWater()
	{
		if (_taskWater != null)
			return true;

		return false;
	}

	public void checkWaterState()
	{
		if (isInsideZone(ZONE_WATER))
			startWaterTask();
		else 
			stopWaterTask();
	}

	public void onPlayerEnter()
	{
		startWarnUserTakeBreak();

        if (SevenSigns.getInstance().isSealValidationPeriod() || SevenSigns.getInstance().isCompResultsPeriod())
        {
            if (!isGM() && isIn7sDungeon() && SevenSigns.getInstance().getPlayerCabal(this) != SevenSigns.getInstance().getCabalHighestScore())
            {
                teleToLocation(MapRegionTable.TeleportWhereType.Town);
                setIsIn7sDungeon(false);
                sendMessage("You have been teleported to the nearest town due to the beginning of the Seal Validation period.");
            }
        }
        else
        {
            if (!isGM() && isIn7sDungeon() && SevenSigns.getInstance().getPlayerCabal(this) == SevenSigns.CABAL_NULL)
            {
                teleToLocation(MapRegionTable.TeleportWhereType.Town);
                setIsIn7sDungeon(false);
                sendMessage("You have been teleported to the nearest town because you have not signed for any cabal.");
            }
        }

        // jail task
        updatePunishState();

        if (isGM())
        {
        	if (_isInvul)
        		sendMessage("Entering world in Invulnerable mode.");
        	if (getAppearance().getInvisible())
        		sendMessage("Entering world in Invisible mode.");
        	if (isSilenceMode())
        		sendMessage("Entering world in Silence mode.");
        }

		revalidateZone(true);
		
		notifyFriends();
	}

	public long getLastAccess()
	{
		return _lastAccess;
	}

	private void checkRecom(int recsHave, int recsLeft)
	{
		Calendar check = Calendar.getInstance();
		check.setTimeInMillis(_lastRecomUpdate);
		check.add(Calendar.DAY_OF_MONTH,1);

		Calendar min = Calendar.getInstance();

		_recomHave = recsHave;
		_recomLeft = recsLeft;

		if (getStat().getLevel() < 10 || check.after(min) )
			return;

		restartRecom();
	}

	public void restartRecom()
	{
		if (Config.ALT_RECOMMEND)
		{
			Connection con = null;
			try
			{
				con = L2DatabaseFactory.getInstance().getConnection();
				PreparedStatement statement = con.prepareStatement(DELETE_CHAR_RECOMS);
				statement.setInt(1, getObjectId());
				
				statement.execute();
				statement.close();

				_recomChars.clear();
			}
			catch (Exception e)
			{
				_log.log(Level.SEVERE, "Failed cleaning character recommendations.", e);
			}
			finally
			{
				try { con.close(); } catch (Exception e) {}
			}
		}

		if (getStat().getLevel() < 20)
		{
			_recomLeft = 3;
			_recomHave--;
		}
		else if (getStat().getLevel() < 40)
		{
			_recomLeft = 6;
			_recomHave -= 2;
		}
		else
		{
			_recomLeft = 9;
			_recomHave -= 3;
		}
		if (_recomHave < 0) _recomHave = 0;

		// If we have to update last update time, but it's now before 13, we should set it to yesterday
		Calendar update = Calendar.getInstance();
		if(update.get(Calendar.HOUR_OF_DAY) < 13) update.add(Calendar.DAY_OF_MONTH,-1);
		update.set(Calendar.HOUR_OF_DAY,13);
		_lastRecomUpdate = update.getTimeInMillis();
	}

	
	@Override
	public void doRevive()
	{
		super.doRevive();
		stopEffects(L2EffectType.CHARMOFCOURAGE);
		updateEffectIcons();
		sendPacket(new EtcStatusUpdate(this));
		_reviveRequested = 0;
		_revivePower = 0;

		if (isMounted())
			startFeed(_mountNpcId);
		if (isInParty() && getParty().isInDimensionalRift())
		{
			if (!DimensionalRiftManager.getInstance().checkIfInPeaceZone(getX(), getY(), getZ()))
				getParty().getDimensionalRift().memberRessurected(this);
		}
	}

	@Override
	public void doRevive(double revivePower)
	{
		// Restore the player's lost experience,
		// depending on the % return of the skill used (based on its power).
		restoreExp(revivePower);
		doRevive();
	}

	public void reviveRequest(L2PcInstance Reviver, L2Skill skill, boolean Pet)
	{
		if (_reviveRequested == 1)
		{
			if (_revivePet == Pet)
			{
				Reviver.sendPacket(new SystemMessage(SystemMessageId.RES_HAS_ALREADY_BEEN_PROPOSED)); // Resurrection is already been proposed.
			}
			else
			{
				if (Pet)
					Reviver.sendPacket(new SystemMessage(SystemMessageId.CANNOT_RES_PET2)); // A pet cannot be resurrected while it's owner is in the process of resurrecting.
				else
					Reviver.sendPacket(new SystemMessage(SystemMessageId.MASTER_CANNOT_RES)); // While a pet is attempting to resurrect, it cannot help in resurrecting its master.
			}
			return;
		}
		if((Pet && getPet() != null && getPet().isDead()) || (!Pet && isDead()))
		{
			_reviveRequested = 1;
			int restoreExp = 0;
			if (isPhoenixBlessed())
				_revivePower=100;
			else if (getCharmOfCourage())
				_revivePower=0;
			else
				_revivePower = Formulas.calculateSkillResurrectRestorePercent(skill.getPower(), Reviver.getWIT());
			
			restoreExp = (int)Math.round((getExpBeforeDeath() - getExp()) * _revivePower / 100);
			    
			_revivePet = Pet;

			if (getCharmOfCourage())
			{
				ConfirmDlg dlg = new ConfirmDlg(SystemMessageId.RESURRECT_USING_CHARM_OF_COURAGE.getId());
				dlg.addTime(60000);
				sendPacket(dlg);
				return;
			}
			ConfirmDlg dlg = new ConfirmDlg(SystemMessageId.RESSURECTION_REQUEST_BY_C1_FOR_S2_XP.getId());
			dlg.addPcName(Reviver);
			dlg.addString(String.valueOf(restoreExp));
			sendPacket(dlg);
		}
	}

	public void reviveAnswer(int answer)
	{
		if (_reviveRequested != 1 || (!isDead() && !_revivePet) || (_revivePet && getPet() != null && !getPet().isDead()))
			return;
		//If character refuses a PhoenixBless autoress, cancel all buffs he had
		if (answer == 0 && isPhoenixBlessed())
		{
		    stopPhoenixBlessing(null);
		    stopAllEffectsExceptThoseThatLastThroughDeath();
		}
		if (answer == 1)
		{
			if (!_revivePet)
			{
				if (_revivePower != 0)
					doRevive(_revivePower);
				else
					doRevive();
			}
			else if (getPet() != null)
			{
				if (_revivePower != 0)
					getPet().doRevive(_revivePower);
				else
					getPet().doRevive();
			}
		}
		_reviveRequested = 0;
		_revivePower = 0;
	}

	public boolean isReviveRequested()
	{
		return (_reviveRequested == 1);
	}

	public boolean isRevivingPet()
	{
		return _revivePet;
	}

	public void removeReviving()
	{
		_reviveRequested = 0;
		_revivePower = 0;
	}

	public void onActionRequest()
	{
		setProtection(false);
	}

	/**
	 * @param expertiseIndex The expertiseIndex to set.
	 */
	public void setExpertiseIndex(int expertiseIndex)
	{
		_expertiseIndex = expertiseIndex;
	}

	/**
	 * @return Returns the expertiseIndex.
	 */
	public int getExpertiseIndex()
	{
		return _expertiseIndex;
	}

	@Override
	public final void onTeleported()
	{
		super.onTeleported();
		
		// Force a revalidation
		revalidateZone(true);

		checkItemRestriction();

		if ((Config.PLAYER_SPAWN_PROTECTION > 0) && !isInOlympiadMode())
			setProtection(true);
		
		// Trained beast is after teleport lost
		if (getTrainedBeast() != null)
		{
			getTrainedBeast().decayMe();
			setTrainedBeast(null);
		}
		
		// Modify the position of the pet if necessary
		L2Summon pet = getPet(); 
		if (pet != null)
		{
			pet.setFollowStatus(false);
			pet.teleToLocation(getPosition().getX(), getPosition().getY(), getPosition().getZ(), false);
			((L2SummonAI)pet.getAI()).setStartFollowController(true);
			pet.setFollowStatus(true);
			pet.updateAndBroadcastStatus(0);
		}

		TvTEvent.onTeleported(this);
	}

	@Override
	public void setIsTeleporting(boolean teleport)
	{
		super.setIsTeleporting(teleport);
		if (teleport)
		{
			if (_teleportWatchdog == null && Config.TELEPORT_WATCHDOG_TIMEOUT > 0)
				_teleportWatchdog = ThreadPoolManager.getInstance().scheduleGeneral(new TeleportWatchdog(this), Config.TELEPORT_WATCHDOG_TIMEOUT * 1000);
		}
		else
		{
			if (_teleportWatchdog != null)
			{
				_teleportWatchdog.cancel(false);
				ThreadPoolManager.getInstance().removeGeneral((Runnable)_teleportWatchdog);
				_teleportWatchdog = null;
			}
		}
	}

	class TeleportWatchdog implements Runnable
	{
		private final L2PcInstance _player;

		TeleportWatchdog(L2PcInstance player)
		{
			_player = player;
		}

		public void run()
		{
			if (_player == null || !_player.isTeleporting())
				return;

			if (Config.DEBUG)
				_log.warning("Player " + _player.getName() + " teleport timeout expired");
			_player.onTeleported();
		}
	}

	public void setLastPartyPosition(int x, int y, int z)
	{
		_lastPartyPosition.setXYZ(x,y,z);
	}

	public int getLastPartyPositionDistance(int x, int y, int z)
	{
		double dx = (x - _lastPartyPosition.getX());
		double dy = (y - _lastPartyPosition.getY());
		double dz = (z - _lastPartyPosition.getZ());

		return (int)Math.sqrt(dx*dx + dy*dy + dz*dz);
	}

	public void setLastServerPosition(int x, int y, int z)
	{
		_lastServerPosition.setXYZ(x,y,z);
	}
	
	public Point3D getLastServerPosition()
	{
		return _lastServerPosition;
	}

	public boolean checkLastServerPosition(int x, int y, int z)
	{
		return _lastServerPosition.equals(x,y,z);
	}

	public int getLastServerDistance(int x, int y, int z)
	{
		double dx = (x - _lastServerPosition.getX());
		double dy = (y - _lastServerPosition.getY());
		double dz = (z - _lastServerPosition.getZ());

		return (int)Math.sqrt(dx*dx + dy*dy + dz*dz);
	}

	@Override
	public void addExpAndSp(long addToExp, int addToSp)
	{
		getStat().addExpAndSp(addToExp, addToSp, false);
	}

	public void addExpAndSp(long addToExp, int addToSp, boolean useVitality)
	{
		getStat().addExpAndSp(addToExp, addToSp, useVitality);
	}

	public void removeExpAndSp(long removeExp, int removeSp)
	{
		getStat().removeExpAndSp(removeExp, removeSp, true);
	}
	
	public void removeExpAndSp(long removeExp, int removeSp, boolean sendMessage)
	{
		getStat().removeExpAndSp(removeExp, removeSp, sendMessage);
	}

	@Override
	public void reduceCurrentHp(double i, L2Character attacker, L2Skill skill)
    {
    	getStatus().reduceHp(i, attacker);

    	// notify the tamed beast of attacks
    	if (getTrainedBeast() != null )
    		getTrainedBeast().onOwnerGotAttacked(attacker);
    }
	@Override
	public void reduceCurrentHp(double value, L2Character attacker, boolean awake, boolean isDOT, L2Skill skill)
	{
		getStatus().reduceHp(value, attacker, awake, isDOT, false);

    	// notify the tamed beast of attacks
    	if (getTrainedBeast() != null )
    		getTrainedBeast().onOwnerGotAttacked(attacker);
	}

	public void broadcastSnoop(int type, String name, String _text)
	{
		if(!_snoopListener.isEmpty())
		{
			Snoop sn = new Snoop(getObjectId(),getName(),type,name,_text);

            for (L2PcInstance pci : _snoopListener)
				if (pci != null)
					pci.sendPacket(sn);
		}
	}

	public void addSnooper(L2PcInstance pci )
	{
		if(!_snoopListener.contains(pci))
			_snoopListener.add(pci);
	}

	public void removeSnooper(L2PcInstance pci )
	{
		_snoopListener.remove(pci);
	}

	public void addSnooped(L2PcInstance pci )
	{
		if(!_snoopedPlayer.contains(pci))
			_snoopedPlayer.add(pci);
	}

	public void removeSnooped(L2PcInstance pci )
	{
		_snoopedPlayer.remove(pci);
	}

	public synchronized void addBypass(String bypass)
	{
		if (bypass == null) return;
		_validBypass.add(bypass);
		//_log.warning("[BypassAdd]"+getName()+" '"+bypass+"'");
	}

	public synchronized void addBypass2(String bypass)
	{
		if (bypass == null) return;
		_validBypass2.add(bypass);
		//_log.warning("[BypassAdd]"+getName()+" '"+bypass+"'");
	}

	public synchronized boolean validateBypass(String cmd)
	{
		if (!Config.BYPASS_VALIDATION)
			return true;

		for (String bp : _validBypass)
		{
		    if (bp == null) continue;

			//_log.warning("[BypassValidation]"+getName()+" '"+bp+"'");
			if (bp.equals(cmd))
				return true;
		}

		for (String bp : _validBypass2)
		{
		    if (bp == null) continue;

			//_log.warning("[BypassValidation]"+getName()+" '"+bp+"'");
			if (cmd.startsWith(bp))
				return true;
		}
		_log.warning("[L2PcInstance] player ["+getName()+"] sent invalid bypass '"+cmd+"', ban this player!");
		return false;
	}

	/**
	 * Performs following tests:<br>
	 * <li> Inventory contains item
	 * <li> Item owner id == this.owner id
	 * <li> It isnt pet control item while mounting pet or pet summoned
	 * <li> It isnt active enchant item
	 * <li> It isnt cursed weapon/item
	 * <li> It isnt wear item
	 * <br>
	 * 
	 * @param objectId: item object id
	 * @param action: just for login porpouse
	 * @return
	 */
	public boolean validateItemManipulation(int objectId, String action)
	{
		L2ItemInstance item = getInventory().getItemByObjectId(objectId);

		if (item == null || item.getOwnerId() != getObjectId())
		{
			_log.finest(getObjectId()+": player tried to " + action + " item he is not owner of");
			return false;
		}

		// Pet is summoned and not the item that summoned the pet AND not the buggle from strider you're mounting
		if (getPet() != null && getPet().getControlItemId() == objectId || getMountObjectID() == objectId)
		{
			if (Config.DEBUG)
				_log.finest(getObjectId()+": player tried to " + action + " item controling pet");

			return false;
		}

		if(getActiveEnchantItem() != null && getActiveEnchantItem().getObjectId() == objectId)
		{
			if (Config.DEBUG)
				_log.finest(getObjectId()+":player tried to " + action + " an enchant scroll he was using");

			return false;
		}

		if (CursedWeaponsManager.getInstance().isCursed(item.getItemId()))
		{
			// can not trade a cursed weapon
			return false;
		}

		if (item.isWear())
		{
			// cannot drop/trade wear-items
			return false;
		}

		return true;
	}

	public synchronized void clearBypass()
	{
        _validBypass.clear();
        _validBypass2.clear();
	}

	/**
	 * @return Returns the inBoat.
	 */
	public boolean isInBoat()
	{
		return _inBoat;
	}

	/**
	 * @param inBoat The inBoat to set.
	 */
	public void setInBoat(boolean inBoat)
	{
		_inBoat = inBoat;
	}

	/**
	 * @return
	 */
	public L2BoatInstance getBoat()
	{
		return _boat;
	}

	/**
	 * @param boat
	 */
	public void setBoat(L2BoatInstance boat)
	{
		_boat = boat;
	}

	/**
	 * @return Returns the inAirShip.
	 */
	public boolean isInAirShip()
	{
		return _inAirShip;
	}

	/**
	 * @param inAirShip The inAirShip to set.
	 */
	public void setInAirShip(boolean inAirShip)
	{
		_inAirShip = inAirShip;
	}

	/**
	 * @return
	 */
	public L2AirShipInstance getAirShip()
	{
		return _airShip;
	}

	/**
	 * @param airShip
	 */
	public void setAirShip(L2AirShipInstance airShip)
	{
		if (airShip != null)
			setInAirShip(true);
		else
			setInAirShip(false);
		_airShip = airShip;
	}
	
	public void setInCrystallize(boolean inCrystallize)
	{
		_inCrystallize = inCrystallize;
	}

	public boolean isInCrystallize()
	{
		return _inCrystallize;
	}

	/**
	 * @return
	 */
	public Point3D getInBoatPosition()
	{
		return _inBoatPosition;
	}

	public void setInBoatPosition(Point3D pt)
	{
		_inBoatPosition = pt;
	}

	/**
	 * @return
	 */
	public Point3D getInAirShipPosition()
	{
		return _inAirShipPosition;
	}

	public void setInAirShipPosition(Point3D pt)
	{
		_inAirShipPosition = pt;
	}

	/**
	 * Manage the delete task of a L2PcInstance (Leave Party, Unsummon pet, Save its inventory in the database, Remove it from the world...).<BR><BR>
	 *
	 * <B><U> Actions</U> :</B><BR><BR>
	 * <li>If the L2PcInstance is in observer mode, set its position to its position before entering in observer mode </li>
	 * <li>Set the online Flag to True or False and update the characters table of the database with online status and lastAccess </li>
	 * <li>Stop the HP/MP/CP Regeneration task </li>
	 * <li>Cancel Crafting, Attak or Cast </li>
	 * <li>Remove the L2PcInstance from the world </li>
	 * <li>Stop Party and Unsummon Pet </li>
	 * <li>Update database with items in its inventory and remove them from the world </li>
	 * <li>Remove all L2Object from _knownObjects and _knownPlayer of the L2Character then cancel Attak or Cast and notify AI </li>
	 * <li>Close the connection with the client </li><BR><BR>
	 *
	 */
	public void deleteMe(boolean closeClient)
	{
		try
		{
			abortAttack();
			abortCast();
			stopMove(null);
			// Check if the L2PcInstance is in observer mode to set its position to its position
			// before entering in observer mode
			if (inObserverMode())
				setXYZ(_obsX, _obsY, _obsZ);
			else if (isInAirShip())
				getAirShip().oustPlayer(this);
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}
		
		//remove combat flag
		try
		{
			if (getInventory().getItemByItemId(9819) != null)
			{
				Fort fort = FortManager.getInstance().getFort(this);
				if (fort != null)
					FortSiegeManager.getInstance().dropCombatFlag(this);
				else
				{
					int slot = getInventory().getSlotFromItem(getInventory().getItemByItemId(9819));
					getInventory().unEquipItemInBodySlotAndRecord(slot);
					destroyItem("CombatFlag", getInventory().getItemByItemId(9819), null, true);
				}
			}
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}
		
		try
		{
			if (isFlying())
			{
				removeSkill(SkillTable.getInstance().getInfo(4289, 1));
			}
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}
		
		try
		{
			CommunityServerThread.getInstance().sendPacket(new WorldInfo(this, null,WorldInfo.TYPE_UPDATE_PLAYER_STATUS));
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}
		
		// Set the online Flag to True or False and update the characters table of the database with online status and lastAccess (called when login and logout)
		try
		{
			setOnlineStatus(false);
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}
		
		// Stop the HP/MP/CP Regeneration task (scheduled tasks)
		try
		{
			stopAllTimers();
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}
		
		try
		{
			setIsTeleporting(false);
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}

		// Stop crafting, if in progress
		try
		{
			RecipeController.getInstance().requestMakeItemAbort(this);
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}
		
		// Cancel Attak or Cast
		try
		{
			setTarget(null);
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}
		
		try
		{
			if (_fusionSkill != null)
				abortCast();
			
			for (L2Character character : getKnownList().getKnownCharacters())
				if (character.getFusionSkill() != null && character.getFusionSkill().getTarget() == this)
					character.abortCast();
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}
		
		try
		{
			for (L2Effect effect : getAllEffects())
			{
				switch (effect.getEffectType())
				{
					case SIGNET_GROUND:
					case SIGNET_EFFECT:
						effect.exit();
						break;
				}
			}
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}
		
		// Remove from world regions zones
		L2WorldRegion oldRegion = getWorldRegion();
		
		// Remove the L2PcInstance from the world
		if (isVisible())
			try
			{
				decayMe();
			}
			catch (Exception e)
			{
				_log.log(Level.SEVERE, "deleteMe()", e);
			}
		
		if (oldRegion != null)
			oldRegion.removeFromZones(this);
		
		// If a Party is in progress, leave it (and festival party)
		if (isInParty())
			try
			{
				leaveParty();
			}
			catch (Exception e)
			{
				_log.log(Level.SEVERE, "deleteMe()", e);
			}
		
		if (Olympiad.getInstance().isRegistered(this) || getOlympiadGameId() != -1) // handle removal from olympiad game
			Olympiad.getInstance().removeDisconnectedCompetitor(this);
		
		// If the L2PcInstance has Pet, unsummon it
		if (getPet() != null)
		{
			try
			{
				getPet().unSummon(this);
				// dead pet wasnt unsummoned, broadcast npcinfo changes (pet will be without owner name - means owner offline)
				if (getPet() != null)
					getPet().broadcastNpcInfo(0);
			}
			catch (Exception e)
			{
				_log.log(Level.SEVERE, "deleteMe()", e);
			}// returns pet to control item
		}
		
		if (getClanId() != 0 && getClan() != null)
		{
			// set the status for pledge member list to OFFLINE
			try
			{
				L2ClanMember clanMember = getClan().getClanMember(getName());
				if (clanMember != null)
					clanMember.setPlayerInstance(null);
					
			}
			catch (Exception e)
			{
				_log.log(Level.SEVERE, "deleteMe()", e);
			}
		}
		
		if (getActiveRequester() != null)
		{
			// deals with sudden exit in the middle of transaction
			setActiveRequester(null);
		}
		
		// If the L2PcInstance is a GM, remove it from the GM List
		if (isGM())
		{
			try
			{
				GmListTable.getInstance().deleteGm(this);
			}
			catch (Exception e)
			{
				_log.log(Level.SEVERE, "deleteMe()", e);
			}
		}

		// remove player from instance and set spawn location if any
		try
		{
			final int instanceId = getInstanceId();
			if (instanceId != 0 && !Config.RESTORE_PLAYER_INSTANCE)
			{
				final Instance inst = InstanceManager.getInstance().getInstance(instanceId);
				if (inst != null)
				{
					inst.removePlayer(getObjectId());
					final int[] spawn = inst.getSpawnLoc();
					if (spawn[0] != 0 && spawn[1] != 0 && spawn[2] != 0)
					{
						final int x = spawn[0] + Rnd.get(-30, 30);
						final int y = spawn[1] + Rnd.get(-30, 30);
						setXYZ(x, y, spawn[2]);
						if (getPet() != null) // dead pet
						{
							getPet().teleToLocation(x, y, spawn[2]);
							getPet().setInstanceId(0);
						}
					}
				}
			}
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}

		// TvT Event removal
		try
		{
			TvTEvent.onLogout(this);
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}

		// Update database with items in its inventory and remove them from the world
		try
		{
			getInventory().deleteMe();
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}
		
		// Update database with items in its warehouse and remove them from the world
		try
		{
			clearWarehouse();
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}
		if (Config.WAREHOUSE_CACHE)
			WarehouseCacheManager.getInstance().remCacheTask(this);
		
		try
		{
			clearRefund();
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}
		
		if (isCursedWeaponEquipped())
		{
			try
			{
				CursedWeaponsManager.getInstance().getCursedWeapon(_cursedWeaponEquippedId).setPlayer(null);
			}
			catch (Exception e)
			{
				_log.log(Level.SEVERE, "deleteMe()", e);
			}
		}
		
		// Remove all L2Object from _knownObjects and _knownPlayer of the L2Character then cancel Attak or Cast and notify AI
		try
		{
			getKnownList().removeAllKnownObjects();
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "deleteMe()", e);
		}
		
		// Close the connection with the client
		closeNetConnection(closeClient);
		
		if (getClanId() > 0)
			getClan().broadcastToOtherOnlineMembers(new PledgeShowMemberListUpdate(this), this);
		//ClanTable.getInstance().getClan(getClanId()).broadcastToOnlineMembers(new PledgeShowMemberListAdd(this));
		
		for (L2PcInstance player : _snoopedPlayer)
			player.removeSnooper(this);
		
		for (L2PcInstance player : _snoopListener)
			player.removeSnooped(this);
		
		if (_chanceSkills != null)
		{
			_chanceSkills.setOwner(null);
			_chanceSkills = null;
		}
		
		// Remove L2Object object from _allObjects of L2World
		L2World.getInstance().removeObject(this);
		L2World.getInstance().removeFromAllPlayers(this); // force remove in case of crash during teleport
		
		//update bbs
		try
		{
			RegionBBSManager.getInstance().changeCommunityBoard();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		
		try
		{
			notifyFriends();
			getBlockList().playerLogout();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	private FishData _fish;

   /*  startFishing() was stripped of any pre-fishing related checks, namely the fishing zone check.
    * Also worthy of note is the fact the code to find the hook landing position was also striped. The
    * stripped code was moved into fishing.java. In my opinion it makes more sense for it to be there
    * since all other skill related checks were also there. Last but not least, moving the zone check
    * there, fixed a bug where baits would always be consumed no matter if fishing actualy took place.
    * startFishing() now takes up 3 arguments, wich are acurately described as being the hook landing 
    * coordinates.
    */
	public void startFishing(int _x, int _y, int _z)
    {
        stopMove(null);
        setIsImmobilized(true);
        _fishing = true;
        _fishx = _x;
        _fishy = _y;
        _fishz = _z;
        broadcastUserInfo();
        //Starts fishing
    	int lvl = GetRandomFishLvl();
		int group = GetRandomGroup();
		int type = GetRandomFishType(group);
		List<FishData> fishs = FishTable.getInstance().getfish(lvl, type, group);
		if (fishs == null || fishs.isEmpty())
		{
			sendMessage("Error - Fishes are not definied");
			endFishing(false);
			return;
		}
		int check = Rnd.get(fishs.size());
		// Use a copy constructor else the fish data may be over-written below
		_fish = new FishData(fishs.get(check));
		fishs.clear();
		fishs = null;
        sendPacket(new SystemMessage(SystemMessageId.CAST_LINE_AND_START_FISHING));
        ExFishingStart efs = null;
        if (!GameTimeController.getInstance().isNowNight() && _lure.isNightLure())
        	_fish.setType(-1);
		//sendMessage("Hook x,y: " + _x + "," + _y + " - Water Z, Player Z:" + _z + ", " + getZ()); //debug line, uncoment to show coordinates used in fishing.
    	efs = new ExFishingStart(this,_fish.getType(),_x,_y,_z,_lure.isNightLure());
        broadcastPacket(efs);
        startLookingForFishTask();
    }
    public void stopLookingForFishTask()
    {
        if (_taskforfish != null)
        {
            _taskforfish.cancel(false);
            _taskforfish = null;
        }
    }
    public void startLookingForFishTask()
    {
        if (!isDead() && _taskforfish == null)
        {
            int checkDelay = 0;
            boolean isNoob = false;
            boolean isUpperGrade = false;

            if (_lure != null)
            {
        		int lureid = _lure.getItemId();
        		isNoob = _fish.getGroup() == 0;
        		isUpperGrade = _fish.getGroup() == 2;
                if (lureid == 6519 || lureid == 6522 || lureid == 6525 || lureid == 8505 || lureid == 8508 || lureid == 8511) //low grade
                	checkDelay = Math.round((float)(_fish.getGutsCheckTime() * (1.33)));
                else if (lureid == 6520 || lureid == 6523 || lureid == 6526 || (lureid >= 8505 && lureid <= 8513) || (lureid >= 7610 && lureid <= 7613) || (lureid >= 7807 && lureid <= 7809) || (lureid >= 8484 && lureid <= 8486)) //medium grade, beginner, prize-winning & quest special bait
                	checkDelay = Math.round((float)(_fish.getGutsCheckTime() * (1.00)));
                else if (lureid == 6521 || lureid == 6524 || lureid == 6527 || lureid == 8507 || lureid == 8510 || lureid == 8513) //high grade
                	checkDelay = Math.round((float)(_fish.getGutsCheckTime() * (0.66)));
            }
            _taskforfish = ThreadPoolManager.getInstance().scheduleEffectAtFixedRate(new LookingForFishTask(_fish.getWaitTime(), _fish.getFishGuts(), _fish.getType(), isNoob, isUpperGrade), 10000, checkDelay);
        }
    }

	private int GetRandomGroup()
	{
		switch (_lure.getItemId()) {
			case 7807: //green for beginners
			case 7808: //purple for beginners
			case 7809: //yellow for beginners
			case 8486: //prize-winning for beginners
				return 0;
			case 8485: //prize-winning luminous
			case 8506: //green luminous
			case 8509: //purple luminous
			case 8512: //yellow luminous
				return 2;
			default:
				return 1;
		}
	}
	private int GetRandomFishType(int group)
	{
		int check = Rnd.get(100);
		int type = 1;
		switch (group) {
			case 0:	//fish for novices
				switch (_lure.getItemId()) {
					case 7807: //green lure, preferred by fast-moving (nimble) fish (type 5)
						if (check <= 54)
							type = 5;
						else if (check <= 77)
							type = 4;
						else
							type = 6;
						break;
					case 7808: //purple lure, preferred by fat fish (type 4)
						if (check <= 54)
							type = 4;
						else if (check <= 77)
							type = 6;
						else
							type = 5;
						break;
					case 7809: //yellow lure, preferred by ugly fish (type 6)
						if (check <= 54)
							type = 6;
						else if (check <= 77)
							type = 5;
						else
							type = 4;
						break;
					case 8486:	//prize-winning fishing lure for beginners
						if (check <= 33)
							type = 4;
						else if (check <= 66)
							type = 5;
						else
							type = 6;
						break;
				}
				break;
			case 1:	//normal fish
				switch (_lure.getItemId()) {
					case 7610:
					case 7611:
					case 7612:
					case 7613:
						type = 3;
						break;
					case 6519:  //all theese lures (green) are prefered by fast-moving (nimble) fish (type 1)
					case 8505:
					case 6520:
					case 6521:
					case 8507:
						if (check <= 54)
							type = 1;
						else if (check <= 74)
							type = 0;
						else if (check <= 94)
							type = 2;
						else
							type = 3;
						break;
					case 6522:	 //all theese lures (purple) are prefered by fat fish (type 0)
					case 8508:
					case 6523:
					case 6524:
					case 8510:
						if (check <= 54)
							type = 0;
						else if (check <= 74)
							type = 1;
						else if (check <= 94)
							type = 2;
						else
							type = 3;
						break;
					case 6525:	//all theese lures (yellow) are prefered by ugly fish (type 2)
					case 8511:
					case 6526:
					case 6527:
					case 8513:
						if (check <= 55)
							type = 2;
						else if (check <= 74)
							type = 1;
						else if (check <= 94)
							type = 0;
						else
							type = 3;
						break;
					case 8484:	//prize-winning fishing lure
						if (check <= 33)
							type = 0;
						else if (check <= 66)
							type = 1;
						else
							type = 2;
						break;
				}
				break;
			case 2:	//upper grade fish, luminous lure
				switch (_lure.getItemId()) {
					case 8506: //green lure, preferred by fast-moving (nimble) fish (type 8)
						if (check <= 54)
							type = 8;
						else if (check <= 77)
							type = 7;
						else
							type = 9;
						break;
					case 8509: //purple lure, preferred by fat fish (type 7)
						if (check <= 54)
							type = 7;
						else if (check <= 77)
							type = 9;
						else
							type = 8;
						break;
					case 8512: //yellow lure, preferred by ugly fish (type 9)
						if (check <= 54)
							type = 9;
						else if (check <= 77)
							type = 8;
						else
							type = 7;
						break;
					case 8485: //prize-winning fishing lure
						if (check <= 33)
							type = 7;
						else if (check <= 66)
							type = 8;
						else
							type = 9;
						break;
				}
		}
		return type;
	}
	private int GetRandomFishLvl()
	{
		L2Effect[] effects = getAllEffects();
		int skilllvl = getSkillLevel(1315);
		for (L2Effect e : effects) {
			if (e.getSkill().getId() == 2274)
				skilllvl = (int)e.getSkill().getPower(this);
		}
		if (skilllvl <= 0) return 1;
		int randomlvl;
		int check = Rnd.get(100);

		if (check <= 50)
		{
			randomlvl = skilllvl;
		}
		else if (check <= 85)
		{
			randomlvl = skilllvl - 1;
			if (randomlvl <= 0)
			{
				randomlvl = 1;
			}
		}
		else
		{
			randomlvl = skilllvl + 1;
			if (randomlvl > 27) randomlvl = 27;
		}

		return randomlvl;
	}
	public void startFishCombat(boolean isNoob, boolean isUpperGrade)
    {
        _fishCombat = new L2Fishing (this, _fish, isNoob, isUpperGrade);
    }
    
	public void endFishing(boolean win)
    {
        ExFishingEnd efe = new ExFishingEnd(win, this);
        broadcastPacket(efe);
        _fishing = false;
        _fishx = 0;
        _fishy = 0;
        _fishz = 0;
        broadcastUserInfo();
        if (_fishCombat == null)
            sendPacket(new SystemMessage(SystemMessageId.BAIT_LOST_FISH_GOT_AWAY));
        _fishCombat = null;
        _lure = null;
        //Ends fishing
        sendPacket(new SystemMessage(SystemMessageId.REEL_LINE_AND_STOP_FISHING));
        setIsImmobilized(false);
        stopLookingForFishTask();
    }

    public L2Fishing getFishCombat()
    {
        return _fishCombat;
    }

    public int getFishx()
    {
        return _fishx;
    }

    public int getFishy()
    {
        return _fishy;
    }

    public int getFishz()
    {
        return _fishz;
    }

    public void setLure (L2ItemInstance lure)
    {
        _lure = lure;
    }

 	public L2ItemInstance getLure()
	{
 		return _lure;
	}

	public int getInventoryLimit()
	{
		int ivlim;
		if (isGM())
			ivlim = Config.INVENTORY_MAXIMUM_GM;
		else if (getRace() == Race.Dwarf)
			ivlim = Config.INVENTORY_MAXIMUM_DWARF;
		else
        	ivlim = Config.INVENTORY_MAXIMUM_NO_DWARF;
		ivlim += (int)getStat().calcStat(Stats.INV_LIM, 0, null, null);

		return ivlim;
	}

	public int getWareHouseLimit()
	{
		int whlim;
		if (getRace() == Race.Dwarf)
               whlim = Config.WAREHOUSE_SLOTS_DWARF;
		else
			whlim = Config.WAREHOUSE_SLOTS_NO_DWARF;

		whlim += (int)getStat().calcStat(Stats.WH_LIM, 0, null, null);

		return whlim;
	}
	
	public int getPrivateSellStoreLimit()
	{
		int pslim;
	
		if (getRace() == Race.Dwarf)
			pslim = Config.MAX_PVTSTORESELL_SLOTS_DWARF;
        else
        	pslim = Config.MAX_PVTSTORESELL_SLOTS_OTHER;

		pslim += (int)getStat().calcStat(Stats.P_SELL_LIM, 0, null, null);

		return pslim;
	}

	public int getPrivateBuyStoreLimit()
	{
		int pblim;
		
		if (getRace() == Race.Dwarf)
			pblim = Config.MAX_PVTSTOREBUY_SLOTS_DWARF;
		else
			pblim = Config.MAX_PVTSTOREBUY_SLOTS_OTHER;
		pblim += (int)getStat().calcStat(Stats.P_BUY_LIM, 0, null, null);

		return pblim;
	}
	
    public int getDwarfRecipeLimit()
    {
        int recdlim = Config.DWARF_RECIPE_LIMIT;
        recdlim += (int)getStat().calcStat(Stats.REC_D_LIM, 0, null, null);
        return recdlim;
    }

    public int getCommonRecipeLimit()
    {
        int recclim = Config.COMMON_RECIPE_LIMIT;
        recclim += (int)getStat().calcStat(Stats.REC_C_LIM, 0, null, null);
        return recclim;
    }

    /**
     * @return Returns the mountNpcId.
     */
    public int getMountNpcId()
    {
        return _mountNpcId;
    }
    
    /**
     * @return Returns the mountLevel.
     */
    public int getMountLevel()
    {
    	return _mountLevel;
    }

    public void setMountObjectID(int newID)
	{
	    _mountObjectID = newID;
	}

	public int getMountObjectID()
	{
	    return _mountObjectID;
	}

    private L2ItemInstance _lure = null;
	public int _shortBuffTaskSkillId = 0;

    /**
     * Get the current skill in use or return null.<BR><BR>
     *
     */
    public SkillDat getCurrentSkill()
    {
        return _currentSkill;
    }


    /**
     * Create a new SkillDat object and set the player _currentSkill.<BR><BR>
     *
     */
    public void setCurrentSkill(L2Skill currentSkill, boolean ctrlPressed,
                                boolean shiftPressed)
    {
        if (currentSkill == null)
        {
            if (Config.DEBUG)
                _log.info("Setting current skill: NULL for " + getName() + ".");

            _currentSkill = null;
            return;
        }

        if (Config.DEBUG)
            _log.info("Setting current skill: " + currentSkill.getName() + " (ID: " + currentSkill.getId() + ") for " + getName() + ".");

        _currentSkill = new SkillDat(currentSkill, ctrlPressed, shiftPressed);
    }
    
    /**
     * Get the current pet skill in use or return null.<br><br>
     * 
     */
    public SkillDat getCurrentPetSkill()
    {
    	return _currentPetSkill;
    }

    /**
     * Create a new SkillDat object and set the player _currentPetSkill.<br><br>
     * 
     */
    public void setCurrentPetSkill(L2Skill currentSkill, boolean ctrlPressed, boolean shiftPressed)
    {
        if (currentSkill == null)
        {
            if (Config.DEBUG)
                _log.info("Setting current pet skill: NULL for " + getName() + ".");

            _currentPetSkill = null;
            return;
        }

        if (Config.DEBUG)
            _log.info("Setting current Pet skill: " + currentSkill.getName() + " (ID: " + currentSkill.getId() + ") for " + getName() + ".");

        _currentPetSkill = new SkillDat(currentSkill, ctrlPressed, shiftPressed);    	
    }


    public SkillDat getQueuedSkill()
    {
        return _queuedSkill;
    }


    /**
     * Create a new SkillDat object and queue it in the player _queuedSkill.<BR><BR>
     *
     */
    public void setQueuedSkill(L2Skill queuedSkill, boolean ctrlPressed, boolean shiftPressed)
    {
        if (queuedSkill == null)
        {
            if (Config.DEBUG)
                _log.info("Setting queued skill: NULL for " + getName() + ".");

            _queuedSkill = null;
            return;
        }

        if (Config.DEBUG)
            _log.info("Setting queued skill: " + queuedSkill.getName() + " (ID: " + queuedSkill.getId() + ") for " + getName() + ".");

        _queuedSkill = new SkillDat(queuedSkill, ctrlPressed, shiftPressed);
    }

    /**
     * returns punishment level of player
     * @return
     */
    public PunishLevel getPunishLevel()
    {
        return _punishLevel;
    }

    /**
     * @return True if player is jailed
     */
    public boolean isInJail()
    {
    	return _punishLevel == PunishLevel.JAIL;
    }
    
    /**
     * @return True if player is chat banned
     */
    public boolean isChatBanned()
    {
    	return _punishLevel == PunishLevel.CHAT;
    }
    
    public void setPunishLevel(int state)
    {
    	switch (state){
    		case 0 :
    		{
    			_punishLevel = PunishLevel.NONE;
    			break;
    		}
    		case 1 :
    		{
    			_punishLevel = PunishLevel.CHAT;
    			break;
    		}
    		case 2 :
    		{
    			_punishLevel = PunishLevel.JAIL;
    			break;
    		}
    		case 3 :
    		{
    			_punishLevel = PunishLevel.CHAR;
    			break;
    		}
    		case 4 :
    		{
    			_punishLevel = PunishLevel.ACC;
    			break;
    		}
    	}
    }

    /** 
     * Sets punish level for player based on delay
     * @param state
     * @param delayInMinutes
     * 		0 - Indefinite
     */
    public void setPunishLevel(PunishLevel state, int delayInMinutes)
    {
    	long delayInMilliseconds = delayInMinutes * 60000L;
    	switch (state)
    	{
    		case NONE: // Remove Punishments
	    	{
	    		switch (_punishLevel)
	    		{
	    			case CHAT:
		    		{
		    			_punishLevel = state;
		    			stopPunishTask(true);
		    			sendPacket(new EtcStatusUpdate(this));
			            sendMessage("Your Chat ban has been lifted");
			            break;
		    		}
	    			case JAIL:
		    		{
		    			_punishLevel = state;
		    			// Open a Html message to inform the player
		        		NpcHtmlMessage htmlMsg = new NpcHtmlMessage(0);
			            String jailInfos = HtmCache.getInstance().getHtm("data/html/jail_out.htm");
			            if (jailInfos != null)
			                htmlMsg.setHtml(jailInfos);
			            else
			                htmlMsg.setHtml("<html><body>You are free for now, respect server rules!</body></html>");
			            sendPacket(htmlMsg);
			            stopPunishTask(true);
			            teleToLocation(17836, 170178, -3507, true);  // Floran
			            break;
		    		}
	    		}
	    		break;
	    	}
    		case CHAT: // Chat Ban
	    	{
	    		// not allow player to escape jail using chat ban
	    		if (_punishLevel == PunishLevel.JAIL)
	    			break;
	    		_punishLevel = state;
	    		_punishTimer = 0;
	    		sendPacket(new EtcStatusUpdate(this));
	    		// Remove the task if any
	    		stopPunishTask(false);
	    		
	    		if (delayInMinutes > 0)
	    		{
	    			_punishTimer = delayInMilliseconds;
	    			
	    			// start the countdown
	    			_punishTask = ThreadPoolManager.getInstance().scheduleGeneral(new PunishTask(this), _punishTimer);
	                sendMessage("You are chat banned for "+delayInMinutes+" minutes.");
	    		}
	    		else
	    			sendMessage("You have been chat banned");
	    		break;
	    		
	    	}
    		case JAIL: // Jail Player
	    	{
	    		_punishLevel = state;
	    		_punishTimer = 0;
		        // Remove the task if any
		        stopPunishTask(false);
	
	            if (delayInMinutes > 0)
	            {
	                _punishTimer = delayInMilliseconds;
	
	                // start the countdown
	                _punishTask = ThreadPoolManager.getInstance().scheduleGeneral(new PunishTask(this), _punishTimer);
	                sendMessage("You are in jail for "+delayInMinutes+" minutes.");
	            }
	            
	            if (!TvTEvent.isInactive() && TvTEvent.isPlayerParticipant(getObjectId()))
	                TvTEvent.removeParticipant(getObjectId());
	            if (Olympiad.getInstance().isRegisteredInComp(this))
	                Olympiad.getInstance().removeDisconnectedCompetitor(this);
	
	            // Open a Html message to inform the player
	            NpcHtmlMessage htmlMsg = new NpcHtmlMessage(0);
	            String jailInfos = HtmCache.getInstance().getHtm("data/html/jail_in.htm");
	            if (jailInfos != null)
	                htmlMsg.setHtml(jailInfos);
	            else
	                htmlMsg.setHtml("<html><body>You have been put in jail by an admin.</body></html>");
	            sendPacket(htmlMsg);
	            setInstanceId(0);
	            setIsIn7sDungeon(false);
	
	            teleToLocation(-114356, -249645, -2984, false);  // Jail
	            break;
	        }
			case CHAR: // Ban Character
			{
				setAccessLevel(-100);
				logout();
				break;
			}
			case ACC: // Ban Account
			{
				setAccountAccesslevel(-100);
				logout();
				break;
			}
	    	default:
	    	{
	    		_punishLevel = state;
	    		break;
	    	}
    	}

        // store in database
        storeCharBase();
    }

    public long getPunishTimer()
    {
        return _punishTimer;
    }

    public void setPunishTimer(long time)
    {
        _punishTimer = time;
    }

    private void updatePunishState()
    {
    	if (getPunishLevel() != PunishLevel.NONE)
        {
            // If punish timer exists, restart punishtask.
            if (_punishTimer > 0)
            {
                _punishTask = ThreadPoolManager.getInstance().scheduleGeneral(new PunishTask(this), _punishTimer);
                sendMessage("You are still "+getPunishLevel().string()+" for "+Math.round(_punishTimer/60000)+" minutes.");
            }
            if (getPunishLevel() == PunishLevel.JAIL)
            {
            	// If player escaped, put him back in jail
                if (!isInsideZone(ZONE_JAIL))
                    teleToLocation(-114356,-249645,-2984, true);
            }
        }
    }

    public void stopPunishTask(boolean save)
    {
        if (_punishTask != null)
        {
            if (save)
            {
            	long delay = _punishTask.getDelay(TimeUnit.MILLISECONDS);
            	if (delay < 0)
            		delay = 0;
            	setPunishTimer(delay);
            }
            _punishTask.cancel(false);
            ThreadPoolManager.getInstance().removeGeneral((Runnable)_punishTask);
            _punishTask = null;
        }
    }

    private class PunishTask implements Runnable
    {
        L2PcInstance _player;
        // protected long _startedAt;

        protected PunishTask(L2PcInstance player)
        {
            _player = player;
            // _startedAt = System.currentTimeMillis();
        }

        public void run()
        {
            _player.setPunishLevel(PunishLevel.NONE, 0);
        }
    }
    public void startFameTask(long delay, int fameFixRate)
    {
    	if (getLevel() < 40 || getClassId().level() < 2)
    		return;
    	if (_fameTask == null)
    		_fameTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new FameTask(this, fameFixRate), delay, delay);
    }
    
    public void stopFameTask()
    {
        if (_fameTask != null)
        {
            _fameTask.cancel(false);
            ThreadPoolManager.getInstance().removeGeneral((Runnable)_fameTask);
            _fameTask = null;
        }
    }
    
    private class FameTask implements Runnable
    {
        private final L2PcInstance _player;
        private final int _value;

        protected FameTask(L2PcInstance player, int value)
        {
            _player = player;
            _value = value;
        }

        public void run()
        {
        	if (_player == null || (_player.isDead() && !Config.FAME_FOR_DEAD_PLAYERS))
        		return;
            _player.setFame(_player.getFame() + _value);
            SystemMessage sm = new SystemMessage(SystemMessageId.ACQUIRED_S1_REPUTATION_SCORE);
            sm.addNumber(_value);
            _player.sendPacket(sm);
            _player.sendPacket(new UserInfo(_player));
        }
    }

    public void startVitalityTask()
    {
    	if (Config.ENABLE_VITALITY && _vitalityTask == null)
    	{
    		_vitalityTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new VitalityTask(this), 1000, 60000);
    	}
    }

    public void stopVitalityTask()
    {
    	if (_vitalityTask != null)
    	{
    		_vitalityTask.cancel(false);
    		ThreadPoolManager.getInstance().removeGeneral((Runnable)_vitalityTask);
    		_vitalityTask = null;
    	}
    }

    private class VitalityTask implements Runnable
    {
    	private final L2PcInstance _player;

    	protected VitalityTask(L2PcInstance player)
    	{
    		_player = player;
    	}

    	public void run()
    	{
    		if (!_player.isInsideZone(L2Character.ZONE_PEACE))
    			return;

    		if (_player.getVitalityPoints() >= PcStat.MAX_VITALITY_POINTS)
    			return;

    		_player.updateVitalityPoints(Config.RATE_RECOVERY_VITALITY_PEACE_ZONE, false, false);
    		_player.sendPacket(new ExVitalityPointInfo(getVitalityPoints()));
    	}
    }

    /**
	 * @return
	 */
	public int getPowerGrade()
	{
		return _powerGrade;
	}

	/**
	 * @return
	 */
	public void setPowerGrade(int power)
	{
		_powerGrade = power;
	}

	public boolean isCursedWeaponEquipped()
	{
		return _cursedWeaponEquippedId != 0;
	}

	public void setCursedWeaponEquippedId(int value)
	{
		_cursedWeaponEquippedId = value;
	}

	public int getCursedWeaponEquippedId()
	{
		return _cursedWeaponEquippedId;
	}
	
	public boolean isCombatFlagEquipped()
    {
        return _combatFlagEquippedId ;
    }

    public void setCombatFlagEquipped(boolean value)
    {
        _combatFlagEquippedId = value;
    }

	public boolean getCharmOfCourage()
	{
		return _charmOfCourage;
	}

	public void setCharmOfCourage(boolean val) 
	{
		_charmOfCourage = val;
		sendPacket(new EtcStatusUpdate(this));
	}
	
	public final void setIsRidingStrider(boolean mode)
	{
		_isRidingStrider = mode;
	}
	
	/* not used anymore
	public final void setIsRidingFenrirWolf(boolean mode)
	{
		_isRidingFenrirWolf = mode;
	}
	public final void setIsRidingWFenrirWolf(boolean mode)
	{
		_isRidingWFenrirWolf = mode;
	}
	public final void setIsRidingGreatSnowWolf(boolean mode)
	{
		_isRidingGreatSnowWolf = mode;
	}
	public final boolean isRidingFenrirWolf()
	{ 
		return _isRidingFenrirWolf;
	}
	public final boolean isRidingWFenrirWolf()
	{ 
		return _isRidingWFenrirWolf;
	}
	public final boolean isRidingGreatSnowWolf()
	{ 
		return _isRidingGreatSnowWolf;
	}*/
	
	public final boolean isRidingStrider()
	{ 
		return _isRidingStrider;
	}

    /**
     * Returns the Number of Souls this L2PcInstance got.
     * @return
     */
    public int getSouls()
    {
        return _souls;
    }

    /**
     * Absorbs a Soul from a Npc.
     * @param skill
     * @param target
     */
    public void absorbSoul(L2Skill skill, L2Npc npc)
    {
        if (_souls >= skill.getNumSouls())
        {
            SystemMessage sm = new SystemMessage(SystemMessageId.SOUL_CANNOT_BE_INCREASED_ANYMORE);
            sendPacket(sm);
            return;
        }

        increaseSouls(1);

        if (npc != null)
        	broadcastPacket(new ExSpawnEmitter(this, npc), 500);
    }
    
    /**
     * Increase Souls
     * @param count
     */
    public void increaseSouls(int count)
    {
        if (count < 0 || count > 45)
            return;

        _souls += count;

        if (getSouls() > 45)
            _souls = 45;

        SystemMessage sm = new SystemMessage(SystemMessageId.YOUR_SOUL_HAS_INCREASED_BY_S1_SO_IT_IS_NOW_AT_S2);
        sm.addNumber(count);
        sm.addNumber(_souls);
        sendPacket(sm);

        restartSoulTask();

        sendPacket(new EtcStatusUpdate(this));
    }

    /**
     * Decreases existing Souls.
     * @param count
     */
    public boolean decreaseSouls(int count, L2Skill skill)
    {
        if (getSouls() <= 0 && skill.getSoulConsumeCount() > 0)
        {
        	sendPacket(new SystemMessage(SystemMessageId.THERE_IS_NOT_ENOUGH_SOUL));
            return false;
        }

        _souls -= count;

        if (getSouls() < 0)
            _souls = 0;

        if (getSouls() == 0)
            stopSoulTask();
        else
            restartSoulTask();

        sendPacket(new EtcStatusUpdate(this));
        return true;
    }

    /**
     * Clear out all Souls from this L2PcInstance
     */
    public void clearSouls()
    {
        _souls = 0;
        stopSoulTask();
        sendPacket(new EtcStatusUpdate(this));
    }

    /**
     * Starts/Restarts the SoulTask to Clear Souls after 10 Mins.
     */
    private void restartSoulTask()
    {
        if (_soulTask != null)
        {
            _soulTask.cancel(false);
            _soulTask = null;
        }
        _soulTask = ThreadPoolManager.getInstance().scheduleGeneral(new SoulTask(this), 600000);
    }

    /**
     * Stops the Clearing Task.
     */
    public void stopSoulTask()
    {
        if (_soulTask != null)
        {
            _soulTask.cancel(false);
            ThreadPoolManager.getInstance().removeGeneral((Runnable)_soulTask);
            _soulTask = null;
        }
    }

    private class SoulTask implements Runnable
    {
        L2PcInstance _player;
        
        protected SoulTask(L2PcInstance player)
        {
            _player = player;
        }
        
        public void run()
        {
            _player.clearSouls();
        }
    }
    
    /**
     *
     * @param magicId
     * @param level
     * @param time
     */
    public void shortBuffStatusUpdate(int magicId, int level, int time)
	{
		if (_shortBuffTask != null)
		{
			_shortBuffTask.cancel(false);
			_shortBuffTask = null;
		}
		_shortBuffTask = ThreadPoolManager.getInstance().scheduleGeneral(new ShortBuffTask(this), time*1000);
		setShortBuffTaskSkillId(magicId);
		
		sendPacket(new ShortBuffStatusUpdate(magicId, level, time));
	}
    
    public void setShortBuffTaskSkillId(int id)
    {
    	_shortBuffTaskSkillId = id;
    }
    public int getDeathPenaltyBuffLevel()
    {
    	  return _deathPenaltyBuffLevel;
    }

    public void setDeathPenaltyBuffLevel(int level)
    {
    	 _deathPenaltyBuffLevel = level;
    }

    public void calculateDeathPenaltyBuffLevel(L2Character killer)
    {
    	if((getKarma() > 0 || Rnd.get(1,100) <= Config.DEATH_PENALTY_CHANCE)
    			&& !(killer instanceof L2PcInstance) && !(this.isGM())
    			&& !(this.getCharmOfLuck() && killer.isRaid())
    			&& !isPhoenixBlessed()
    			&& !(TvTEvent.isStarted() && TvTEvent.isPlayerParticipant(getObjectId()))
    			&& !(this.isInsideZone(L2Character.ZONE_PVP)||this.isInsideZone(L2Character.ZONE_SIEGE))) 
    		
    		increaseDeathPenaltyBuffLevel();
	}

    public void increaseDeathPenaltyBuffLevel()
    {
    	if(getDeathPenaltyBuffLevel() >= 15) //maximum level reached
    		return;
    	
    	if(getDeathPenaltyBuffLevel() != 0)
    	{
    		L2Skill skill = SkillTable.getInstance().getInfo(5076, getDeathPenaltyBuffLevel());

    		if(skill != null)
    			removeSkill(skill, true);
    	}

    	_deathPenaltyBuffLevel++;

    	addSkill(SkillTable.getInstance().getInfo(5076, getDeathPenaltyBuffLevel()), false);
    	sendPacket(new EtcStatusUpdate(this));
    	SystemMessage sm = new SystemMessage(SystemMessageId.DEATH_PENALTY_LEVEL_S1_ADDED);
    	sm.addNumber(getDeathPenaltyBuffLevel());
    	sendPacket(sm);
    }

    public void reduceDeathPenaltyBuffLevel()
    {
    	if(getDeathPenaltyBuffLevel() <= 0)
    		return;

    	L2Skill skill = SkillTable.getInstance().getInfo(5076, getDeathPenaltyBuffLevel());

    	if(skill != null)
    		removeSkill(skill, true);

    	_deathPenaltyBuffLevel--;

    	if(getDeathPenaltyBuffLevel() > 0)
    	{
    		addSkill(SkillTable.getInstance().getInfo(5076, getDeathPenaltyBuffLevel()), false);
    		sendPacket(new EtcStatusUpdate(this));
    		SystemMessage sm = new SystemMessage(SystemMessageId.DEATH_PENALTY_LEVEL_S1_ADDED);
    		sm.addNumber(getDeathPenaltyBuffLevel());
    		sendPacket(sm);
    	}
    	else
    	{
    		sendPacket(new EtcStatusUpdate(this));
    		sendPacket(new SystemMessage(SystemMessageId.DEATH_PENALTY_LIFTED));
    	}
    }

    public void restoreDeathPenaltyBuffLevel()
    {
    	L2Skill skill = SkillTable.getInstance().getInfo(5076, getDeathPenaltyBuffLevel());

    	if(skill != null)
    		removeSkill(skill, true);

    	if(getDeathPenaltyBuffLevel() > 0)
    	{
    		addSkill(SkillTable.getInstance().getInfo(5076, getDeathPenaltyBuffLevel()), false);
    	}
    }

	private FastMap<Integer, TimeStamp> _reuseTimeStamps = new FastMap<Integer, TimeStamp>().setShared(true);
	private boolean _canFeed;
	private int _afroId = 0;
	private boolean _isInSiege;

    public Collection<TimeStamp> getReuseTimeStamps()
    {
        return _reuseTimeStamps.values();
    }
    
    public FastMap<Integer, TimeStamp> getReuseTimeStamp()
    {
    	return _reuseTimeStamps;
    }
    
	/**
	 * Simple class containing all neccessary information to maintain
	 * valid timestamps and reuse for skills upon relog. Filter this
	 * carefully as it becomes redundant to store reuse for small delays.
	 * @author  Yesod
	 */
	public static class TimeStamp
	{
		private int skill;
		private long reuse;
		private long stamp;

		public TimeStamp(int _skill, long _reuse)
		{
			skill = _skill;
			reuse = _reuse;
			stamp = System.currentTimeMillis()+ reuse;
		}

		public TimeStamp(int _skill, long _reuse, long _systime)
		{
			skill = _skill;
			reuse = _reuse;
			stamp = _systime;
		}
		
		public long getStamp()
		{
				return stamp;
		}

		public int getSkill()
        {
            return skill;
        }
        
        public long getReuse()
        {
            return reuse;
        }
        
        public long getRemaining()
        {
            return Math.max(stamp - System.currentTimeMillis(), 0);
        }

		/* Check if the reuse delay has passed and
		 * if it has not then update the stored reuse time
		 * according to what is currently remaining on
		 * the delay. */
		public boolean hasNotPassed()
		{
            if (System.currentTimeMillis() < stamp)
            {
                return true;
            }
			return false;
		}
	}

	/**
	 * Index according to skill id the current
	 * timestamp of use.
	 * @param skillid
	 * @param reuse delay
	 */
	@Override
	public void addTimeStamp(int s, int r)
	{
		_reuseTimeStamps.put(s, new TimeStamp(s, r));
	}

	/**
	 * Index according to skill this TimeStamp
	 * instance for restoration purposes only.
	 * @param TimeStamp
	 */
	public void addTimeStamp(TimeStamp ts)
	{
		_reuseTimeStamps.put(ts.getSkill(), ts);
	}

	/**
	 * Index according to skill id the current
	 * timestamp of use.
	 * @param skillid
	 */
	@Override
	public void removeTimeStamp(int s)
	{
		_reuseTimeStamps.remove(s);
	}
	
	@Override
	public L2PcInstance getActingPlayer()
	{
		return this;
	}

	@Override
	public final void sendDamageMessage(L2Character target, int damage, boolean mcrit, boolean pcrit, boolean miss)
    {
		// Check if hit is missed
		if (miss)
		{
			sendPacket(new SystemMessage(SystemMessageId.C1_ATTACK_WENT_ASTRAY).addString(getName()));
			return;
		}

		// Check if hit is critical
		if (pcrit)
        {
			sendPacket(new SystemMessage(SystemMessageId.C1_HAD_CRITICAL_HIT).addPcName(this));
            if (target instanceof L2Npc && getSkillLevel(467) > 0)
            {
                L2Skill skill = SkillTable.getInstance().getInfo(467,getSkillLevel(467));
                if (Rnd.get(100) < skill.getCritChance())
                {
                    absorbSoul(skill,((L2Npc)target));
                }
            }
        }
        if (mcrit)
            sendPacket(new SystemMessage(SystemMessageId.CRITICAL_HIT_MAGIC));

        if (isInOlympiadMode() &&
        		target instanceof L2PcInstance &&
        		((L2PcInstance)target).isInOlympiadMode() &&
        		((L2PcInstance)target).getOlympiadGameId() == getOlympiadGameId())
        {
        	Olympiad.getInstance().notifyCompetitorDamage(this, damage, getOlympiadGameId());
        }

		final SystemMessage sm;
		
		if (target.isInvul() && !(target instanceof L2NpcInstance))
		{
			sm = new SystemMessage(SystemMessageId.ATTACK_WAS_BLOCKED);
		}
		else if (target instanceof L2DoorInstance || target instanceof L2ControlTowerInstance)
		{
			sm = new SystemMessage(SystemMessageId.YOU_DID_S1_DMG);
			sm.addNumber(damage);
		}
		else
		{
			sm = new SystemMessage(SystemMessageId.C1_GAVE_C2_DAMAGE_OF_S3);
			sm.addPcName(this);
			sm.addCharName(target);
			sm.addNumber(damage);
		}
		
		sendPacket(sm);
	}


    /**
     * 
     * @param npcId
     */
    public void setAgathionId(int npcId)
    {
    	_agathionId = npcId;
    }
    
    /**
     * 
     * @return
     */
    public int getAgathionId()
    {
	    return _agathionId;
    }

    public int getVitalityPoints()
    {
    	return getStat().getVitalityPoints();
    }
	
	/**
	 * @return Vitality Level
	 */
	public int getVitalityLevel()
	{
		return getStat().getVitalityLevel();
	}

    public void setVitalityPoints(int points, boolean quiet)
    {
    	getStat().setVitalityPoints(points, quiet);
    }

    public synchronized void updateVitalityPoints(float points, boolean useRates, boolean quiet)
    {
    	getStat().updateVitalityPoints(points, useRates, quiet);
    }

    /*
     * Function for skill summon friend or Gate Chant.
     */
    /** Request Teleport **/
    public boolean teleportRequest(L2PcInstance requester, L2Skill skill)
    {
    	if (_summonRequest.getTarget() != null && requester != null)
    		return false;
    	_summonRequest.setTarget(requester, skill);
    	return true;
    }

    /** Action teleport **/
    public void teleportAnswer(int answer, int requesterId)
    {
    	if (_summonRequest.getTarget() == null)
    		return;
    	if (answer == 1 && _summonRequest.getTarget().getCharId() == requesterId)
    	{
    		teleToTarget(this, _summonRequest.getTarget(), _summonRequest.getSkill());
    	}
    	_summonRequest.setTarget(null, null);
    }
    
    public static void teleToTarget(L2PcInstance targetChar, L2PcInstance summonerChar, L2Skill summonSkill)
	{
		if (targetChar == null || summonerChar == null || summonSkill == null)
			return;

		if (!checkSummonerStatus(summonerChar))
			return;
		if (!checkSummonTargetStatus(targetChar, summonerChar))
			return;

		int itemConsumeId = summonSkill.getTargetConsumeId();
		int itemConsumeCount = summonSkill.getTargetConsume();
		if (itemConsumeId != 0 && itemConsumeCount != 0)
		{
			//Delete by rocknow
			if (targetChar.getInventory().getInventoryItemCount(itemConsumeId, 0) < itemConsumeCount)
			{
				SystemMessage sm = new SystemMessage(SystemMessageId.S1_REQUIRED_FOR_SUMMONING);
				sm.addItemName(summonSkill.getTargetConsumeId());
				targetChar.sendPacket(sm);
				return;
			}
			targetChar.getInventory().destroyItemByItemId("Consume", itemConsumeId, itemConsumeCount, summonerChar, targetChar);
			SystemMessage sm = new SystemMessage(SystemMessageId.S1_DISAPPEARED);
			sm.addItemName(summonSkill.getTargetConsumeId());
			targetChar.sendPacket(sm);
		}
		targetChar.teleToLocation(summonerChar.getX(), summonerChar.getY(), summonerChar.getZ(), true);
	}

	public static boolean checkSummonerStatus(L2PcInstance summonerChar)
	{
		if (summonerChar == null)
			return false;

		if (summonerChar.isInOlympiadMode())
		{
			summonerChar.sendPacket(new SystemMessage(SystemMessageId.THIS_ITEM_IS_NOT_AVAILABLE_FOR_THE_OLYMPIAD_EVENT));
			return false;
		}

		if (summonerChar.inObserverMode())
		{
			return false;
		}

		if (!TvTEvent.onEscapeUse(summonerChar.getObjectId()))
		{
			summonerChar.sendPacket(new SystemMessage(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING));
			return false;			
		}
		
		if (summonerChar.isInsideZone(L2Character.ZONE_NOSUMMONFRIEND) || summonerChar.isFlyingMounted())
		{
			summonerChar.sendPacket(new SystemMessage(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING));
			return false;
		}
		return true;
	}

	public static boolean checkSummonTargetStatus(L2Object target, L2PcInstance summonerChar)
	{
		if (target == null || !(target instanceof L2PcInstance))
			return false;
		
		L2PcInstance targetChar = (L2PcInstance) target;
		
		if (targetChar.isAlikeDead())
		{
			SystemMessage sm = new SystemMessage(SystemMessageId.C1_IS_DEAD_AT_THE_MOMENT_AND_CANNOT_BE_SUMMONED);
			sm.addPcName(targetChar);
			summonerChar.sendPacket(sm);
			return false;
		}

		if (targetChar.isInStoreMode())
		{
			SystemMessage sm = new SystemMessage(SystemMessageId.C1_CURRENTLY_TRADING_OR_OPERATING_PRIVATE_STORE_AND_CANNOT_BE_SUMMONED);
			sm.addPcName(targetChar);
			summonerChar.sendPacket(sm);
			return false;
		}

		if (targetChar.isRooted() || targetChar.isInCombat())
		{
			SystemMessage sm = new SystemMessage(SystemMessageId.C1_IS_ENGAGED_IN_COMBAT_AND_CANNOT_BE_SUMMONED);
			sm.addPcName(targetChar);
			summonerChar.sendPacket(sm);
			return false;
		}

		if (targetChar.isInOlympiadMode())
		{
			summonerChar.sendPacket(new SystemMessage(SystemMessageId.YOU_CANNOT_SUMMON_PLAYERS_WHO_ARE_IN_OLYMPIAD));
			return false;
		}

		if (targetChar.isFestivalParticipant() || targetChar.isFlyingMounted())
		{
			summonerChar.sendPacket(new SystemMessage(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING));
			return false;
		}

		if (targetChar.inObserverMode())
		{
			summonerChar.sendPacket(new SystemMessage(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING));
			return false;
		}

		if (!TvTEvent.onEscapeUse(targetChar.getObjectId()))
		{
			summonerChar.sendPacket(new SystemMessage(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING));
			return false;			
		}

		if (targetChar.isInsideZone(L2Character.ZONE_NOSUMMONFRIEND))
		{
			SystemMessage sm = new SystemMessage(SystemMessageId.C1_IN_SUMMON_BLOCKING_AREA);
			sm.addString(targetChar.getName());
			summonerChar.sendPacket(sm);
			return false;
		}
		
		if (summonerChar.getInstanceId() > 0)
		{
			Instance summonerInstance = InstanceManager.getInstance().getInstance(summonerChar.getInstanceId());
			if (!Config.ALLOW_SUMMON_TO_INSTANCE || !summonerInstance.isSummonAllowed())
			{
				summonerChar.sendPacket(new SystemMessage(SystemMessageId.YOU_MAY_NOT_SUMMON_FROM_YOUR_CURRENT_LOCATION));
				return false;
			}
		}

		// on retail character can enter 7s dungeon with summon friend,
		// but will be teleported away by mobs
		// because currently this is not working in L2J we do not allowing summoning
		if (summonerChar.isIn7sDungeon())
		{
			int targetCabal = SevenSigns.getInstance().getPlayerCabal(targetChar);
			if (SevenSigns.getInstance().isSealValidationPeriod())
			{
				if (targetCabal != SevenSigns.getInstance().getCabalHighestScore())
				{
					summonerChar.sendPacket(new SystemMessage(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING));
					return false;					
				}
			}
			else
			{
				if (targetCabal == SevenSigns.CABAL_NULL)
				{
					summonerChar.sendPacket(new SystemMessage(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING));
					return false;
				}
			}
		}

		return true;
	}

	public void gatesRequest(L2DoorInstance door)
	{
		_gatesRequest.setTarget(door);
	}

	public void gatesAnswer(int answer, int type)
	{
		if (_gatesRequest.getDoor() == null)
			return;

		if (answer == 1 && getTarget() == _gatesRequest.getDoor() && type == 1)
			_gatesRequest.getDoor().openMe();
		else if (answer == 1 && getTarget() == _gatesRequest.getDoor() && type == 0)
			_gatesRequest.getDoor().closeMe();

		_gatesRequest.setTarget(null);
	}

	@Override
	public void setIsCastingNow(boolean value)
	{
		if (value == false)
			_currentSkill = null;

		super.setIsCastingNow(value);
	}

	public void checkItemRestriction()
	{
		for (int i = 0; i < Inventory.PAPERDOLL_TOTALSLOTS; i++)
		{
			L2ItemInstance equippedItem = getInventory().getPaperdollItem(i);
			if (equippedItem != null && !equippedItem.getItem().checkCondition(this, this, false))
			{
				getInventory().unEquipItemInSlotAndRecord(i);

				InventoryUpdate iu = new InventoryUpdate();
				iu.addModifiedItem(equippedItem);
				sendPacket(iu);

				if (equippedItem.isWear())
					continue;

				SystemMessage sm = null;
				if (equippedItem.getItem().getBodyPart() == L2Item.SLOT_BACK)
				{
					sendPacket(new SystemMessage(SystemMessageId.CLOAK_REMOVED_BECAUSE_ARMOR_SET_REMOVED));
					return;
				}

				if (equippedItem.getEnchantLevel() > 0)
				{
					sm = new SystemMessage(SystemMessageId.EQUIPMENT_S1_S2_REMOVED);
					sm.addNumber(equippedItem.getEnchantLevel());
					sm.addItemName(equippedItem);
				}
				else
				{
					sm = new SystemMessage(SystemMessageId.S1_DISARMED);
					sm.addItemName(equippedItem);
				}
				sendPacket(sm);
			}
		}
	}

    public void setTransformAllowedSkills(int[] ids)
    {
    	_transformAllowedSkills = ids;
    }
    
    public boolean containsAllowedTransformSkill(int id)
    {
    	for (int i = 0; i < _transformAllowedSkills.length; i++)
    	{
    		if (_transformAllowedSkills[i] == id)
    		{
    			return true;
    		}
    	}
    	return false;
    }
    
    /** Section for mounted pets */
    class FeedTask implements Runnable
    {
    	public void run()
    	{
    		try
    		{
    			if (!isMounted())
    			{
    				stopFeed();
    				return;
    			}
    			
    			if (getCurrentFeed() > getFeedConsume())
    			{
    				// eat
    				setCurrentFeed(getCurrentFeed()-getFeedConsume());
    			}
    			else
    			{
    				// go back to pet control item, or simply said, unsummon it
    				setCurrentFeed(0);
    				stopFeed();
    				dismount();
    				sendPacket(new SystemMessage(SystemMessageId.OUT_OF_FEED_MOUNT_CANCELED));
    			}
    			
    			int[] foodIds = PetDataTable.getFoodItemId(getMountNpcId());
    			if (foodIds[0] == 0) return;
    			L2ItemInstance food = null;
    			food = getInventory().getItemByItemId(foodIds[0]);
    			
    			// use better strider food if exists
    			if (PetDataTable.isStrider(getMountNpcId()))
    			{
    				if (getInventory().getItemByItemId(foodIds[1]) != null)
    					food = getInventory().getItemByItemId(foodIds[1]);
    			}
    			if (food != null && isHungry())
    			{
    				IItemHandler handler = ItemHandler.getInstance().getItemHandler(food.getEtcItem());
    				if (handler != null)
    				{
    					handler.useItem(L2PcInstance.this, food);
    					SystemMessage sm = new SystemMessage(SystemMessageId.PET_TOOK_S1_BECAUSE_HE_WAS_HUNGRY);
    					sm.addItemName(food.getItemId());
    					sendPacket(sm);
    				}
    			}
    		}
    		catch (Exception e)
    		{
    			_log.log(Level.SEVERE, "Mounted Pet [NpcId: "+getMountNpcId()+"] a feed task error has occurred", e);
    		}
    	}
    }
    	
    protected synchronized void startFeed(int npcId)
    {
    	_canFeed = npcId > 0;
    	if (!isMounted())
    		return;
    	if (getPet() != null)
    	{
    		setCurrentFeed(((L2PetInstance) getPet()).getCurrentFed());
    		_controlItemId = getPet().getControlItemId();
    		sendPacket(new SetupGauge(3, getCurrentFeed()*10000/getFeedConsume(), getMaxFeed()*10000/getFeedConsume()));
    		if (!isDead())
    		{
    			_mountFeedTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new FeedTask(), 10000, 10000);
    		}
    	}
    	else if (_canFeed)
    	{
    		setCurrentFeed(getMaxFeed());
    		SetupGauge sg = new SetupGauge(3, getCurrentFeed()*10000/getFeedConsume(), getMaxFeed()*10000/getFeedConsume());
    		sendPacket(sg);
    		if (!isDead())
    		{
    			_mountFeedTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new FeedTask(), 10000, 10000);
    		}
    	}
    }
    
    protected synchronized void stopFeed()
    {
    	if (_mountFeedTask != null)
    	{
    		_mountFeedTask.cancel(false);
    		ThreadPoolManager.getInstance().removeGeneral((Runnable)_mountFeedTask);
    		_mountFeedTask = null;
    		if (Config.DEBUG) _log.fine("Pet [#"+_mountNpcId+"] feed task stop");
    	}
    }
    
    protected final void clearPetData()
    {
    	_data = null;
    }
    
    protected final L2PetData getPetData(int npcId)
    {
    	if (_data == null && getPet() != null)
    		_data = PetDataTable.getInstance().getPetData(getPet().getNpcId(), getPet().getLevel());
    	else if (_data == null && npcId > 0)
    	{
    		_data = PetDataTable.getInstance().getPetData(npcId, getLevel());
    	}
    	
    	return _data;
    }
    
    public int getCurrentFeed() { return _curFeed; }
    
    protected int getFeedConsume()
    {
    	// if pet is attacking
    	if (isAttackingNow())
    		return getPetData(_mountNpcId).getPetFeedBattle();
    	else
    		return getPetData(_mountNpcId).getPetFeedNormal();
    }
    
    public void setCurrentFeed(int num)
    {
    	_curFeed = num > getMaxFeed() ? getMaxFeed() : num;
    	SetupGauge sg = new SetupGauge(3, getCurrentFeed()*10000/getFeedConsume(), getMaxFeed()*10000/getFeedConsume());
    	sendPacket(sg);
    }
    
    protected int getMaxFeed()
    {
    	return getPetData(_mountNpcId).getPetMaxFeed();
    }
    
    protected boolean isHungry()
    {
    	return _canFeed ? (getCurrentFeed() < (0.55 * getPetData(getMountNpcId()).getPetMaxFeed())):false;
    }
    
	public class dismount implements Runnable
	{
		public void run()
		{
			try
			{
				L2PcInstance.this.dismount();
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}
	}

	public void enteredNoLanding(int delay)
	{
		_dismountTask = ThreadPoolManager.getInstance().scheduleGeneral(new L2PcInstance.dismount(), delay * 1000);
	}

	public void exitedNoLanding()
	{
		if (_dismountTask != null)
		{
			_dismountTask.cancel(true);
			_dismountTask = null;
		}
	}
    
    public void storePetFood(int petId)
    {
    	if (_controlItemId != 0 && petId != 0)
    	{
    		String req;
    		req = "UPDATE pets SET fed=? WHERE item_obj_id = ?";
    		Connection con = null;
    		try
    		{
    			con = L2DatabaseFactory.getInstance().getConnection();
    			PreparedStatement statement = con.prepareStatement(req);
    			statement.setInt(1, getCurrentFeed());
    			statement.setInt(2, _controlItemId);
    			statement.executeUpdate();
    			statement.close();
    			_controlItemId = 0;
    		}
    		catch (Exception e)
    		{
    			_log.log(Level.SEVERE, "Failed to store Pet [NpcId: "+petId+"] data", e);
    		}
    		finally
    		{
    			try
    			{
    				con.close();
    			}
    			catch (Exception e)
    			{
    			}
    		}
    	}
    }
    /** End of section for mounted pets */

    @Override
    public int getAttackElementValue(byte attribute)
    {
    	int value = super.getAttackElementValue(attribute);

    	// 20% if summon exist
    	if (getPet() != null && getClassId().isSummoner() && (getPet() instanceof L2SummonInstance))
    		return value / 5;

    	return value;
    }

	/**
     * @return afro haircut id
     */
    public int getAfroHaircutId()
    {
	    return _afroId ;
    }
    
    public void setAfroHaircutId(int id)
    {
	    _afroId = id;
	    broadcastUserInfo();
    }

    public void setIsInSiege(boolean b)
    {
    	_isInSiege = b;
    }
    
    public boolean isInSiege()
    {
    	return _isInSiege;
    }
    
    public FloodProtectors getFloodProtectors()
    {
    	return _floodProtectors;
    }

    public boolean isFlyingMounted()
    {
	    return _isFlyingMounted;
    }
    
    public void setIsFlyingMounted(boolean val)
    {
    	_isFlyingMounted = val;
    	setIsFlying(val);
    }
    
    /**
     * Returns the Number of Charges this L2PcInstance got.
     * @return
     */
    public int getCharges()
    {
    	return _charges.get();
    }
    
    public synchronized void increaseCharges(int count, int max)
    {
    	if (_charges.get() >= max)
    	{
    		sendPacket(new SystemMessage(SystemMessageId.FORCE_MAXLEVEL_REACHED));
    		return;
    	}
    	else
    	{
    		// if no charges - start clear task
    		if (_charges.get() == 0)
    			restartChargeTask();
    			}
    	
    	if (_charges.addAndGet(count) >= max)
    	{
    		_charges.set(max);
    		sendPacket(new SystemMessage(SystemMessageId.FORCE_MAXLEVEL_REACHED));
    	}
    	else
    	{
    		SystemMessage sm = new SystemMessage(SystemMessageId.FORCE_INCREASED_TO_S1);
    		sm.addNumber(_charges.get());
    		sendPacket(sm);
    	}
    	
    	sendPacket(new EtcStatusUpdate(this));
    }
    
    public synchronized boolean decreaseCharges(int count)
    {
    	if (_charges.get() < count)
    		return false;
    	
    	if (_charges.addAndGet(-count) == 0)
    		stopChargeTask();
    	
    	sendPacket(new EtcStatusUpdate(this));
    	return true;
    }
    
    public void clearCharges()
    {
    	_charges.set(0);
    	sendPacket(new EtcStatusUpdate(this));
    }
    
    /**
     * Starts/Restarts the ChargeTask to Clear Charges after 10 Mins.
     */
    private void restartChargeTask()
    {
    	if (_chargeTask != null)
    	{
    		_chargeTask.cancel(false);
    		_chargeTask = null;
    	}
    	_chargeTask = ThreadPoolManager.getInstance().scheduleGeneral(new ChargeTask(this), 600000);
    }
    
    /**
     * Stops the Charges Clearing Task.
     */
    public void stopChargeTask()
    {
    	if (_chargeTask != null)
    	{
    		_chargeTask.cancel(false);
    		ThreadPoolManager.getInstance().removeGeneral((Runnable)_chargeTask);
    		_chargeTask = null;
    	}
    }
    
    private class ChargeTask implements Runnable
    {
    	L2PcInstance _player;
    	
    	protected ChargeTask(L2PcInstance player)
    	{
    		_player = player;
    	}
    	
    	public void run()
    	{
    		_player.clearCharges();
    	}
    }
    
    public class TeleportBookmark
    {
    	public int _id,_x,_y,_z,_icon;
    	public String _name,_tag;
    	
    	TeleportBookmark(int id, int x, int y, int z, int icon, String tag, String name)
    	{
    		_id = id;
    		_x = x;
    		_y = y;
    		_z = z;
    		_icon = icon;
    		_name = name;
    		_tag = tag;
    	}
    	
    }
    
    public void teleportBookmarkModify(int Id, int icon, String tag, String name)
    {
    	int count = 0;
    	int size = tpbookmark.size();
    	while(size > count)
    	{
    		if(tpbookmark.get(count)._id==Id)
    		{
    			tpbookmark.get(count)._icon = icon;
    			tpbookmark.get(count)._tag = tag;
    			tpbookmark.get(count)._name = name;
    			
    			Connection con = null;

    			try
    			{

    				con = L2DatabaseFactory.getInstance().getConnection();
    				PreparedStatement statement = con.prepareStatement(UPDATE_TP_BOOKMARK);
    				
    				statement.setInt(1, icon);
    				statement.setString(2, tag);
    				statement.setString(3, name);
    				statement.setInt(4, getObjectId());
    				statement.setInt(5, Id);

    				statement.execute();
    				statement.close();
    			}
    			catch (Exception e) { _log.warning("Could not update character teleport bookmark data: "+ e); }
    			finally { try { con.close(); } catch (Exception e) {} }
    			
    		}
    		count++;
    	}
    	
    	sendPacket(new ExGetBookMarkInfoPacket(this));
    	
    }
    
    public void teleportBookmarkDelete(int Id)
    {
		Connection con = null;

		try
		{
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement(DELETE_TP_BOOKMARK);
			
			statement.setInt(1, getObjectId());
			statement.setInt(2, Id);

			statement.execute();
			statement.close();
		}
		catch (Exception e) { _log.warning("Could not delete character teleport bookmark data: "+ e); }
		finally { try { con.close(); } catch (Exception e) {} }
		
		int count = 0;
		int size = tpbookmark.size();
		
    	while(size > count)
    	{
    		if(tpbookmark.get(count)._id == Id)
    		{
    			tpbookmark.remove(count);
    			break;
    		}
    		count++;
    	}
    	
		sendPacket(new ExGetBookMarkInfoPacket(this));
    }
    
    public void teleportBookmarkGo(int Id)
    {
    	if(!teleportBookmarkCondition(0) || this == null)
    		return;
    	if (getInventory().getInventoryItemCount(13016, 0) == 0)
    	{
    		sendPacket(new SystemMessage(2359));
    		return;
    	}
    	SystemMessage sm = new SystemMessage(SystemMessageId.S1_DISAPPEARED);
    	sm.addItemName(13016);
    	sendPacket(sm);
    	int count = 0;
    	int size = tpbookmark.size();
    	while(size > count)
    	{
    		if(tpbookmark.get(count)._id == Id)
    		{
    			destroyItem("Consume", getInventory().getItemByItemId(13016).getObjectId(), 1, null, false);
    			this.teleToLocation(tpbookmark.get(count)._x, tpbookmark.get(count)._y, tpbookmark.get(count)._z);
    			break;
    		}
    		count++;
    	}
    	sendPacket(new ExGetBookMarkInfoPacket(this));
    }
    
    public boolean teleportBookmarkCondition(int type)
    {
    	if(this.isInCombat())
    	{
    		sendPacket(new SystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_DURING_A_BATTLE));
    		return false;
    	}
    	else if (this.isInSiege())
    	{
    		sendPacket(new SystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_WHILE_PARTICIPATING));
    		return false;
    	}
    	else if (this.isInDuel())
    	{
    		sendPacket(new SystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_DURING_A_DUEL));
    		return false;
    	}
    	else if (this.isFlying())
    	{
    		sendPacket(new SystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_WHILE_FLYING));
    		return false;
    	}
    	else if (this.isInOlympiadMode())
    	{
    		sendPacket(new SystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_WHILE_PARTICIPATING_IN_AN_OLYMPIAD_MATCH));
    		return false;
    	}
    	else if (this.isParalyzed())
    	{
    		sendPacket(new SystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_WHILE_YOU_ARE_PARALYZED));
    		return false;
    	}
    	else if (this.isDead())
    	{
    		sendPacket(new SystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_WHILE_YOU_ARE_DEAD));
    		return false;
    	}
    	else if (isIn7sDungeon() && type == 1)
    	{
    		sendPacket(new SystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_TO_REACH_THIS_AREA));
    		return false;
    	}
    	else if (this.isInBoat() || this.isInAirShip() || this.isInJail() || this.isInsideZone(ZONE_NOSUMMONFRIEND))
    	{
    		if(type == 0)
    			sendPacket(new SystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_IN_THIS_AREA));
    		else if (type == 1)
    			sendPacket(new SystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_TO_REACH_THIS_AREA));
    		return false;
    	}
    	else if (this.isInWater())
    	{
    		sendPacket(new SystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_UNDERWATER));
    		return false;
    	}
    	else if (type == 1 && (this.isInsideZone(ZONE_SIEGE) || this.isInsideZone(ZONE_CLANHALL) || this.isInsideZone(ZONE_JAIL) || this.isInsideZone(ZONE_CASTLE) || this.isInsideZone(ZONE_NOSUMMONFRIEND) || this.isInsideZone(ZONE_FORT)))
    	{
    		sendPacket(new SystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_TO_REACH_THIS_AREA));
    		return false;
    	}
    	/* TODO: Instant Zone still not implement
    	else if (this.isInsideZone(ZONE_INSTANT))
    	{
    		sendPacket(new SystemMessage(2357));
    		return;
    	}
    	*/
    	else 
    		return true;
    }
    
    public void TeleportBookmarkAdd(int x,int y,int z,int icon, String tag, String name)
    {
    	if(this == null)
    		return;
    	
    	if(!teleportBookmarkCondition(1))
    		return;
    	
    	if(tpbookmark.size() >= _bookmarkslot)
    	{
    		sendPacket(new SystemMessage(2358));
    		return;
    	}
    	
    	if(getInventory().getInventoryItemCount(20033, 0) == 0)
    	{
    		sendPacket(new SystemMessage(6501));
    		return;
    	}

    	int count = 0;
    	int id = 1;
    	FastList<Integer> idlist = new FastList<Integer>();
    	
    	int size = tpbookmark.size();
    	
    	while(size > count)
    	{
    		idlist.add(tpbookmark.get(count)._id);
    		count++;
    	}
    	
    	for(int i=1; i<10; i++)
    	{
    		if(!idlist.contains(i))
    		{
    			id = i;
    			break;
    		}
    	}
    	
    	TeleportBookmark tpadd = new TeleportBookmark(id, x, y, z, icon, tag, name);
    	if(tpbookmark == null)
    		tpbookmark = new FastList<TeleportBookmark>();
    	
    	tpbookmark.add(tpadd);

    	destroyItem("Consume", getInventory().getItemByItemId(20033).getObjectId(), 1, null, false);
    	
    	SystemMessage sm = new SystemMessage(SystemMessageId.S1_DISAPPEARED);
    	sm.addItemName(20033);
    	sendPacket(sm);
    	
    	Connection con = null;

		try
		{

			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement(INSERT_TP_BOOKMARK);
			
			statement.setInt(1, getObjectId());
			statement.setInt(2, id);
			statement.setInt(3, x);
			statement.setInt(4, y);
			statement.setInt(5, z);
			statement.setInt(6, icon);
			statement.setString(7, tag);
			statement.setString(8, name);


			statement.execute();
			statement.close();
		}
		catch (Exception e) { _log.warning("Could not insert character teleport bookmark data: "+ e); }
		finally { try { con.close(); } catch (Exception e) {} }
		
		sendPacket(new ExGetBookMarkInfoPacket(this));
    }
    
    public void restoreTeleportBookmark()
    {
    	if(tpbookmark == null)
    		tpbookmark = new FastList<TeleportBookmark>();
    	Connection con = null;

		try
		{
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement(RESTORE_TP_BOOKMARK);
			statement.setInt(1, getObjectId());
			ResultSet rset = statement.executeQuery();

			while (rset.next())
			{
				tpbookmark.add(new TeleportBookmark(rset.getInt("Id"), rset.getInt("x"), rset.getInt("y"), rset.getInt("z"), rset.getInt("icon"), rset.getString("tag"), rset.getString("name")));
			}

			rset.close();
			statement.close();
		}
		catch (Exception e)
		{
		    _log.log(Level.SEVERE, "Failed restoing character teleport bookmark.", e);
		}
		finally
		{
			try { con.close(); } catch (Exception e) {}
		}
    }
    
    @Override
    public void sendInfo(L2PcInstance activeChar)
    {
    	if(isInBoat())
        {
        	getPosition().setWorldPosition(getBoat().getPosition().getWorldPosition());

            activeChar.sendPacket(new CharInfo(this));
            activeChar.sendPacket(new ExBrExtraUserInfo(this));
            int relation1 = getRelation(activeChar);
        	int relation2 = activeChar.getRelation(this);
        	if (getKnownList().getKnownRelations().get(activeChar.getObjectId()) != null && getKnownList().getKnownRelations().get(activeChar.getObjectId()) != relation1)
        	{
        		activeChar.sendPacket(new RelationChanged(this, relation1, activeChar.isAutoAttackable(this)));
        		if (getPet() != null)
        			activeChar.sendPacket(new RelationChanged(getPet(), relation1, activeChar.isAutoAttackable(this)));
        	}
        	if (activeChar.getKnownList().getKnownRelations().get(getObjectId()) != null && activeChar.getKnownList().getKnownRelations().get(getObjectId()) != relation2)
        	{
        		sendPacket(new RelationChanged(activeChar, relation2, isAutoAttackable(activeChar)));
        		if (activeChar.getPet() != null)
        			sendPacket(new RelationChanged(activeChar.getPet(), relation2, isAutoAttackable(activeChar)));
        	}
        	activeChar.sendPacket(new GetOnVehicle(this, getBoat(), getInBoatPosition().getX(), getInBoatPosition().getY(), getInBoatPosition().getZ()));
        	/*if(getBoat().GetVehicleDeparture() == null)
        	{

        		int xboat = getBoat().getX();
        		int yboat= getBoat().getY();
        		double modifier = Math.PI/2;
        		if (yboat == 0)
        		{
        			yboat = 1;
        		}
        		if(yboat < 0)
        		{
        			modifier = -modifier;
        		}
        		double angleboat = modifier - Math.atan(xboat/yboat);
        		int xp = getX();
        		int yp = getY();
        		modifier = Math.PI/2;
        		if (yp == 0)
        		{
        			yboat = 1;
        		}
        		if(yboat < 0)
        		{
        			modifier = -modifier;
        		}
        		double anglep = modifier - Math.atan(yp/xp);

        		double finx = Math.cos(anglep - angleboat)*Math.sqrt(xp *xp +yp*yp ) + Math.cos(angleboat)*Math.sqrt(xboat *xboat +yboat*yboat );
        		double finy = Math.sin(anglep - angleboat)*Math.sqrt(xp *xp +yp*yp ) + Math.sin(angleboat)*Math.sqrt(xboat *xboat +yboat*yboat );
        		//getPosition().setWorldPosition(getBoat().getX() - getInBoatPosition().x,getBoat().getY() - getInBoatPosition().y,getBoat().getZ()- getInBoatPosition().z);
        		getPosition().setWorldPosition((int)finx,(int)finy,getBoat().getZ()- getInBoatPosition().z);

        	}*/
        }
        else if(isInAirShip())
        {
        	getPosition().setWorldPosition(getAirShip().getPosition().getWorldPosition());

            activeChar.sendPacket(new CharInfo(this));
            activeChar.sendPacket(new ExBrExtraUserInfo(this));
            int relation1 = getRelation(activeChar);
        	int relation2 = activeChar.getRelation(this);
        	if (getKnownList().getKnownRelations().get(activeChar.getObjectId()) != null && getKnownList().getKnownRelations().get(activeChar.getObjectId()) != relation1)
        	{
        		activeChar.sendPacket(new RelationChanged(this, relation1, activeChar.isAutoAttackable(this)));
        		if (getPet() != null)
        			activeChar.sendPacket(new RelationChanged(getPet(), relation1, activeChar.isAutoAttackable(this)));
        	}
        	if (activeChar.getKnownList().getKnownRelations().get(getObjectId()) != null && activeChar.getKnownList().getKnownRelations().get(getObjectId()) != relation2)
        	{
        		sendPacket(new RelationChanged(activeChar, relation2, isAutoAttackable(activeChar)));
        		if (activeChar.getPet() != null)
        			sendPacket(new RelationChanged(activeChar.getPet(), relation2, isAutoAttackable(activeChar)));
        	}
        	activeChar.sendPacket(new ExGetOnAirShip(this, getAirShip()));
        }
        else
        {
        	activeChar.sendPacket(new CharInfo(this));
        	activeChar.sendPacket(new ExBrExtraUserInfo(this));
        	int relation1 = getRelation(activeChar);
        	int relation2 = activeChar.getRelation(this);
        	if (getKnownList().getKnownRelations().get(activeChar.getObjectId()) != null && getKnownList().getKnownRelations().get(activeChar.getObjectId()) != relation1)
        	{
        		activeChar.sendPacket(new RelationChanged(this, relation1, activeChar.isAutoAttackable(this)));
        		if (getPet() != null)
        			activeChar.sendPacket(new RelationChanged(getPet(), relation1, activeChar.isAutoAttackable(this)));
        	}
        	if (activeChar.getKnownList().getKnownRelations().get(getObjectId()) != null && activeChar.getKnownList().getKnownRelations().get(getObjectId()) != relation2)
        	{
        		sendPacket(new RelationChanged(activeChar, relation2, isAutoAttackable(activeChar)));
        		if (activeChar.getPet() != null)
        			sendPacket(new RelationChanged(activeChar.getPet(), relation2, isAutoAttackable(activeChar)));
        	}
        }
        if (getMountType() == 4)
        {
               // TODO: Remove when horse mounts fixed
               activeChar.sendPacket(new Ride(this, false, 0));
               activeChar.sendPacket(new Ride(this, true, getMountNpcId()));
        }

        switch (getPrivateStoreType())
        {
        	case L2PcInstance.STORE_PRIVATE_SELL:
        		activeChar.sendPacket(new PrivateStoreMsgSell(this));
        		break;
        	case L2PcInstance.STORE_PRIVATE_PACKAGE_SELL:
        		activeChar.sendPacket(new ExPrivateStoreSetWholeMsg(this));
        		break;
        	case L2PcInstance.STORE_PRIVATE_BUY:
        		activeChar.sendPacket(new PrivateStoreMsgBuy(this));
        		break;
        	case L2PcInstance.STORE_PRIVATE_MANUFACTURE:
        		activeChar.sendPacket(new RecipeShopMsg(this));
        		break;
        }
    }
    
    public void showQuestMovie(int id)
	{
		abortAttack();
		abortCast();
		stopMove(null);
		sendPacket(new ExStartScenePlayer(id));
	}
    
    public boolean isAllowedToEnchantSkills()
    {
    	if (isLocked())
    		return false;
    	if (isTransformed())
    		return false;
    	if (AttackStanceTaskManager.getInstance().getAttackStanceTask(this))
    		return false;
    	if (isCastingNow() || isCastingSimultaneouslyNow())
    		return false;
    	if (isInBoat() || isInAirShip())
    		return false;
    	return true;
    }

	/** 
 	 * Set the _creationTime of the L2PcInstance.<BR><BR> 
 	 */ 
	public void setCreateTime(long creationTime)
	{
		_creationTime = creationTime;
	}

	/** 
 	 * Return the _creationTime of the L2PcInstance.<BR><BR> 
 	 */ 
	public long getCreateTime()
	{
		return _creationTime;
	}
	
	/**
	 * @return number of days to char birthday.<BR><BR> 
	 */
	public int checkBirthDay()
	{
		QuestState _state = getQuestState("CharacterBirthday");
		Calendar now = Calendar.getInstance();
		Calendar birth = Calendar.getInstance();
		now.setTimeInMillis(System.currentTimeMillis());
		birth.setTimeInMillis(_creationTime);
		
		if (_state != null && _state.getInt("Birthday") > now.get(Calendar.YEAR))
			return -1;
		
		// "Characters with a February 29 creation date will receive a gift on February 28."
		if (birth.get(Calendar.DAY_OF_MONTH) == 29 && birth.get(Calendar.MONTH) == 1)
			birth.add(Calendar.HOUR_OF_DAY, -24);
		
		if (now.get(Calendar.MONTH) == birth.get(Calendar.MONTH)
				&& now.get(Calendar.DAY_OF_MONTH) == birth.get(Calendar.DAY_OF_MONTH)
				&& now.get(Calendar.YEAR) != birth.get(Calendar.YEAR))
		{
			return 0;
		}
		else
		{
			int i;
			for (i = 1; i < 6; i++)
			{
				now.add(Calendar.HOUR_OF_DAY, 24);
				if (now.get(Calendar.MONTH) == birth.get(Calendar.MONTH)
						&& now.get(Calendar.DAY_OF_MONTH) == birth.get(Calendar.DAY_OF_MONTH)
						&& now.get(Calendar.YEAR) != birth.get(Calendar.YEAR))
					return i;
			}
		}
		return -1;
	}
	
	
	/**
	 * list of character friends
	 * 
	 */
	private List<Integer> _friendList = new FastList<Integer>();
	
	public List<Integer> getFriendList()
	{
		return _friendList;
	}
	
	public void restoreFriendList()
	{
		_friendList.clear();
		
		Connection con = null;
		
		try
		{
			String sqlQuery = "SELECT friendId FROM character_friends WHERE charId=? AND relation=0";
			
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement(sqlQuery);
			statement.setInt(1, getObjectId());
			ResultSet rset = statement.executeQuery();
			
			int friendId;
			while (rset.next())
			{
				friendId = rset.getInt("friendId");
				if (friendId == getObjectId())
					continue;
				_friendList.add(friendId);
			}
			
			rset.close();
			statement.close();
		}
		catch (Exception e)
		{
			_log.warning("Error found in " + getName() + "'s FriendList: " + e);
		}
		finally
		{
			try	{ con.close(); } catch (Exception e) {}
		}
	}

	/**
	 * 
	 */
	private void notifyFriends()
	{
		FriendStatusPacket pkt = new FriendStatusPacket(getObjectId());
		for(int id : _friendList)
		{
			L2Object obj = L2World.getInstance().findObject(id);
			if (obj != null)
				obj.sendPacket(pkt);
		}
	}

	/**
	 * @return the _silenceMode
	 */
	public boolean isSilenceMode()
	{
		return _silenceMode;
	}

	/**
	 * @param mode the _silenceMode to set
	 */
	public void setSilenceMode(boolean mode)
	{
		_silenceMode = mode;
		sendPacket(new EtcStatusUpdate(this));
	}
	
	private void storeRecipeShopList()
	{
		Connection con = null;

		try
		{
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement;
			L2ManufactureList list = getCreateList();

			if (list != null && list.size() > 0)
			{
				int	_position = 1;
				statement = con.prepareStatement("DELETE FROM character_recipeshoplist WHERE charId=? ");
				statement.setInt(1, getObjectId());
				statement.execute();
				statement.close();
				for (L2ManufactureItem item : list.getList())
				{
					statement = con.prepareStatement("INSERT INTO character_recipeshoplist (charId, Recipeid, Price, Pos) VALUES (?, ?, ?, ?)");
					statement.setInt(1, getObjectId());	
					statement.setInt(2, item.getRecipeId());
					statement.setLong(3, item.getCost());
					statement.setInt(4, _position);
					statement.execute();
					statement.close();
					_position++;
				}
			}
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "Could not store recipe shop for playerID " + getObjectId() + ": ", e);
		}
		finally
		{
			try
			{
				if (con != null)
					con.close();
			}
			catch (SQLException e)
			{
				e.printStackTrace();
			}
		}
	}
	
	private void restoreRecipeShopList()
	{
		Connection con = null;

		try
		{
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con.prepareStatement("SELECT Recipeid,Price FROM character_recipeshoplist WHERE charId=? ORDER BY Pos ASC");
			statement.setInt(1, getObjectId());
			ResultSet rset = statement.executeQuery();
			
			
			L2ManufactureList createList = new L2ManufactureList();
			while (rset.next())
			{
				createList.add(new L2ManufactureItem(rset.getInt("Recipeid"), rset.getLong("Price")));
			}
			setCreateList(createList);
			rset.close();
			statement.close();
		}
		catch (Exception e)
		{
			_log.log(Level.SEVERE, "Could not restore recipe shop list data for playerId: "+getObjectId(), e);
		}
		finally
		{
			try
			{
				if (con != null)
					con.close();
			}
			catch (SQLException e)
			{
				e.printStackTrace();
			}
		}
	}

	public double getCollisionRadius()
	{
		if (getAppearance().getSex())
			return getBaseTemplate().fCollisionRadius_female;
		else
			return getBaseTemplate().fCollisionRadius;
	}
	
	public double getCollisionHeight()
	{
		if (getAppearance().getSex())
			return getBaseTemplate().fCollisionHeight_female;
		else
			return getBaseTemplate().fCollisionHeight;
	}
	
}
Obrigado gente!!
acho q isso vai ajudar mts pessoas!!

----------

Desculpe o spawn !!
mas eh q eu nao conseguia editar!!
essa ultima codificaçao eh meu L2PcInstance.java
original ...
Vlw!!

lelebrr está offline   Responder com Citação
O seguinte membro ao lado disse Obrigado(a) a : lelebrr por gostar deste Post :
Links Patrocinados
Antigo 26-01-2010, 10:52 PM   #2
lelebrr
Membro - Capitão
 
Avatar de lelebrr
 
Registrado em: Feb 2009
Posts: 125
Agradeceu: 51
Agradecido 50 Vezes em 22 Posts
Achei Ruim:
Acharam ruim Vezes em Posts
Pontos: 3,786, Nível: 38
Pontos: 3,786, Nível: 38 Pontos: 3,786, Nível: 38 Pontos: 3,786, Nível: 38
Atividade: 99%
Atividade: 99% Atividade: 99% Atividade: 99%

Inventório de lelebrr

Padrão

Desculpe o spawn !!
mas eh q eu nao conseguia editar!!
essa ultima codificaçao eh meu L2PcInstance.java
original ...
Vlw!!

lelebrr está offline   Responder com Citação
Antigo 27-01-2010, 02:01 AM   #3
Trinix
Membro - Coronel
 
Avatar de Trinix
 
Registrado em: Nov 2009
Localização: Town of Aden
Posts: 171
Agradeceu: 46
Agradecido 126 Vezes em 64 Posts
Achei Ruim:
Acharam ruim Vezes em Posts
Pontos: 5,202, Nível: 46
Pontos: 5,202, Nível: 46 Pontos: 5,202, Nível: 46 Pontos: 5,202, Nível: 46
Atividade: 99%
Atividade: 99% Atividade: 99% Atividade: 99%

Inventório de Trinix

Padrão

amigo si tu querer add isso manualmente vai ter dor de cabeça isso é um Java Patch tem um tutorial de como aplicar isso pelo Eclipse na area de Java Mods

Trinix está offline   Responder com Citação
Antigo 27-01-2010, 05:09 AM   #4
lelebrr
Membro - Capitão
 
Avatar de lelebrr
 
Registrado em: Feb 2009
Posts: 125
Agradeceu: 51
Agradecido 50 Vezes em 22 Posts
Achei Ruim:
Acharam ruim Vezes em Posts
Pontos: 3,786, Nível: 38
Pontos: 3,786, Nível: 38 Pontos: 3,786, Nível: 38 Pontos: 3,786, Nível: 38
Atividade: 99%
Atividade: 99% Atividade: 99% Atividade: 99%

Inventório de lelebrr

Padrão

intao eu posso usar como patch ???
soh tenho q mudar endereços??
Obrigado!

cara ... nao consigo !!
alguem pode posta uma foto ow colocar algum exemplo de endereço index

....

creio q meu problema esteja aki

Código: [Somente Usuários Registrados Podem Visualizar os Links Desta PáginaClique aqui para se Registrar]
Index: java/net/sf/l2j/gameServer/datatables/FakePcsTable.java
===================================================================
--- java/net/sf/l2j/gameServer/datatables/FakePcsTable.java	(revision 0)
+++ java/net/sf/l2j/gameServer/datatables/FakePcsTable.java	(revision 0)
@@ -0,0 +1,140 @@
+package com.l2jserver.gameserver.datatables;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.logging.Logger;
+
+import javolution.util.FastMap;
+
+import com.l2jserver.L2DatabaseFactory;
+import com.l2jserver.gameserver.model.actor.FakePc;
por favor gente!
Obrigado!

lelebrr está offline   Responder com Citação
Resposta


Regras para Posts
Você não pode postar novos tópicos
Você não pode postar respostas
Você não pode postar anexos
Você não pode editar seus posts

Código [IMG] Sim
Código HTML Não

Ir para...


Horários baseados na GMT -3. Agora são 12:35 AM.