/*
* 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.List;
import java.util.Map;
import java.util.Set;
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 javolution.util.FastSet;
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.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.CharSummonTable;
import com.l2jserver.gameserver.datatables.CharTemplateTable;
import com.l2jserver.gameserver.datatables.ClanTable;
import com.l2jserver.gameserver.datatables.EnchantGroupsTable;
import com.l2jserver.gameserver.datatables.ExperienceTable;
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.NobleSkillTable;
import com.l2jserver.gameserver.datatables.NpcTable;
import com.l2jserver.gameserver.datatables.PetDataTable;
import com.l2jserver.gameserver.datatables.SkillTable;
import com.l2jserver.gameserver.datatables.SkillTreesData;
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.GrandBossManager;
import com.l2jserver.gameserver.instancemanager.HandysBlockCheckerManager;
import com.l2jserver.gameserver.instancemanager.InstanceManager;
import com.l2jserver.gameserver.instancemanager.ItemsOnGroundManager;
import com.l2jserver.gameserver.instancemanager.MapRegionManager;
import com.l2jserver.gameserver.instancemanager.QuestManager;
import com.l2jserver.gameserver.instancemanager.SiegeManager;
import com.l2jserver.gameserver.instancemanager.TerritoryWarManager;
import com.l2jserver.gameserver.model.BlockList;
import com.l2jserver.gameserver.model.CharEffectList;
import com.l2jserver.gameserver.model.Elementals;
import com.l2jserver.gameserver.model.FishData;
import com.l2jserver.gameserver.model.L2AccessLevel;
import com.l2jserver.gameserver.model.L2Clan;
import com.l2jserver.gameserver.model.L2ClanMember;
import com.l2jserver.gameserver.model.L2ContactList;
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.L2Party.messageType;
import com.l2jserver.gameserver.model.L2PetData;
import com.l2jserver.gameserver.model.L2PetLevelData;
import com.l2jserver.gameserver.model.L2PremiumItem;
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.L2Skill.SkillTargetType;
import com.l2jserver.gameserver.model.L2SkillLearn;
import com.l2jserver.gameserver.model.L2Transformation;
import com.l2jserver.gameserver.model.L2UIKeysSettings;
import com.l2jserver.gameserver.model.L2World;
import com.l2jserver.gameserver.model.L2WorldRegion;
import com.l2jserver.gameserver.model.Location;
import com.l2jserver.gameserver.model.MacroList;
import com.l2jserver.gameserver.model.PartyMatchRoom;
import com.l2jserver.gameserver.model.PartyMatchRoomList;
import com.l2jserver.gameserver.model.PartyMatchWaitingList;
import com.l2jserver.gameserver.model.ShortCuts;
import com.l2jserver.gameserver.model.TerritoryWard;
import com.l2jserver.gameserver.model.TradeList;
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.L2Vehicle;
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.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.Hero;
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.PcFreight;
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.multisell.PreparedListContainer;
import com.l2jserver.gameserver.model.olympiad.OlympiadGameManager;
import com.l2jserver.gameserver.model.olympiad.OlympiadGameTask;
import com.l2jserver.gameserver.model.olympiad.OlympiadManager;
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.model.zone.type.L2BossZone;
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.ExBasicActionList;
import com.l2jserver.gameserver.network.serverpackets.ExBrExtraUserInfo;
import com.l2jserver.gameserver.network.serverpackets.ExDominionWarStart;
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.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.ExVoteSystemInfo;
import com.l2jserver.gameserver.network.serverpackets.FriendStatusPacket;
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.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.PlaySound;
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.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.skills.AbnormalEffect;
import com.l2jserver.gameserver.skills.Env;
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.effects.EffectTemplate;
import com.l2jserver.gameserver.templates.item.L2Armor;
import com.l2jserver.gameserver.templates.item.L2ArmorType;
import com.l2jserver.gameserver.templates.item.L2EtcItem;
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.PlayerEventStatus;
import com.l2jserver.gameserver.util.Point3D;
import com.l2jserver.gameserver.util.Util;
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, restore_type FROM character_skills_save WHERE charId=? AND class_index=? 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,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=?,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=?,lvl_joined_academy=?,apprentice=?,sponsor=?,varka_ketra_ally=?,clan_join_expiry_time=?,clan_create_expiry_time=?,char_name=?,death_penalty_level=?,bookmarkslot=?,vitality_points=?,language=? 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, accesslevel, online, char_slot, lastAccess, clan_privs, wantspeace, base_class, onlinetime, isin7sdungeon, punish_level, punish_timer, newbie, nobless, power_grade, subpledge, lvl_joined_academy, apprentice, sponsor, varka_ketra_ally,clan_join_expiry_time,clan_create_expiry_time,death_penalty_level,bookmarkslot,vitality_points,createTime,language 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 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;
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 String _lang = null;
private String _htmlPrefix = null;
private volatile 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 L2PetLevelData _leveldata;
private int _curFeed;
protected Future<?> _mountFeedTask;
private ScheduledFuture<?> _dismountTask;
private boolean _petItems = false;
/** 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;
private final L2ContactList _contactList = new L2ContactList(this);
private int _bookmarkslot = 0; // The Teleport Bookmark Slot
private List<TeleportBookmark> tpbookmark = new FastList<TeleportBookmark>();
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 and AirShip */
private L2Vehicle _vehicle = null;
private Point3D _inVehiclePosition;
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;
private boolean _inCrystallize;
private boolean _inCraftMode;
private long _offlineShopStart = 0;
private L2Transformation _transformation;
private int _transformationId = 0;
/** The table containing all L2RecipeList of the L2PcInstance */
private final Map<Integer, L2RecipeList> _dwarvenRecipeBook = new FastMap<Integer, L2RecipeList>();
private final Map<Integer, L2RecipeList> _commonRecipeBook = new FastMap<Integer, L2RecipeList>();
/** Premium Items */
private final Map<Integer, L2PremiumItem> _premiumItems = new FastMap<Integer, L2PremiumItem>();
/** True if the L2PcInstance is sitting */
private boolean _waitTypeSitting;
/** Location before entering Observer Mode */
private int _lastX;
private int _lastY;
private int _lastZ;
private boolean _observerMode = false;
/** Stored from last ValidatePosition **/
private final Point3D _lastServerPosition = 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
/** Recommendation Bonus task **/
private ScheduledFuture<?> _recoBonusTask;
/** Recommendation task **/
private ScheduledFuture<?> _recoGiveTask;
/** Recommendation Two Hours bonus **/
private boolean _recoTwoHoursGiven = false;
private final PcInventory _inventory = new PcInventory(this);
private final PcFreight _freight = new PcFreight(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;
// Multisell
private PreparedListContainer _currentMultiSell = null;
/** 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 final Map<String, QuestState> _quests = new FastMap<String, QuestState>();
/** The list containing all shortCuts of this L2PcInstance */
private final ShortCuts _shortCuts = new ShortCuts(this);
/** The list containing all macroses of this L2PcInstance */
private final MacroList _macroses = new MacroList(this);
private final List<L2PcInstance> _snoopListener = new FastList<L2PcInstance>();
private final List<L2PcInstance> _snoopedPlayer = new FastList<L2PcInstance>();
// 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!!
// after Freya players can control more than one tamed beast
private List<L2TamedBeastInstance> _tamedBeast = null;
private boolean _minimapAllowed = false;
// client radar
//TODO: This needs to be better intergrated and saved/loaded
private L2Radar _radar;
// Party matching
// private int _partymatching = 0;
private int _partyroom = 0;
// private int _partywait = 0;
// 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;
// charges
private final 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 final 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 > GameTimeController.getGameTicks(); }
private long _teleportProtectEndTime = 0;
public boolean isTeleportProtected() { return _teleportProtectEndTime > GameTimeController.getGameTicks(); }
// 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;
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>().shared();
/** Active shots. */
protected FastSet<Integer> _activeSoulShots = new FastSet<Integer>().shared();
public final ReentrantLock soulShotLock = new ReentrantLock();
/** Event parameters */
private PlayerEventStatus eventStatus = null;
private byte _handysBlockCheckerEventArena = -1;
/** new loto ticket **/
private final int _loto[] = new int[5];
//public static int _loto_nums[] = {0,1,2,3,4,5,6,7,8,9,};
/** new race ticket **/
private final 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 final List<String> _validBypass = new FastList<String>();
private final 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;
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;
/** Char Coords from Client */
private int _clientX;
private int _clientY;
private int _clientZ;
private int _clientHeading;
// during fall validations will be disabled for 10 ms.
private static final int FALLING_VALIDATION_DELAY = 10000;
private volatile long _fallingTimestamp = 0;
private int _multiSocialTarget = 0;
private int _multiSociaAction = 0;
private int _movieId = 0;
private String _adminConfirmCmd = null;
private volatile long _lastItemAuctionInfoRequest = 0;
private Future<?> _PvPRegTask;
private long _pvpFlagLasts;
public void setPvpFlagLasts(long time)
{
_pvpFlagLasts = time;
}
public long getPvpFlagLasts()
{
return _pvpFlagLasts;
}
public void startPvPFlag()
{
updatePvPFlag(1);
_PvPRegTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new PvPFlag(), 1000, 1000);
}
public void stopPvpRegTask()
{
if (_PvPRegTask != null)
_PvPRegTask.cancel(true);
}
public void stopPvPFlag()
{
stopPvpRegTask();
updatePvPFlag(0);
_PvPRegTask = null;
}
/** Task lauching the function stopPvPFlag() */
private class PvPFlag implements Runnable
{
public PvPFlag()
{
}
@Override
public void run()
{
try
{
if (System.currentTimeMillis() > getPvpFlagLasts())
{
stopPvPFlag();
}
else if (System.currentTimeMillis() > (getPvpFlagLasts() - 20000))
{
updatePvPFlag(2);
}
else
{
updatePvPFlag(1);
// Start a new PvP timer check
//checkPvPFlag();
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "error in pvp flag task:", e);
}
}
}
// Character UI
private L2UIKeysSettings _uiKeySettings;
/** Herbs Task Time **/
private int _herbstask = 0;
/** Task for Herbs */
private class HerbTask implements Runnable
{
private final String _process;
private final int _itemId;
private final long _count;
private final L2Object _reference;
private final boolean _sendMessage;
HerbTask(String process, int itemId, long count, L2Object reference, boolean sendMessage)
{
_process = process;
_itemId = itemId;
_count = count;
_reference = reference;
_sendMessage = sendMessage;
}
@Override
public void run()
{
try
{
addItem(_process, _itemId, _count, _reference, _sendMessage);
}
catch (Exception e)
{
_log.log(Level.WARNING, "", e);
}
}
}
/** ShortBuff clearing Task */
ScheduledFuture<?> _shortBuffTask = null;
private class ShortBuffTask implements Runnable
{
@Override
public void run()
{
if (L2PcInstance.this == null)
return;
L2PcInstance.this.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 static class SkillDat
{
private final L2Skill _skill;
private final boolean _ctrlPressed;
private final 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 final SummonRequest _summonRequest = new SummonRequest();
private static 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 final GatesRequest _gatesRequest = new GatesRequest();
private static class GatesRequest
{
private L2DoorInstance _target = null;
public void setTarget(L2DoorInstance door)
{
_target = door;
}
public L2DoorInstance getDoor()
{
return _target;
}
}
// Save responder name for log it
private String _lastPetitionGmName = null;
/**
* 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)
return getAccountNamePlayer();
return getClient().getAccountName();
}
public String getAccountNamePlayer()
{
return _accountName;
}
public Map<Integer, String> getAccountChars()
{
return _chars;
}
public int getRelation(L2PcInstance target)
{
int result = 0;
if (getClan() != null)
{
result |= RelationChanged.RELATION_CLAN_MEMBER;
if (getClan() == target.getClan())
result |= RelationChanged.RELATION_CLAN_MATE;
if (getAllyId() != 0)
result |= RelationChanged.RELATION_ALLY_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)
{
if (TerritoryWarManager.getInstance().getRegisteredTerritoryId(this) != 0)
result |= RelationChanged.RELATION_TERRITORY_WAR;
else
{
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;
}
}
if(getBlockCheckerArena() != -1)
{
result |= RelationChanged.RELATION_INSIEGE;
HandysBlockCheckerManager.ArenaParticipantsHolder holder = HandysBlockCheckerManager.getInstance().getHolder(getBlockCheckerArena());
if(holder.getPlayerTeam(this) == 0)
result |= RelationChanged.RELATION_ENEMY;
else
result |= RelationChanged.RELATION_ALLY;
result |= RelationChanged.RELATION_ATTACKER;
}
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);
setInstanceType(InstanceType.L2PcInstance);
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);
startVitalityTask();
}
private L2PcInstance(int objectId)
{
super(objectId, null);
setInstanceType(InstanceType.L2PcInstance);
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;
}
/** 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(boolean)}</li> <li>Save player data into DB <BR>
* {@link L2GameClient#saveCharToDisk(L2PcInstance, boolean)}</li> <BR>
* <BR>
*/
public void logout()
{
logout(true);
}
/**
* Manage Logout Task: <li>Remove player from world <BR>
* {@link L2PcInstance#deleteMe(boolean)}</li> <li>Save player data into DB <BR>
* {@link L2GameClient#saveCharToDisk(L2PcInstance, boolean)}</li> <BR>
* <BR>
* @param closeClient
*/
public void logout(boolean closeClient)
{
try
{
closeNetConnection(closeClient);
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception on logout(): " + e.getMessage(), e);
}
}
/**
* 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
{
L2DatabaseFactory.close(con);
}
}
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
{
L2DatabaseFactory.close(con);
}
}
/**
* 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 = "";
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().getName().equals(qs.getQuest().getName()))
{
if (qs.getQuest().notifyEvent(event, npc, this))
showQuestWindow(quest, State.getStateName(qs.getState()));
retval = qs;
}
}
}
}
}
}
return retval;
}
private void showQuestWindow(String questId, String stateId)
{
String path = "data/scripts/quests/"+questId+"/"+stateId+".htm";
String content = HtmCache.getInstance().getHtm(getHtmlPrefix(), 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;
/**
* 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)
return;
if (!getNotifyQuestOfDeath().contains(qs))
getNotifyQuestOfDeath().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 == null)
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)
{
synchronized(this)
{
if (_notifyQuestOfDeathList == null)
_notifyQuestOfDeathList = new FastList<QuestState>();
}
}
return _notifyQuestOfDeathList;
}
public final boolean isNotifyQuestOfDeathEmpty()
{
return _notifyQuestOfDeathList == null || _notifyQuestOfDeathList.isEmpty();
}
/**
* 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;
}
@Override
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_ALTERED))
{
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 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;
}
/**
* Set the number of recommandation obtained by the L2PcInstance (Max : 255).<BR><BR>
*/
public void setRecomLeft(int value)
{
if (value > 255)
_recomLeft = 255;
else if (value < 0)
_recomLeft = 0;
else
_recomLeft = 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)
{
target.incRecomHave();
decRecomLeft();
}
/**
* 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>
*/
@Override
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() &&
((item.getItemType() != L2EtcItemType.ARROW) && (item.getItemType() != L2EtcItemType.BOLT)))
{
int crystaltype = item.getItem().getCrystalType();
if (crystaltype > getExpertiseLevel())
{
if (item.isWeapon() && crystaltype > weaponPenalty)
weaponPenalty = crystaltype;
else if (crystaltype > armorPenalty)
armorPenalty = crystaltype;
}
}
}
boolean changed = false;
// calc armor penalty
armorPenalty = armorPenalty - getExpertiseLevel();
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 - getExpertiseLevel();
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 = SystemMessage.getSystemMessage(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 checkSShotsMatch(L2ItemInstance equipped, L2ItemInstance unequipped)
{
if (unequipped == null)
return;
unequipped.setChargedSoulshot(L2ItemInstance.CHARGED_NONE);
unequipped.setChargedSpiritshot(L2ItemInstance.CHARGED_NONE);
// on retail auto shots never disabled on uneqip
/*if (unequipped.getItem().getType2() == L2Item.TYPE2_WEAPON &&
(equipped == null ? true : equipped.getItem().getItemGradeSPlus() != unequipped.getItem().getItemGradeSPlus()))
{
disableAutoShotByCrystalType(unequipped.getItem().getItemGradeSPlus());
}*/
}
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;
if ((item.getItem().getBodyPart() & L2Item.SLOT_MULTI_ALLWEAPON) != 0)
{
L2ItemInstance old = getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
checkSShotsMatch(item, old);
}
if (isEquiped)
{
if (item.getEnchantLevel() > 0)
{
sm = SystemMessage.getSystemMessage(SystemMessageId.EQUIPMENT_S1_S2_REMOVED);
sm.addNumber(item.getEnchantLevel());
sm.addItemName(item);
}
else
{
sm = SystemMessage.getSystemMessage(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
{
items = getInventory().equipItemAndRecord(item);
if (item.isEquipped())
{
if (item.getEnchantLevel() > 0)
{
sm = SystemMessage.getSystemMessage(SystemMessageId.S1_S2_EQUIPPED);
sm.addNumber(item.getEnchantLevel());
sm.addItemName(item);
}
else
{
sm = SystemMessage.getSystemMessage(SystemMessageId.S1_EQUIPPED);
sm.addItemName(item);
}
sendPacket(sm);
// Consume mana - will start a task if required; returns if item is not a shadow item
item.decreaseMana(false);
if ((item.getItem().getBodyPart() & L2Item.SLOT_MULTI_ALLWEAPON) != 0)
{
rechargeAutoSoulShot(true, true, false);
}
}
else
sendPacket(SystemMessageId.CANNOT_EQUIP_ITEM_DUE_TO_BAD_CONDITION);
}
refreshExpertisePenalty();
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 = SystemMessage.getSystemMessage(SystemMessageId.CLAN_MEMBER_S1_EXPELLED);
msg.addPcName(this);
_clan.broadcastToOnlineMembers(msg);
_clan.broadcastToOnlineMembers(new PledgeShowMemberListDelete(getName()));
_clan.removeClanMember(getObjectId(), 0);
sendPacket(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(SystemMessageId.THIRD_CLASS_TRANSFER));
else
sendPacket(SystemMessage.getSystemMessage(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));
//Add AutoGet skills and normal skills and/or learnByFS depending on configurations.
rewardSkills();
if (!isGM() && Config.DECREASE_SKILL_LEVEL)
checkPlayerSkills();
}
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;
}
/**
* This method reward all AutoGet skills and Normal skills if Auto-Learn configuration is true.<br>
*/
public void rewardSkills()
{
//Give all normal skills if activated Auto-Learn is activated, included AutoGet skills.
if (Config.AUTO_LEARN_SKILLS)
{
giveAvailableSkills(Config.AUTO_LEARN_FS_SKILLS, true);
}
else
{
giveAvailableAutoGetSkills();
}
checkItemRestriction();
sendSkillList();
}
/**
* Re-give all skills which aren't saved to database, like Noble, Hero, Clan Skills.<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();
clan.addSkillEffects(this);
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();
}
public int giveAvailableSkills(boolean includedByFs, boolean includeAutoGet) {
return giveAvailableSkills(includedByFs, includeAutoGet, false);
}
/**
* Give all available skills to the player.<br>
* @param includedByFs
* @param includeAutoGet
* @return skillCounter, the amount of new skills added.
*/
public int giveAvailableSkills(boolean includedByFs, boolean includeAutoGet, boolean consumeSp)
{
int skillCounter = 0;
int skillLvlCounter = 0;
int spConsumed = 0;
boolean learned = false;
boolean insufficientSp = false;
// Get available skills
FastList<L2SkillLearn> skills = SkillTreesData.getInstance().getAvailableSkills(this, getClassId(), includedByFs, includeAutoGet);
do
{
learned = false;
for (L2SkillLearn s: skills)
{
L2Skill sk = SkillTable.getInstance().getInfo(s.getSkillId(), s.getSkillLevel());
if ( sk == null
|| ( sk.getId() == L2Skill.SKILL_DIVINE_INSPIRATION
&& !Config.AUTO_LEARN_DIVINE_INSPIRATION && !isGM())
|| (consumeSp && getSp() < s.getLevelUpSp()))
{
if (consumeSp && getSp() < s.getLevelUpSp())
insufficientSp = true;
continue;
}
if (consumeSp) {
setSp(getSp() - s.getLevelUpSp());
final StatusUpdate su = new StatusUpdate(this);
su.addAttribute(StatusUpdate.SP, getSp());
sendPacket(su);
spConsumed += s.getLevelUpSp();
}
if (getSkillLevel(sk.getId()) == -1)
{
skillCounter++;
} else
{
skillLvlCounter++;
}
// 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);
learned = true;
}
//Get new available skills, some skills depend of previous skills to be available.
skills = SkillTreesData.getInstance().getAvailableSkills(this, getClassId(), includedByFs, includeAutoGet);
} while (learned);
if (consumeSp)
sendMessage("" + spConsumed + " SP has been consumed.");
sendMessage("You have learned " + skillCounter + " new skills.");
sendMessage("You have learned " + skillLvlCounter + " skill upgrades.");
if (insufficientSp)
sendMessage("You have insufficient SP to learn all remaining skills.");
return skillCounter;
}
/**
* Give all available AutoGet skills to the player.<br>
*/
public void giveAvailableAutoGetSkills()
{
// Get available skills
final FastList<L2SkillLearn> autoGetSkills = SkillTreesData.getInstance().getAvailableAutoGetSkills(this);
if ((autoGetSkills != null) && !autoGetSkills.isEmpty())
{
for (L2SkillLearn s: autoGetSkills)
{
final L2Skill skill = SkillTable.getInstance().getInfo(s.getSkillId(), s.getSkillLevel());
if (skill != null)
{
addSkill(skill, true);
}
else
{
_log.warning("Skipped null autoGet Skill for player:" + getName() + "[" + getObjectId() + "]");
}
}
}
}
/** 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 true if Hellbound minimap allowed */
public boolean isMinimapAllowed()
{
return _minimapAllowed;
}
/* Enable or disable minimap on Hellbound */
public void setMinimapAllowed(boolean b)
{
_minimapAllowed = b;
}
/** 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)
return _clan.getCrestId();
return 0;
}
/**
* @return The Clan CrestLarge Identifier or 0
*/
public int getClanCrestLargeId()
{
if (_clan != null)
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()
{
sitDown(true);
}
public void sitDown(boolean checkCast)
{
if (checkCast && isCastingNow())
{
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(), 2500);
setIsParalyzed(true);
}
}
/**
* Sit down Task
*/
private class SitDownTask implements Runnable
{
@Override
public void run()
{
L2PcInstance.this.setIsParalyzed(false);
L2PcInstance.this.getAI().setIntention(CtrlIntention.AI_INTENTION_REST);
}
}
/**
* Stand up Task
*/
private class StandUpTask implements Runnable
{
@Override
public void run()
{
L2PcInstance.this.setIsSitting(false);
L2PcInstance.this.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.isParticipant(this) && getEventStatus().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 (_effects.isAffected(CharEffectList.EFFECT_FLAG_RELAXING))
{
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(), 2500);
}
}
/**
* 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;
}
/**
* Return the PcFreight object of the L2PcInstance.<BR><BR>
*/
public PcFreight getFreight()
{
return _freight;
}
/**
* 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>
*/
@Deprecated
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 = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S1_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(SystemMessage.getSystemMessage(SystemMessageId.YOU_NOT_ENOUGH_ADENA));
return false;
}
if (count > 0)
{
L2ItemInstance adenaItem = _inventory.getAdenaInstance();
if (!_inventory.reduceAdena(process, count, this, reference))
return false;
// 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 = SystemMessage.getSystemMessage(SystemMessageId.S1_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 = SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(SystemMessageId.YOU_NOT_ENOUGH_ADENA));
return false;
}
if (count > 0)
{
L2ItemInstance ancientAdenaItem = _inventory.getAncientAdenaInstance();
if (!_inventory.reduceAncientAdena(process, count, this, reference))
return false;
if (!Config.FORCE_INVENTORY_UPDATE)
{
InventoryUpdate iu = new InventoryUpdate();
iu.addItem(ancientAdenaItem);
sendPacket(iu);
}
else
{
sendPacket(new ItemList(this, false));
}
if (sendMessage)
{
if (count > 1)
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S2_S1_DISAPPEARED);
sm.addItemName(PcInventory.ANCIENT_ADENA_ID);
sm.addItemNumber(count);
sendPacket(sm);
}
else
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISAPPEARED);
sm.addItemName(PcInventory.ANCIENT_ADENA_ID);
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 = SystemMessage.getSystemMessage(SystemMessageId.YOU_PICKED_UP_S1_S2);
sm.addItemName(item);
sm.addItemNumber(item.getCount());
sendPacket(sm);
}
else if (item.getEnchantLevel() > 0)
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_PICKED_UP_A_S1_S2);
sm.addNumber(item.getEnchantLevel());
sm.addItemName(item);
sendPacket(sm);
}
else
{
SystemMessage sm = SystemMessage.getSystemMessage(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(this);
su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
sendPacket(su);
// If over capacity, drop the item
if (!isGM() && !_inventory.validateCapacity(0, item.isQuestItem()) && newitem.isDropable() && (!newitem.isStackable() || newitem.getLastChange() != L2ItemInstance.MODIFIED))
dropItem("InvDrop", newitem, null, true, 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(SystemMessage.getSystemMessage(SystemMessageId.C1_ACQUIRED_THE_FLAG), this.getName());
}
}
// Territory Ward
else if (item.getItemId() >= 13560 && item.getItemId() <= 13568)
{
TerritoryWard ward = TerritoryWarManager.getInstance().getTerritoryWard(item.getItemId() - 13479);
if (ward != null)
ward.activate(this, item);
}
}
}
/**
* 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 L2ItemInstance 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 null;
}
// 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 = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S2_S1_S);
sm.addItemName(itemId);
sm.addItemNumber(count);
sendPacket(sm);
}
else
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_PICKED_UP_S1_S2);
sm.addItemName(itemId);
sm.addItemNumber(count);
sendPacket(sm);
}
}
else
{
if (process.equalsIgnoreCase("sweep") || process.equalsIgnoreCase("Quest"))
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.EARNED_ITEM_S1);
sm.addItemName(itemId);
sendPacket(sm);
}
else
{
SystemMessage sm = SystemMessage.getSystemMessage(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, false);
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, item.isQuestItem()) && createdItem.isDropable() && (!createdItem.isStackable() || createdItem.getLastChange() != L2ItemInstance.MODIFIED))
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(SystemMessage.getSystemMessage(SystemMessageId.C1_ACQUIRED_THE_FLAG), this.getName());
}
}
// Territory Ward
else if (createdItem.getItemId() >= 13560 && createdItem.getItemId() <= 13568)
{
TerritoryWard ward = TerritoryWarManager.getInstance().getTerritoryWard(createdItem.getItemId() - 13479);
if (ward != null)
ward.activate(this, createdItem);
}
return createdItem;
}
}
return null;
}
/**
* 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(SystemMessage.getSystemMessage(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(this);
su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
sendPacket(su);
// Sends message to client if requested
if (sendMessage)
{
if (count > 1)
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S2_S1_DISAPPEARED);
sm.addItemName(item);
sm.addItemNumber(count);
sendPacket(sm);
}
else
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISAPPEARED);
sm.addItemName(item);
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(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(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)
{
if (itemId == 57)
return reduceAdena(process, count, reference, sendMessage);
L2ItemInstance item = _inventory.getItemByItemId(itemId);
if (item == null || item.getCount() < count || _inventory.destroyItemByItemId(process, itemId, count, this, reference) == null)
{
if (sendMessage)
sendPacket(SystemMessage.getSystemMessage(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(this);
su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
sendPacket(su);
// Sends message to client if requested
if (sendMessage)
{
if (count > 1)
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S2_S1_DISAPPEARED);
sm.addItemName(itemId);
sm.addItemNumber(count);
sendPacket(sm);
}
else
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISAPPEARED);
sm.addItemName(itemId);
sendPacket(sm);
}
}
return true;
}
/**
* 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(this);
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);
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);
}
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
* @param protectItem: whether or not dropped item must be protected temporary against other players
* @return boolean informing if the action was successfull
*/
public boolean dropItem(String process, L2ItemInstance item, L2Object reference, boolean sendMessage, boolean protectItem)
{
item = _inventory.dropItem(process, item, this, reference);
if (item == null)
{
if (sendMessage)
sendPacket(SystemMessage.getSystemMessage(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);
}
// protection against auto destroy dropped 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);
// retail drop protection
if (protectItem)
item.getDropProtection().protect(this);
// 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(this);
su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
sendPacket(su);
// Sends message to client if requested
if (sendMessage)
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_DROPPED_S1);
sm.addItemName(item);
sendPacket(sm);
}
return true;
}
public boolean dropItem(String process, L2ItemInstance item, L2Object reference, boolean sendMessage)
{
return dropItem(process, item, reference, sendMessage, false);
}
/**
* 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, boolean protectItem)
{
L2ItemInstance invitem = _inventory.getItemByObjectId(objectId);
L2ItemInstance item = _inventory.dropItem(process, objectId, count, this, reference);
if (item == null)
{
if (sendMessage)
sendPacket(SystemMessage.getSystemMessage(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);
// retail drop protection
if (protectItem)
item.getDropProtection().protect(this);
// 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(this);
su.addAttribute(StatusUpdate.CUR_LOAD, getCurrentLoad());
sendPacket(su);
// Sends message to client if requested
if (sendMessage)
{
SystemMessage sm = SystemMessage.getSystemMessage(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().getControlObjectId() == 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;
}
// 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;
}
public void setTeleportProtection(boolean protect)
{
if (Config.DEVELOPER && (protect || _teleportProtectEndTime > 0))
_log.warning(getName() + ": Tele Protection " + (protect?"ON " + (GameTimeController.getGameTicks() + Config.PLAYER_TELEPORT_PROTECTION * GameTimeController.TICKS_PER_SECOND) :"OFF") + " (currently " + GameTimeController.getGameTicks() + ")");
_teleportProtectEndTime = protect? GameTimeController.getGameTicks() + Config.PLAYER_TELEPORT_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>
*/
private 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(LeaveWorld.STATIC_PACKET);
else
client.close(ServerClose.STATIC_PACKET);
}
}
}
}
public Point3D getCurrentSkillWorldPosition()
{
return _currentSkillWorldPosition;
}
public void setCurrentSkillWorldPosition(Point3D worldPosition)
{
_currentSkillWorldPosition = worldPosition;
}
/**
*
* @see com.l2jserver.gameserver.model.actor.L2Character#enableSkill(com.l2jserver.gameserver.model.L2Skill)
*/
@Override
public void enableSkill(L2Skill skill)
{
super.enableSkill(skill);
_reuseTimeStamps.remove(skill.getReuseHashCode());
}
/**
*
* @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(SystemMessage.getSystemMessage(SystemMessageId.A_MALICIOUS_SKILL_CANNOT_BE_USED_IN_PEACE_ZONE));
return false;
}
if (getTrap() != null
&& getTrap().getSkill().getId() == ((L2SkillTrap)skill).getTriggerSkillId())
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
sm.addSkillName(skill);
sendPacket(sm);
return false;
}
break;
}
case SUMMON:
{
if (!((L2SkillSummon)skill).isCubic() && (getPet() != null || isMounted() || CharSummonTable.getInstance().getPets().contains(getObjectId()) || CharSummonTable.getInstance().getPets().contains(getObjectId())))
{
if (Config.DEBUG)
_log.fine("player has a pet already. ignore summon skill");
sendPacket(SystemMessage.getSystemMessage(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 = SystemMessage.getSystemMessage(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() && skill.getSkillType() != L2SkillType.REFUEL))
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
sm.addSkillName(skill);
sendPacket(sm);
return false;
}
return true;
}
/**
* 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(this);
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
L2Party party = _party;
if (party != null
&& (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);
party.broadcastToPartyMembers(this, update);
}
if (isInOlympiadMode()
&& isOlympiadStart()
&& (needCpUpdate || needHpUpdate))
{
final OlympiadGameTask game = OlympiadGameManager.getInstance().getOlympiadTask(getOlympiadGameId());
if (game != null && game.isBattleStarted())
game.getZone().broadcastStatusUpdate(this);
}
// 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));
if (TerritoryWarManager.getInstance().isTWInProgress()
&& (TerritoryWarManager.getInstance().checkIsRegistered(-1, getObjectId())
|| TerritoryWarManager.getInstance().checkIsRegistered(-1, getClan())))
{
broadcastPacket(new ExDominionWarStart(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)
{
if (player == null)
continue;
player.sendPacket(mov);
if (mov instanceof CharInfo)
{
int relation = getRelation(player);
Integer oldrelation = getKnownList().getKnownRelations().get(player.getObjectId());
if (oldrelation != null && oldrelation != relation)
{
player.sendPacket(new RelationChanged(this, relation, isAutoAttackable(player)));
if (getPet() != null)
player.sendPacket(new RelationChanged(getPet(), relation, isAutoAttackable(player)));
}
}
}
}
}
@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 (player == null)
continue;
if (isInsideRadius(player, radiusInKnownlist, false, false))
{
player.sendPacket(mov);
if (mov instanceof CharInfo)
{
int relation = getRelation(player);
Integer oldrelation = getKnownList().getKnownRelations().get(player.getObjectId());
if (oldrelation != null && oldrelation != relation)
{
player.sendPacket(new RelationChanged(this, relation, isAutoAttackable(player)));
if (getPet() != null)
player.sendPacket(new RelationChanged(getPet(), relation, isAutoAttackable(player)));
}
}
}
}
}
}
/**
* 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);
}
}
private class GameGuardCheck implements Runnable
{
/**
* @see java.lang.Runnable#run()
*/
@Override
public void run()
{
L2GameClient client = L2PcInstance.this.getClient();
if (client != null && !client.isAuthedGG() && L2PcInstance.this.isOnline())
{
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(LeaveWorld.STATIC_PACKET);
}
}
}
/**
* 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(SystemMessage.getSystemMessage(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(this+" 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(this);
if (Config.DEBUG)
_log.fine("pickup pos: "+ target.getX() + " "+target.getY()+ " "+target.getZ() );
sendPacket(sm);
SystemMessage smsg = null;
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 (!target.getDropProtection().tryPickUp(this))
{
sendPacket(ActionFailed.STATIC_PACKET);
smsg = SystemMessage.getSystemMessage(SystemMessageId.FAILED_TO_PICKUP_S1);
smsg.addItemName(target);
sendPacket(smsg);
return;
}
if ( ((isInParty() && getParty().getLootDistribution() == L2Party.ITEM_LOOTER) || !isInParty()) && !_inventory.validateCapacity(target))
{
sendPacket(ActionFailed.STATIC_PACKET);
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.SLOTS_FULL));
return;
}
if (isInvul() && !isGM())
{
sendPacket(ActionFailed.STATIC_PACKET);
smsg = SystemMessage.getSystemMessage(SystemMessageId.FAILED_TO_PICKUP_S1);
smsg.addItemName(target);
sendPacket(smsg);
return;
}
if (target.getOwnerId() != 0 && target.getOwnerId() != getObjectId() && !isInLooterParty(target.getOwnerId()))
{
if (target.getItemId() == 57)
{
smsg = SystemMessage.getSystemMessage(SystemMessageId.FAILED_TO_PICKUP_S1_ADENA);
smsg.addItemNumber(target.getCount());
}
else if (target.getCount() > 1)
{
smsg = SystemMessage.getSystemMessage(SystemMessageId.FAILED_TO_PICKUP_S2_S1_S);
smsg.addItemName(target);
smsg.addItemNumber(target.getCount());
}
else
{
smsg = SystemMessage.getSystemMessage(SystemMessageId.FAILED_TO_PICKUP_S1);
smsg.addItemName(target);
}
sendPacket(ActionFailed.STATIC_PACKET);
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, false);
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)
{
smsg = SystemMessage.getSystemMessage(SystemMessageId.ANNOUNCEMENT_C1_PICKED_UP_S2_S3);
smsg.addPcName(this);
smsg.addNumber(target.getEnchantLevel());
smsg.addItemName(target.getItemId());
broadcastPacket(smsg, 1400);
}
else
{
smsg = SystemMessage.getSystemMessage(SystemMessageId.ANNOUNCEMENT_C1_PICKED_UP_S2);
smsg.addPcName(this);
smsg.addItemName(target.getItemId());
broadcastPacket(smsg, 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);
}
else
{
addItem("Pickup", target, null, true);
//Auto-Equip arrows/bolts if player has a bow/crossbow and player picks up arrows/bolts.
final L2EtcItem etcItem = target.getEtcItem();
if (etcItem != null)
{
final L2EtcItemType itemType = etcItem.getItemType();
if (itemType == L2EtcItemType.ARROW)
{
checkAndEquipArrows();
}
else if (itemType == L2EtcItemType.BOLT)
{
checkAndEquipBolts();
}
}
}
}
}
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(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(SystemMessageId.NO_PRIVATE_STORE_HERE));
sendPacket(ActionFailed.STATIC_PACKET);
}
}
public final PreparedListContainer getMultiSell()
{
return _currentMultiSell;
}
public final void setMultiSell(PreparedListContainer list)
{
_currentMultiSell = list;
}
@Override
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 = SystemMessage.getSystemMessage(SystemMessageId.YOU_ALREADY_POLYMORPHED_AND_CANNOT_POLYMORPH_AGAIN);
sendPacket(msg);
return;
}
setQueuedSkill(null, false, false);
if(isMounted())
{
// Get off the strider or something else if character is mounted
dismount();
}
_transformation = transformation;
stopAllToggles();
transformation.onTransform();
sendSkillList();
sendPacket(new SkillCoolTime(this));
sendPacket(ExBasicActionList.getStaticPacket(this));
broadcastUserInfo();
}
@Override
public synchronized void untransform()
{
if (_transformation != null)
{
setQueuedSkill(null, false, false);
setTransformAllowedSkills(new int[]{});
_transformation.onUntransform();
_transformation = null;
stopEffects(L2EffectType.TRANSFORMATION);
sendSkillList();
sendPacket(new SkillCoolTime(this));
sendPacket(ExBasicActionList.getStaticPacket(this));
broadcastUserInfo();
}
}
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
{
L2DatabaseFactory.close(con);
}
}
/**
* 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
{
L2DatabaseFactory.close(con);
}
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;
// vehicles cant be targeted
else if (newTarget instanceof L2Vehicle)
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 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 setMarryRequest(boolean state)
{
_marryrequest = state;
}
public boolean isMarryRequest()
{
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 = L2World.getInstance().getPlayer(_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 L2Item item (always equiped in the left hand).<BR>
* Arrows, Shield..<BR>
*
*/
@Override
public L2Item getSecondaryWeaponItem()
{
L2ItemInstance item = getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
if (item != null)
return item.getItem();
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(true);
}
if (killer != null)
{
L2PcInstance pk = killer.getActingPlayer();
TvTEvent.onKill(killer, this);
if (L2Event.isParticipant(pk) && pk != null)
pk.getEventStatus().kills.add(this);
//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 = SystemMessage.getSystemMessage(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 = SystemMessage.getSystemMessage(SystemMessageId.S1);
sm.addString(msg);
Announcements.getInstance().announceToAll(sm);
}
else
Announcements.getInstance().announceToAll(msg);
}
}
broadcastStatusUpdate();
// Clear resurrect xp calculation
setExpBeforeDeath(0);
// Issues drop of Cursed Weapon.
if (isCursedWeaponEquipped())
{
CursedWeaponsManager.getInstance().drop(_cursedWeaponEquippedId, killer);
}
else if (isCombatFlagEquipped())
{
//TODO: Fort siege during TW??
if (TerritoryWarManager.getInstance().isTWInProgress())
TerritoryWarManager.getInstance().dropCombatFlag(this, true, false);
else
{
Fort fort = FortManager.getInstance().getFort(this);
if (fort != null)
FortSiegeManager.getInstance().dropCombatFlag(this, fort.getFortId());
else
{
int slot = getInventory().getSlotFromItem(getInventory().getItemByItemId(9819));
getInventory().unEquipItemInBodySlot(slot);
destroyItem("CombatFlag", getInventory().getItemByItemId(9819), null, true);
}
}
}
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 player is Lucky shouldn't get penalized.
if (Config.ALT_GAME_DELEVEL && !isLucky())
{
// 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)
final boolean siegeNpc = (killer instanceof L2DefenderInstance) || (killer instanceof L2FortCommanderInstance);
final boolean atWar = (pk != null) && (getClan() != null) && (getClan().isAtWarWith(pk.getClanId()));
deathPenalty(atWar, (pk != null), siegeNpc);
}
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 (isAffected(CharEffectList.EFFECT_FLAG_CHARM_OF_COURAGE) && this.isInSiege())
{
reviveRequest(this, null, false);
}
return true;
}
private void onDieDropItem(L2Character killer)
{
if (L2Event.isParticipant(this) || 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().getControlObjectId() == 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().unEquipItemInSlot(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 = SystemMessage.getSystemMessage(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
checkItemRestriction();
}
}
}
/**
* 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();
}
}
/**
* TODO: Unhardcode by implementing Lucky effect (Support for effects on passive skills required).
* @return Returns {@code true} if player has Lucky skill and is level 9 or less.
*/
public boolean isLucky()
{
return ((getLevel() <= 9) && (getKnownSkill(L2Skill.SKILL_LUCKY) != null));
}
/**
* 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(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 (!L2Event.isParticipant(this))
if (lvl < ExperienceTable.getInstance().getMaxLevel())
lostExp = Math.round((getStat().getExpForLevel(lvl+1) - getStat().getExpForLevel(lvl)) * percentLost /100);
else
lostExp = Math.round((getStat().getExpForLevel(ExperienceTable.getInstance().getMaxLevel()) - getStat().getExpForLevel(ExperienceTable.getInstance().getMaxLevel() - 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);
}
public boolean isPartyWaiting()
{
return PartyMatchWaitingList.getInstance().getPlayers().contains(this);
}
public void setPartyRoom(int id)
{
_partyroom = id;
}
public int getPartyRoom()
{
return _partyroom;
}
public boolean isInPartyMatchRoom()
{
return _partyroom > 0;
}
/**
* 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();
stopRecoBonusTask();
stopRecoGiveTask();
}
/**
* 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 List<L2TamedBeastInstance> getTrainedBeasts()
{
return _tamedBeast;
}
/**
* Set the L2Summon of the L2PcInstance.<BR><BR>
*/
public void addTrainedBeast(L2TamedBeastInstance tamedBeast)
{
if (_tamedBeast == null)
_tamedBeast = new FastList<L2TamedBeastInstance>();
_tamedBeast.add(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 void setActiveRequester(L2PcInstance requester)
{
_activeRequester = requester;
}
/**
* Return the L2PcInstance requester of a transaction (ex : FriendInvite, JoinAlly, JoinParty...).<BR><BR>
*/
public L2PcInstance getActiveRequester()
{
L2PcInstance requester = _activeRequester;
if (requester != null)
{
if (requester.isRequestExpired() && _activeTradeList == null)
_activeRequester = null;
}
return _activeRequester;
}
/**
* Return True if a transaction is in progress.<BR><BR>
*/
public boolean isProcessingRequest()
{
return getActiveRequester() != null || _requestExpireTime > GameTimeController.getGameTicks();
}
/**
* Return True if a transaction is in progress.<BR><BR>
*/
public boolean isProcessingTransaction()
{
return getActiveRequester() != 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 = SystemMessage.getSystemMessage(SystemMessageId.BEGIN_TRADE_WITH_C1);
msg.addPcName(partner);
sendPacket(msg);
sendPacket(new TradeStart(this));
}
public void onTradeConfirm(L2PcInstance partner)
{
SystemMessage msg = SystemMessage.getSystemMessage(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 = SystemMessage.getSystemMessage(SystemMessageId.C1_CANCELED_TRADE);
msg.addPcName(partner);
sendPacket(msg);
}
public void onTradeFinish(boolean successfull)
{
_activeTradeList = null;
sendPacket(new TradeDone(1));
if (successfull)
sendPacket(SystemMessage.getSystemMessage(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;
if (Config.OFFLINE_DISCONNECT_FINISHED && _privatestore == STORE_PRIVATE_NONE && (getClient() == null || getClient().isDetached()))
{
deleteMe();
}
}
/**
* 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 _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;
_activeWarehouse = null;
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;
// Don't allow disarming a Combat Flag or Territory Ward
if (isCombatFlagEquipped()) return false;
// Unequip the weapon
L2ItemInstance wpn = getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
if (wpn != null)
{
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 = SystemMessage.getSystemMessage(SystemMessageId.EQUIPMENT_S1_S2_REMOVED);
sm.addNumber(unequiped[0].getEnchantLevel());
sm.addItemName(unequiped[0]);
}
else
{
sm = SystemMessage.getSystemMessage(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)
{
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 = SystemMessage.getSystemMessage(SystemMessageId.EQUIPMENT_S1_S2_REMOVED);
sm.addNumber(unequiped[0].getEnchantLevel());
sm.addItemName(unequiped[0]);
}
else
{
sm = SystemMessage.getSystemMessage(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;
stopAllToggles();
Ride mount = new Ride(this, true, pet.getTemplate().npcId);
setMount(pet.getNpcId(), pet.getLevel(), mount.getMountType());
setMountObjectID(pet.getControlObjectId());
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;
stopAllToggles();
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(SystemMessage.getSystemMessage(SystemMessageId.STRIDER_CANT_BE_RIDDEN_WHILE_DEAD));
return false;
}
else if (pet.isDead())
{
//A dead strider cannot be ridden.
sendPacket(ActionFailed.STATIC_PACKET);
sendPacket(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(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);
//FIXME: Wrong Message
sendMessage("You cannot mount a steed while holding a flag.");
return false;
}
else if (pet.isHungry())
{
sendPacket(ActionFailed.STATIC_PACKET);
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.HUNGRY_STRIDER_NOT_MOUNT));
return false;
}
else if (!Util.checkIfInRange(200, this, pet, true))
{
sendPacket(ActionFailed.STATIC_PACKET);
sendPacket(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(SystemMessageId.NO_DISMOUNT_HERE));
return false;
}
else if (isHungry())
{
sendPacket(ActionFailed.STATIC_PACKET);
sendPacket(SystemMessage.getSystemMessage(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.FrequentSkill.WYVERN_BREATH.getSkill());
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.getItemType() == L2WeaponType.DUALDAGGER)
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 super.isInvul() || _teleportProtectEndTime > 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, messageType.Disconnected);
_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>
*/
@Override
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;
}
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(this);
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, boolean updateInDb)
{
if (_isOnline != isOnline)
_isOnline = isOnline;
// Update the characters table of the database with online status and lastAccess (called when login and logout)
if (updateInDb)
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, isOnlineInt());
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
{
L2DatabaseFactory.close(con);
}
}
/**
* 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, isOnlineInt());
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,getCreateTime());
statement.executeUpdate();
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Could not insert char data: " + e.getMessage(), e);
return false;
}
finally
{
L2DatabaseFactory.close(con);
}
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.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);
}
int pledgeClass = 0;
pledgeClass = player.getClan().getClanMember(objectId).calculatePledgeClass(player);
if (player.isNoble() && pledgeClass < 5)
pledgeClass = 5;
if (player.isHero() && pledgeClass < 8)
pledgeClass = 8;
player.setPledgeClass(pledgeClass);
}
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");
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"));
// Language
player.setLang(rset.getString("language"));
// 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();
// Set Hero status if it applies
if (Hero.getInstance().getHeroes() != null && Hero.getInstance().getHeroes().containsKey(objectId))
player.setHero(true);
// 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
player.getInventory().restore();
player.getFreight().restore();
if (!Config.WAREHOUSE_CACHE)
player.getWarehouse();
// 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();
if (Config.STORE_UI_SETTINGS)
player.restoreUISettings();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Failed loading character.", e);
}
finally
{
L2DatabaseFactory.close(con);
}
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);
}
rset.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Could not restore classes for " + player.getName() + ": " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
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 the recipe book of this L2PcInstance.
restoreRecipeBook(true);
// Restore Recipe Shop list
if(Config.STORE_RECIPE_SHOPLIST)
restoreRecipeShopList();
// Load Premium Item List
loadPremiumItemList();
// Check for items in pet inventory
checkPetInvItems();
}
/**
* 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)
{
_log.log(Level.SEVERE, "Could not restore recipe book data:" + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
public Map<Integer, L2PremiumItem> getPremiumItemList()
{
return _premiumItems;
}
private void loadPremiumItemList()
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
String sql = "SELECT itemNum, itemId, itemCount, itemSender FROM character_premium_items WHERE charId=?";
PreparedStatement statement = con.prepareStatement(sql);
statement.setInt(1, getObjectId());
ResultSet rset = statement.executeQuery();
while (rset.next())
{
int itemNum = rset.getInt("itemNum");
int itemId = rset.getInt("itemId");
long itemCount = rset.getLong("itemCount");
String itemSender = rset.getString("itemSender");
_premiumItems.put(itemNum, new L2PremiumItem(itemId, itemCount, itemSender));
}
rset.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Could not restore premium items: "+ e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
public void updatePremiumItem(int itemNum, long newcount)
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("UPDATE character_premium_items SET itemCount=? WHERE charId=? AND itemNum=? ");
statement.setLong(1, newcount);
statement.setInt(2, getObjectId());
statement.setInt(3, itemNum);
statement.execute();
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Could not update premium items: "+ e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
public void deletePremiumItem(int itemNum)
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM character_premium_items WHERE charId=? AND itemNum=? ");
statement.setInt(1, getObjectId());
statement.setInt(2, itemNum);
statement.execute();
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Could not delete premium item: " + e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
/**
* 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();
if (Config.STORE_UI_SETTINGS)
storeUISettings();
SevenSigns.getInstance().saveSevenSignsData(getObjectId());
}
@Override
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 ? _lastX : getX());
statement.setInt(14, _observerMode ? _lastY : getY());
statement.setInt(15, _observerMode ? _lastZ : 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, getClanId());
statement.setInt(24, getRace().ordinal());
statement.setInt(25, getClassId().getId());
statement.setLong(26, getDeleteTimer());
statement.setString(27, getTitle());
statement.setInt(28, getAppearance().getTitleColor());
statement.setInt(29, getAccessLevel().getLevel());
statement.setInt(30, isOnlineInt());
statement.setInt(31, isIn7sDungeon() ? 1 : 0);
statement.setInt(32, getClanPrivileges());
statement.setInt(33, getWantsPeace());
statement.setInt(34, getBaseClass());
long totalOnlineTime = _onlineTime;
if (_onlineBeginTime > 0)
totalOnlineTime += (System.currentTimeMillis()-_onlineBeginTime)/1000;
statement.setLong(35, totalOnlineTime);
statement.setInt(36, getPunishLevel().value());
statement.setLong(37, getPunishTimer());
statement.setInt(38, getNewbie());
statement.setInt(39, isNoble() ? 1 : 0);
statement.setLong(40, getPowerGrade());
statement.setInt(41, getPledgeType());
statement.setInt(42,getLvlJoinedAcademy());
statement.setLong(43,getApprentice());
statement.setLong(44,getSponsor());
statement.setInt(45, getAllianceWithVarkaKetra());
statement.setLong(46, getClanJoinExpiryTime());
statement.setLong(47, getClanCreateExpiryTime());
statement.setString(48, getName());
statement.setLong(49, getDeathPenaltyBuffLevel());
statement.setInt(50, getBookMarkSlot());
statement.setInt(51, getVitalityPoints());
statement.setString(52, getLang());
statement.setInt(53, getObjectId());
statement.execute();
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Could not store char base data: "+this+" - " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
private void storeCharSub()
{
if (getTotalSubClasses() <= 0)
return;
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement(UPDATE_CHAR_SUBCLASS);
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.clearParameters();
}
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Could not store sub class data for " + getName() + ": " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
@Override
public 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();
if (storedSkills.contains(skill.getReuseHashCode()))
continue;
storedSkills.add(skill.getReuseHashCode());
if (!effect.isHerbEffect() && effect.getInUse()
&& !skill.isToggle())
{
statement.setInt(1, getObjectId());
statement.setInt(2, skill.getId());
statement.setInt(3, skill.getLevel());
statement.setInt(4, effect.getCount());
statement.setInt(5, effect.getTime());
if (_reuseTimeStamps.containsKey(skill.getReuseHashCode()))
{
TimeStamp t = _reuseTimeStamps.get(skill.getReuseHashCode());
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 (int hash : _reuseTimeStamps.keySet())
{
if (storedSkills.contains(hash))
continue;
TimeStamp t = _reuseTimeStamps.get(hash);
if (t != null && t.hasNotPassed())
{
storedSkills.add(hash);
statement.setInt(1, getObjectId());
statement.setInt(2, t.getSkillId());
statement.setInt(3, t.getSkillLvl());
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
{
L2DatabaseFactory.close(con);
}
}
/**
* Return True if the L2PcInstance is on line.<BR>
* <BR>
*/
public boolean isOnline()
{
return _isOnline;
}
public int isOnlineInt()
{
if (_isOnline && getClient() != null)
return getClient().isDetached() ? 2 : 1;
else
return 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;
}
@Override
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
final L2Skill oldSkill = super.removeSkill(skill);
if (oldSkill != null)
{
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);
statement.setInt(1, oldSkill.getId());
statement.setInt(2, getObjectId());
statement.setInt(3, getClassIndex());
statement.execute();
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Error could not delete skill: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
if (transformId() > 0 || isCursedWeaponEquipped())
return oldSkill;
final 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>
* 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.log(Level.WARNING, "Error could not store char skills: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
/**
* Retrieve from the database all skills of this L2PcInstance and add them to _skills.
*/
private void restoreSkills()
{
Connection con = null;
try
{
// Retrieve all skills of this L2PcInstance from the database
con = L2DatabaseFactory.getInstance().getConnection();
final PreparedStatement statement = con.prepareStatement(RESTORE_SKILLS_FOR_CHAR);
statement.setInt(1, getObjectId());
statement.setInt(2, getClassIndex());
final ResultSet rset = statement.executeQuery();
// Go though the recordset of this SQL query
while (rset.next())
{
final int id = rset.getInt("skill_id");
final int level = rset.getInt("skill_level");
// Create a L2Skill object for each record
final L2Skill skill = SkillTable.getInstance().getInfo(id, level);
if (skill == null)
{
_log.warning("Skipped null skill Id: " + id + " Level: " + level + " while restoring player skills for playerObjId: " + getObjectId());
continue;
}
// Add the L2Skill object to the L2Character _skills and its Func objects to the calculator set of the L2Character
super.addSkill(skill);
if (Config.SKILL_CHECK_ENABLE && (!isGM() || Config.SKILL_CHECK_GM))
{
if (!SkillTreesData.getInstance().isSkillAllowed(this, skill))
{
Util.handleIllegalPlayerAction(this, "Player " + getName() + " has invalid skill " + skill.getName() +
" ("+skill.getId() + "/" + skill.getLevel() + "), class:" + getTemplate().className, 1);
if (Config.SKILL_CHECK_REMOVE)
removeSkill(skill);
}
}
}
rset.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Could not restore character " + this + " skills: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
/**
* Retrieve from the database all skill effects of this L2PcInstance and add them to the player.
*/
@Override
public void restoreEffects()
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement;
ResultSet rset;
statement = con.prepareStatement(RESTORE_SKILL_SAVE);
statement.setInt(1, getObjectId());
statement.setInt(2, getClassIndex());
rset = statement.executeQuery();
while (rset.next())
{
int effectCount = rset.getInt("effect_count");
int effectCurTime = rset.getInt("effect_cur_time");
long reuseDelay = rset.getLong("reuse_delay");
long systime = rset.getLong("systime");
int restoreType = rset.getInt("restore_type");
final L2Skill skill = SkillTable.getInstance().getInfo(rset.getInt("skill_id"), rset.getInt("skill_level"));
if (skill == null)
continue;
final long remainingTime = systime - System.currentTimeMillis();
if (remainingTime > 10)
{
disableSkill(skill, remainingTime);
addTimeStamp(skill, reuseDelay, systime);
}
/**
* Restore Type 1
* The remaning skills lost effect upon logout but
* were still under a high reuse delay.
*/
if (restoreType > 0)
continue;
/**
* 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.
*
*/
if (skill.hasEffects())
{
Env env = new Env();
env.player = this;
env.target = this;
env.skill = skill;
L2Effect ef;
for (EffectTemplate et : skill.getEffectTemplates())
{
ef = et.getEffect(env);
if (ef != null)
{
ef.setCount(effectCount);
ef.setFirstTime(effectCurTime);
ef.scheduleEffect();
}
}
}
}
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.log(Level.WARNING, "Could not restore "+this+" active effect data: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
/**
* 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
{
L2DatabaseFactory.close(con);
}
// Calculate Henna modifiers of this L2PcInstance
recalcHennaStats();
}
/**
* 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
{
L2DatabaseFactory.close(con);
}
// 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 = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S2_S1_S);
sm.addItemName(henna.getItemIdDye());
sm.addItemNumber(henna.getAmountDyeRequire() / 2);
sendPacket(sm);
sendPacket(SystemMessage.getSystemMessage(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
{
L2DatabaseFactory.close(con);
}
// 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
*
*/
@Override
public boolean 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 false;
}
//************************************* 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 false;
}
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 false;
}
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 false;
}
// 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:
case TARGET_AURA_CORPSE_MOB:
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);
return true;
}
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() || isParalyzed() || isStunned() || isSleeping())
{
sendPacket(ActionFailed.STATIC_PACKET);
return false;
}
// Check if the player is dead
if (isDead())
{
// 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(SystemMessage.getSystemMessage(SystemMessageId.ONLY_FISHING_SKILLS_NOW));
return false;
}
if (inObserverMode())
{
sendPacket(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(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:
case TARGET_AREA_SUMMON:
case TARGET_AURA_CORPSE_MOB:
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))
{
SystemMessage sm = null;
if (_reuseTimeStamps.containsKey(skill.getReuseHashCode()))
{
int remainingTime = (int)(_reuseTimeStamps.get(skill.getReuseHashCode()).getRemaining()/1000);
int hours = remainingTime/3600;
int minutes = (remainingTime%3600)/60;
int seconds = (remainingTime%60);
if (hours > 0)
{
sm = SystemMessage.getSystemMessage(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 = SystemMessage.getSystemMessage(SystemMessageId.S2_MINUTES_S3_SECONDS_REMAINING_FOR_REUSE_S1);
sm.addSkillName(skill);
sm.addNumber(minutes);
}
else
{
sm = SystemMessage.getSystemMessage(SystemMessageId.S2_SECONDS_REMAINING_FOR_REUSE_S1);
sm.addSkillName(skill);
}
sm.addNumber(seconds);
}
else
{
sm = SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(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;
}
if (target.getActingPlayer() != null && getSiegeState() > 0 && isInsideZone(L2Character.ZONE_SIEGE)
&& target.getActingPlayer().getSiegeState() == getSiegeState()
&& target.getActingPlayer() != this && target.getActingPlayer().getSiegeSide() == getSiegeSide())
{
//
if (TerritoryWarManager.getInstance().isTWInProgress())
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_CANNOT_ATTACK_A_MEMBER_OF_THE_SAME_TERRITORY));
else
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.FORCED_ATTACK_IS_IMPOSSIBLE_AGAINST_SIEGE_SIDE_TEMPORARY_ALLIED_MEMBERS));
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 for Event Mob's
if (target instanceof L2EventMonsterInstance && ((L2EventMonsterInstance)target).eventSkillAttackBlocked())
{
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_AURA_CORPSE_MOB:
case TARGET_CLAN:
case TARGET_PARTY_CLAN:
case TARGET_ALLY:
case TARGET_PARTY:
case TARGET_SELF:
case TARGET_GROUND:
case TARGET_AREA_SUMMON:
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(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(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 = SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(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_AURA_CORPSE_MOB:
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(SystemMessage.getSystemMessage(SystemMessageId.INCORRECT_TARGET));
// 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(SystemMessage.getSystemMessage(SystemMessageId.INCORRECT_TARGET));
// 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(SystemMessage.getSystemMessage(SystemMessageId.TARGET_IS_INCORRECT));
// Send a Server->Client packet ActionFailed to the L2PcInstance
sendPacket(ActionFailed.STATIC_PACKET);
return false;
}
}
// TODO: Unhardcode skillId 844 which is the outpost construct skill
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, skill.getId() == 844))
|| (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(SystemMessage.getSystemMessage(SystemMessageId.CANT_SEE_TARGET));
sendPacket(ActionFailed.STATIC_PACKET);
return false;
}
}
else if (!GeoData.getInstance().canSeeTarget(this, target))
{
sendPacket(SystemMessage.getSystemMessage(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 = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
sm.addSkillName(skill);
}
else if (!castle.getArtefacts().contains(getTarget()))
{
sm = SystemMessage.getSystemMessage(SystemMessageId.INCORRECT_TARGET);
}
else if (!castle.getSiege().getIsInProgress())
{
sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
sm.addSkillName(skill);
}
else if (!Util.checkIfInRange(200, this, getTarget(), true))
{
sm = SystemMessage.getSystemMessage(SystemMessageId.DIST_TOO_FAR_CASTING_STOPPED);
}
else if (castle.getSiege().getAttackerClan(getClan()) == null)
{
sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
sm.addSkillName(skill);
}
else
{
if (!isCheckOnly)
{
sm = SystemMessage.getSystemMessage(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 = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
sm.addSkillName(skill);
}
else if (fort.getFlagPole() != getTarget())
{
sm = SystemMessage.getSystemMessage(SystemMessageId.INCORRECT_TARGET);
}
else if (!fort.getSiege().getIsInProgress())
{
sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
sm.addSkillName(skill);
}
else if (!Util.checkIfInRange(200, this, getTarget(), true))
{
sm = SystemMessage.getSystemMessage(SystemMessageId.DIST_TOO_FAR_CASTING_STOPPED);
}
else if (fort.getSiege().getAttackerClan(getClan()) == null)
{
sm = SystemMessage.getSystemMessage(SystemMessageId.S1_CANNOT_BE_USED);
sm.addSkillName(skill);
}
else
{
if (!isCheckOnly)
fort.getSiege().announceToPlayer(SystemMessage.getSystemMessage(SystemMessageId.S1_TRYING_RAISE_FLAG),getClan().getName());
return true;
}
sendPacket(sm);
return false;
}
public boolean isInLooterParty(int LooterId)
{
L2PcInstance looter = L2World.getInstance().getPlayer(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
)
{
SkillDat skilldat = getCurrentSkill();
SkillDat skilldatpet = getCurrentPetSkill();
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 ((skilldat != null && !skilldat.isCtrlPressed() && skill.isOffensive() && !srcIsSummon)
|| (skilldatpet != null && !skilldatpet.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.FrequentSkill.STRIDER_SIEGE_ASSAULT.getSkill();
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);
}
/**
* Stop all toggle-type effects
*/
public final void stopAllToggles()
{
_effects.stopAllToggles();
}
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;
}
private class InventoryEnable implements Runnable
{
@Override
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 maxcount, 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, maxcount, 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.add(itemId);
}
public boolean removeAutoSoulShot(int itemId)
{
return _activeSoulShots.remove(itemId);
}
public Set<Integer> getAutoSoulShot()
{
return _activeSoulShots;
}
public void rechargeAutoSoulShot(boolean physical, boolean magic, boolean summon)
{
L2ItemInstance item;
IItemHandler handler;
if (_activeSoulShots == null || _activeSoulShots.isEmpty())
return;
try
{
for (int itemId : _activeSoulShots)
{
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, false);
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, false);
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, false);
break;
}
}
else
{
if (itemId == 6645 || itemId == 20332)
{
handler = ItemHandler.getInstance().getItemHandler(item.getEtcItem());
if (handler != null)
handler.useItem(this, item, false);
}
}
}
}
else
{
removeAutoSoulShot(itemId);
}
}
}
catch (NullPointerException npe)
{
_log.log(Level.WARNING, toString() , npe);
}
}
/**
* Cancel autoshot for all shots matching crystaltype<BR>
* {@link L2Item#getCrystalType()}
*
* @param crystalType int type to disable
*/
public void disableAutoShotByCrystalType(int crystalType)
{
for (int itemId : _activeSoulShots)
{
if (ItemTable.getInstance().getTemplate(itemId).getCrystalType() == crystalType)
disableAutoShot(itemId);
}
}
/**
* Cancel autoshot use for shot itemId
* @param itemId int id to disable
* @return true if canceled.
*/
public boolean disableAutoShot(int itemId)
{
if (_activeSoulShots.contains(itemId))
{
removeAutoSoulShot(itemId);
sendPacket(new ExAutoSoulShot(itemId, 0));
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.AUTO_USE_OF_S1_CANCELLED);
sm.addString(ItemTable.getInstance().getTemplate(itemId).getName());
sendPacket(sm);
return true;
}
else return false;
}
/**
* Cancel all autoshots for player
*/
public void disableAutoShotsAll()
{
for (int itemId : _activeSoulShots)
{
sendPacket(new ExAutoSoulShot(itemId, 0));
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.AUTO_USE_OF_S1_CANCELLED);
sm.addString(ItemTable.getInstance().getTemplate(itemId).getName());
sendPacket(sm);
}
_activeSoulShots.clear();
}
private ScheduledFuture<?> _taskWarnUserTakeBreak;
private class WarnUserTakeBreak implements Runnable
{
@Override
public void run()
{
if (L2PcInstance.this.isOnline())
{
SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.PLAYING_FOR_LONG_TIME);
L2PcInstance.this.sendPacket(msg);
}
else
stopWarnUserTakeBreak();
}
}
private class RentPetTask implements Runnable
{
@Override
public void run()
{
stopRentPet();
}
}
private class WaterTask implements Runnable
{
@Override
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 = SystemMessage.getSystemMessage(SystemMessageId.DROWN_DAMAGE_S1);
sm.addNumber((int)reduceHp);
sendPacket(sm);
}
}
private class LookingForFishTask implements Runnable
{
boolean _isNoob, _isUpperGrade;
int _fishType, _fishGutsCheck;
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;
}
@Override
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)
{
_lastX = getX();
_lastY = getY();
_lastZ = getZ();
stopEffects(L2EffectType.HIDE);
_observerMode = true;
setTarget(null);
setIsParalyzed(true);
startParalyze();
setIsInvul(true);
getAppearance().setInvisible();
//sendPacket(new GMHide(1));
sendPacket(new ObservationMode(x, y, z));
getKnownList().removeAllKnownObjects(); // reinit knownlist
setXYZ(x, y, z);
broadcastUserInfo();
}
public void setLastCords(int x, int y, int z)
{
_lastX = getX();
_lastY = getY();
_lastZ = getZ();
}
public void enterOlympiadObserverMode(Location loc, int id)
{
if (getPet() != null)
getPet().unSummon(this);
stopEffects(L2EffectType.HIDE);
if (!getCubics().isEmpty())
{
for (L2CubicInstance cubic : getCubics().values())
{
cubic.stopAction();
cubic.cancelDisappear();
}
getCubics().clear();
}
if (getParty() != null)
getParty().removePartyMember(this, messageType.Expelled);
_olympiadGameId = id;
if (isSitting())
standUp();
if (!_observerMode)
{
_lastX = getX();
_lastY = getY();
_lastZ = getZ();
}
_observerMode = true;
setTarget(null);
setIsInvul(true);
getAppearance().setInvisible();
//sendPacket(new GMHide(1));
teleToLocation(loc, false);
sendPacket(new ExOlympiadMode(3));
broadcastUserInfo();
}
public void leaveObserverMode()
{
setTarget(null);
getKnownList().removeAllKnownObjects(); // reinit knownlist
setXYZ(_lastX, _lastY, _lastZ);
setIsParalyzed(false);
stopParalyze(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);
setFalling(); // prevent receive falling damage
_observerMode = false;
setLastCords(0, 0, 0);
sendPacket(new ObservationReturn(this));
broadcastUserInfo();
}
public void leaveOlympiadObserverMode()
{
if (_olympiadGameId == -1)
return;
_olympiadGameId = -1;
_observerMode = false;
setTarget(null);
sendPacket(new ExOlympiadMode(0));
teleToLocation(_lastX, _lastY, _lastZ, 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);
setLastCords(0, 0, 0);
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 getLastX()
{
return _lastX;
}
public int getLastY()
{
return _lastY;
}
public int getLastZ()
{
return _lastZ;
}
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 = SystemMessage.getSystemMessage(_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;
boolean isEnchantable = SkillTable.getInstance().isEnchantable(s.getId());
if (isEnchantable)
{
L2EnchantSkillLearn esl = EnchantGroupsTable.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();
statement.close();
}
catch (Exception e) {
_log.log(Level.WARNING, "WARNING: Could not add character sub class for " + getName() + ": " + e.getMessage(), e);
return false;
}
finally
{
L2DatabaseFactory.close(con);
}
// 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 + ".");
final ClassId subTemplate = ClassId.values()[classId];
final FastMap<Integer, L2SkillLearn> skillTree = SkillTreesData.getInstance().getCompleteClassSkillTree(subTemplate);
final FastMap<Integer, L2Skill> prevSkillList = new FastMap<Integer, L2Skill>();
for (L2SkillLearn skillInfo : skillTree.values())
{
if (skillInfo.getGetLevel() <= 40)
{
L2Skill prevSkill = prevSkillList.get(skillInfo.getSkillId());
L2Skill newSkill = SkillTable.getInstance().getInfo(skillInfo.getSkillId(), skillInfo.getSkillLevel());
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.log(Level.WARNING, "Could not modify sub class for " + getName() + " to class index " + classIndex + ": " + e.getMessage(), e);
// This must be done in order to maintain data consistency.
getSubClasses().remove(classIndex);
return false;
}
finally
{
L2DatabaseFactory.close(con);
}
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 (getPet() instanceof L2SummonInstance)
getPet().unSummon(this);
if (classIndex == 0)
{
setClassTemplate(getBaseClass());
}
else
{
try
{
setClassTemplate(getSubClasses().get(classIndex).getClassId());
}
catch (Exception e)
{
_log.log(Level.WARNING, "Could not switch " + getName() + "'s sub class to class index " + classIndex + ": " + e.getMessage(), 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.
*/
for (L2Skill oldSkill : getAllSkills())
super.removeSkill(oldSkill);
stopAllEffectsExceptThoseThatLastThroughDeath();
stopCubics();
restoreRecipeBook(false);
// Restore any Death Penalty Buff
restoreDeathPenaltyBuffLevel();
restoreSkills();
rewardSkills();
regiveTemporarySkills();
// 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(this, 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(MapRegionManager.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(getObjectId()) != SevenSigns.getInstance().getCabalHighestScore())
{
teleToLocation(MapRegionManager.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(getObjectId()) == SevenSigns.CABAL_NULL)
{
teleToLocation(MapRegionManager.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();
if (!isGM() && Config.DECREASE_SKILL_LEVEL)
checkPlayerSkills();
}
public long getLastAccess()
{
return _lastAccess;
}
@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 (isResurrectionBlocked())
return;
if (_reviveRequested == 1)
{
if (_revivePet == Pet)
{
Reviver.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.RES_HAS_ALREADY_BEEN_PROPOSED)); // Resurrection is already been proposed.
}
else
{
if (Pet)
Reviver.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.CANNOT_RES_PET2)); // A pet cannot be resurrected while it's owner is in the process of resurrecting.
else
Reviver.sendPacket(SystemMessage.getSystemMessage(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 (isAffected(CharEffectList.EFFECT_FLAG_CHARM_OF_COURAGE))
_revivePower=0;
else
_revivePower = Formulas.calculateSkillResurrectRestorePercent(skill.getPower(), Reviver);
restoreExp = (int)Math.round((getExpBeforeDeath() - getExp()) * _revivePower / 100);
_revivePet = Pet;
if (isAffected(CharEffectList.EFFECT_FLAG_CHARM_OF_COURAGE))
{
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()
{
if (isSpawnProtected())
{
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_ARE_NO_LONGER_PROTECTED_FROM_AGGRESSIVE_MONSTERS));
if (Config.RESTORE_SERVITOR_ON_RECONNECT && getPet() == null && CharSummonTable.getInstance().getServitors().containsKey(getObjectId()))
CharSummonTable.getInstance().restoreServitor(this);
if (Config.RESTORE_PET_ON_RECONNECT && getPet() == null && CharSummonTable.getInstance().getPets().containsKey(getObjectId()))
CharSummonTable.getInstance().restorePet(this);
}
if (isTeleportProtected())
sendMessage("Teleport spawn protection ended.");
setProtection(false);
setTeleportProtection(false);
}
/**
* Expertise of the L2PcInstance (None=0, D=1, C=2, B=3, A=4, S=5, S80=6, S84=7)
* @return int Expertise skill level.
*/
public int getExpertiseLevel()
{
int level = getSkillLevel(239);
if (level < 0)
level = 0;
return level;
}
@Override
public void teleToLocation(int x, int y, int z, int heading, boolean allowRandomOffset)
{
if (getVehicle() != null && !getVehicle().isTeleporting())
setVehicle(null);
if (isFlyingMounted() && z < -1005)
z = -1005;
super.teleToLocation(x, y, z, heading, allowRandomOffset);
}
@Override
public final void onTeleported()
{
super.onTeleported();
if (isInAirShip())
getAirShip().sendInfo(this);
// Force a revalidation
revalidateZone(true);
checkItemRestriction();
if ((Config.PLAYER_TELEPORT_PROTECTION > 0) && !isInOlympiadMode())
setTeleportProtection(true);
// Trained beast is after teleport lost
if (getTrainedBeasts() != null)
{
for(L2TamedBeastInstance tamedBeast : getTrainedBeasts())
tamedBeast.deleteMe();
getTrainedBeasts().clear();
}
// 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)
{
setIsTeleporting(teleport, true);
}
public void setIsTeleporting(boolean teleport, boolean useWatchDog)
{
super.setIsTeleporting(teleport);
if (!useWatchDog)
return;
if (teleport)
{
if ((_teleportWatchdog == null) && (Config.TELEPORT_WATCHDOG_TIMEOUT > 0))
{
synchronized(this)
{
if (_teleportWatchdog == null)
_teleportWatchdog = ThreadPoolManager.getInstance().scheduleGeneral(new TeleportWatchdog(), Config.TELEPORT_WATCHDOG_TIMEOUT * 1000);
}
}
}
else
{
if (_teleportWatchdog != null)
{
_teleportWatchdog.cancel(false);
//ThreadPoolManager.getInstance().removeGeneral((Runnable)_teleportWatchdog);
_teleportWatchdog = null;
}
}
}
private class TeleportWatchdog implements Runnable
{
private final L2PcInstance _player;
TeleportWatchdog()
{
_player = L2PcInstance.this;
}
@Override
public void run()
{
if (_player == null || !_player.isTeleporting())
return;
if (Config.DEBUG)
_log.warning("Player " + _player.getName() + " teleport timeout expired");
_player.onTeleported();
}
}
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 value, L2Character attacker, boolean awake, boolean isDOT, L2Skill skill)
{
if (skill != null)
getStatus().reduceHp(value, attacker, awake, isDOT, skill.isToggle(), skill.getDmgDirectlyToHP());
else
getStatus().reduceHp(value, attacker, awake, isDOT, false, false);
// notify the tamed beast of attacks
if (getTrainedBeasts() != null )
for(L2TamedBeastInstance tamedBeast : getTrainedBeasts())
tamedBeast.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 void addBypass(String bypass)
{
if (bypass == null) return;
synchronized(_validBypass)
{
_validBypass.add(bypass);
}
//_log.warning("[BypassAdd]"+getName()+" '"+bypass+"'");
}
public void addBypass2(String bypass)
{
if (bypass == null) return;
synchronized(_validBypass2)
{
_validBypass2.add(bypass);
}
//_log.warning("[BypassAdd]"+getName()+" '"+bypass+"'");
}
public boolean validateBypass(String cmd)
{
if (!Config.BYPASS_VALIDATION)
return true;
synchronized (_validBypass)
{
for (String bp : _validBypass)
{
if (bp == null)
continue;
//_log.warning("[BypassValidation]"+getName()+" '"+bp+"'");
if (bp.equals(cmd))
return true;
}
}
synchronized (_validBypass2)
{
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+"'.");
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().getControlObjectId() == 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;
}
return true;
}
public void clearBypass()
{
synchronized (_validBypass)
{
_validBypass.clear();
}
synchronized (_validBypass2)
{
_validBypass2.clear();
}
}
/**
* @return Returns the inBoat.
*/
public boolean isInBoat()
{
return _vehicle != null && _vehicle.isBoat();
}
/**
* @return
*/
public L2BoatInstance getBoat()
{
return (L2BoatInstance)_vehicle;
}
/**
* @return Returns the inAirShip.
*/
public boolean isInAirShip()
{
return _vehicle != null && _vehicle.isAirShip();
}
/**
* @return
*/
public L2AirShipInstance getAirShip()
{
return (L2AirShipInstance) _vehicle;
}
public L2Vehicle getVehicle()
{
return _vehicle;
}
public void setVehicle(L2Vehicle v)
{
if (v == null && _vehicle != null)
_vehicle.removePassenger(this);
_vehicle = v;
}
public void setInCrystallize(boolean inCrystallize)
{
_inCrystallize = inCrystallize;
}
public boolean isInCrystallize()
{
return _inCrystallize;
}
/**
* @return
*/
public Point3D getInVehiclePosition()
{
return _inVehiclePosition;
}
public void setInVehiclePosition(Point3D pt)
{
_inVehiclePosition = 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>
*
*/
@Override
public void deleteMe()
{
cleanup();
store();
super.deleteMe();
}
private synchronized void cleanup()
{
// 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
{
if (!isOnline())
_log.log(Level.SEVERE, "deleteMe() called on offline character "+this, new RuntimeException());
setOnlineStatus(false, true);
}
catch (Exception e)
{
_log.log(Level.SEVERE, "deleteMe()", e);
}
try
{
if(Config.ENABLE_BLOCK_CHECKER_EVENT && getBlockCheckerArena() != -1)
HandysBlockCheckerManager.getInstance().onDisconnect(this);
}
catch(Exception e)
{
_log.log(Level.SEVERE, "deleteMe()", e);
}
try
{
_isOnline = false;
abortAttack();
abortCast();
stopMove(null);
setDebug(null);
}
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, fort.getFortId());
else
{
int slot = getInventory().getSlotFromItem(getInventory().getItemByItemId(9819));
getInventory().unEquipItemInBodySlot(slot);
destroyItem("CombatFlag", getInventory().getItemByItemId(9819), null, true);
}
}
else if (isCombatFlagEquipped())
{
TerritoryWarManager.getInstance().dropCombatFlag(this, false, false);
}
}
catch (Exception e)
{
_log.log(Level.SEVERE, "deleteMe()", e);
}
try
{
PartyMatchWaitingList.getInstance().removePlayer(this);
if (_partyroom != 0)
{
PartyMatchRoom room = PartyMatchRoomList.getInstance().getRoom(_partyroom);
if (room != null)
{
room.deleteMember(this);
}
}
}
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);
}
// Recommendations must be saved before task (timer) is canceled
try
{
storeRecommendations();
}
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())
{
if (effect.getSkill().isToggle())
{
effect.exit();
continue;
}
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
final L2WorldRegion oldRegion = getWorldRegion();
if (oldRegion != null)
oldRegion.removeFromZones(this);
// Remove the L2PcInstance from the world
try
{
decayMe();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "deleteMe()", e);
}
// 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 (OlympiadManager.getInstance().isRegistered(this) || getOlympiadGameId() != -1) // handle removal from olympiad game
OlympiadManager.getInstance().removeDisconnectedCompetitor(this);
// If the L2PcInstance has Pet, unsummon it
if (getPet() != null)
{
try
{
getPet().setRestoreSummon(true);
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 (getClan() != null)
{
// set the status for pledge member list to OFFLINE
try
{
L2ClanMember clanMember = getClan().getClanMember(getObjectId());
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);
cancelActiveTrade();
}
// 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);
}
}
try
{
// Check if the L2PcInstance is in observer mode to set its position to its position
// before entering in observer mode
if (inObserverMode())
setXYZInvisible(_lastX, _lastY, _lastZ);
if (getVehicle() != null)
getVehicle().oustPlayer(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);
setXYZInvisible(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
{
getFreight().deleteMe();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "deleteMe()", e);
}
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);
}
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);
// 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)
{
_log.log(Level.WARNING, "Exception on deleteMe() changeCommunityBoard: " + e.getMessage(), e);
}
try
{
notifyFriends();
getBlockList().playerLogout();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception on deleteMe() notifyFriends: " + e.getMessage(), e);
}
}
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(SystemMessage.getSystemMessage(SystemMessageId.CAST_LINE_AND_START_FISHING));
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.
broadcastPacket(new ExFishingStart(this,_fish.getType(),_x,_y,_z,_lure.isNightLure()));
sendPacket(new PlaySound(1, "SF_P_01", 0, 0, 0, 0, 0));
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()
{
int skilllvl = getSkillLevel(1315);
final L2Effect e = getFirstEffect(2274);
if (e != null)
skilllvl = (int)e.getSkill().getPower();
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)
{
_fishing = false;
_fishx = 0;
_fishy = 0;
_fishz = 0;
//broadcastUserInfo();
if (_fishCombat == null)
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.BAIT_LOST_FISH_GOT_AWAY));
_fishCombat = null;
_lure = null;
//Ends fishing
broadcastPacket(new ExFishingEnd(win, this));
sendPacket(SystemMessage.getSystemMessage(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(getHtmlPrefix(), "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(), _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(), _punishTimer);
sendMessage("You are in jail for "+delayInMinutes+" minutes.");
}
if (!TvTEvent.isInactive() && TvTEvent.isPlayerParticipant(getObjectId()))
TvTEvent.removeParticipant(getObjectId());
if (OlympiadManager.getInstance().isRegisteredInComp(this))
OlympiadManager.getInstance().removeDisconnectedCompetitor(this);
// Open a Html message to inform the player
NpcHtmlMessage htmlMsg = new NpcHtmlMessage(0);
String jailInfos = HtmCache.getInstance().getHtm(getHtmlPrefix(), "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(), _punishTimer);
sendMessage("You are still "+getPunishLevel().string()+" for "+Math.round(_punishTimer/60000f)+" 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
{
@Override
public void run()
{
L2PcInstance.this.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(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(int value)
{
_player = L2PcInstance.this;
_value = value;
}
@Override
public void run()
{
if (_player == null || (_player.isDead() && !Config.FAME_FOR_DEAD_PLAYERS))
return;
if ((_player.getClient() == null || _player.getClient().isDetached()) && !Config.OFFLINE_FAME)
return;
_player.setFame(_player.getFame() + _value);
SystemMessage sm = SystemMessage.getSystemMessage(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;
}
@Override
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;
}
@Override
public boolean isAttackingDisabled()
{
return (super.isAttackingDisabled() || _combatFlagEquippedId);
}
public boolean isCombatFlagEquipped()
{
return _combatFlagEquippedId ;
}
public void setCombatFlagEquipped(boolean value)
{
_combatFlagEquippedId = value;
}
public final void setIsRidingStrider(boolean mode)
{
_isRidingStrider = mode;
}
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 = SystemMessage.getSystemMessage(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 = SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(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()
{
synchronized(this)
{
if (_soulTask != null)
{
_soulTask.cancel(false);
_soulTask = null;
}
_soulTask = ThreadPoolManager.getInstance().scheduleGeneral(new SoulTask(), 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
{
@Override
public void run()
{
L2PcInstance.this.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(), 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()
&& !isLucky()
&& !(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 = SystemMessage.getSystemMessage(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 = SystemMessage.getSystemMessage(SystemMessageId.DEATH_PENALTY_LEVEL_S1_ADDED);
sm.addNumber(getDeathPenaltyBuffLevel());
sendPacket(sm);
}
else
{
sendPacket(new EtcStatusUpdate(this));
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.DEATH_PENALTY_LIFTED));
}
}
public void restoreDeathPenaltyBuffLevel()
{
if(getDeathPenaltyBuffLevel() > 0)
addSkill(SkillTable.getInstance().getInfo(5076, getDeathPenaltyBuffLevel()), false);
}
private final FastMap<Integer, TimeStamp> _reuseTimeStamps = new FastMap<Integer, TimeStamp>().shared();
private boolean _canFeed;
private int _eventEffectId = 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 final int _skillId;
private final int _skillLvl;
private final long _reuse;
private final long _stamp;
public TimeStamp(L2Skill skill, long reuse)
{
_skillId = skill.getId();
_skillLvl = skill.getLevel();
_reuse = reuse;
_stamp = System.currentTimeMillis()+ reuse;
}
public TimeStamp(L2Skill skill, long reuse, long systime)
{
_skillId = skill.getId();
_skillLvl = skill.getLevel();
_reuse = reuse;
_stamp = systime;
}
public long getStamp()
{
return _stamp;
}
public int getSkillId()
{
return _skillId;
}
public int getSkillLvl()
{
return _skillLvl;
}
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()
{
return System.currentTimeMillis() < _stamp;
}
}
/**
* Index according to skill id the current
* timestamp of use.
* @param skillid
* @param reuse delay
*/
@Override
public void addTimeStamp(L2Skill skill, long reuse)
{
_reuseTimeStamps.put(skill.getReuseHashCode(), new TimeStamp(skill, reuse));
}
/**
* Index according to skill this TimeStamp
* instance for restoration purposes only.
* @param TimeStamp
*/
public void addTimeStamp(L2Skill skill, long reuse, long systime)
{
_reuseTimeStamps.put(skill.getReuseHashCode(), new TimeStamp(skill, reuse, systime));
}
@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)
{
if (target instanceof L2PcInstance)
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_EVADED_C2_ATTACK);
sm.addPcName((L2PcInstance) target);
sm.addCharName(this);
target.sendPacket(sm);
}
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.C1_ATTACK_WENT_ASTRAY).addPcName(this));
return;
}
// Check if hit is critical
if (pcrit)
{
sendPacket(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(SystemMessageId.CRITICAL_HIT_MAGIC));
if (isInOlympiadMode() &&
target instanceof L2PcInstance &&
((L2PcInstance)target).isInOlympiadMode() &&
((L2PcInstance)target).getOlympiadGameId() == getOlympiadGameId())
{
OlympiadGameManager.getInstance().notifyCompetitorDamage(this, damage);
}
final SystemMessage sm;
if (target.isInvul() && !(target instanceof L2Npc))
{
sm = SystemMessage.getSystemMessage(SystemMessageId.ATTACK_WAS_BLOCKED);
}
else if (target instanceof L2DoorInstance || target instanceof L2ControlTowerInstance)
{
sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_DID_S1_DMG);
sm.addNumber(damage);
}
else
{
sm = SystemMessage.getSystemMessage(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 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().getObjectId() == 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 = SystemMessage.getSystemMessage(SystemMessageId.S1_REQUIRED_FOR_SUMMONING);
sm.addItemName(summonSkill.getTargetConsumeId());
targetChar.sendPacket(sm);
return;
}
targetChar.getInventory().destroyItemByItemId("Consume", itemConsumeId, itemConsumeCount, summonerChar, targetChar);
SystemMessage sm = SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(SystemMessageId.THIS_ITEM_IS_NOT_AVAILABLE_FOR_THE_OLYMPIAD_EVENT));
return false;
}
if (summonerChar.inObserverMode())
{
return false;
}
if (!TvTEvent.onEscapeUse(summonerChar.getObjectId()))
{
summonerChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING));
return false;
}
if (summonerChar.isInsideZone(L2Character.ZONE_NOSUMMONFRIEND) || summonerChar.isFlyingMounted())
{
summonerChar.sendPacket(SystemMessage.getSystemMessage(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 = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_DEAD_AT_THE_MOMENT_AND_CANNOT_BE_SUMMONED);
sm.addPcName(targetChar);
summonerChar.sendPacket(sm);
return false;
}
if (targetChar.isInStoreMode())
{
SystemMessage sm = SystemMessage.getSystemMessage(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 = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ENGAGED_IN_COMBAT_AND_CANNOT_BE_SUMMONED);
sm.addPcName(targetChar);
summonerChar.sendPacket(sm);
return false;
}
if (targetChar.isInOlympiadMode())
{
summonerChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_CANNOT_SUMMON_PLAYERS_WHO_ARE_IN_OLYMPIAD));
return false;
}
if (targetChar.isFestivalParticipant() || targetChar.isFlyingMounted())
{
summonerChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING));
return false;
}
if (targetChar.inObserverMode())
{
summonerChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.C1_STATE_FORBIDS_SUMMONING).addCharName(targetChar));
return false;
}
if (targetChar.isCombatFlagEquipped())
{
summonerChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING));
return false;
}
if (!TvTEvent.onEscapeUse(targetChar.getObjectId()))
{
summonerChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING));
return false;
}
if (targetChar.isInsideZone(L2Character.ZONE_NOSUMMONFRIEND))
{
SystemMessage sm = SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(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.getObjectId());
if (SevenSigns.getInstance().isSealValidationPeriod())
{
if (targetCabal != SevenSigns.getInstance().getCabalHighestScore())
{
summonerChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_IN_AN_AREA_WHICH_BLOCKS_SUMMONING));
return false;
}
}
else
{
if (targetCabal == SevenSigns.CABAL_NULL)
{
summonerChar.sendPacket(SystemMessage.getSystemMessage(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);
}
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)
|| (isInOlympiadMode() && equippedItem.isOlyRestrictedItem())))
{
getInventory().unEquipItemInSlot(i);
InventoryUpdate iu = new InventoryUpdate();
iu.addModifiedItem(equippedItem);
sendPacket(iu);
SystemMessage sm = null;
if (equippedItem.getItem().getBodyPart() == L2Item.SLOT_BACK)
{
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.CLOAK_REMOVED_BECAUSE_ARMOR_SET_REMOVED));
return;
}
if (equippedItem.getEnchantLevel() > 0)
{
sm = SystemMessage.getSystemMessage(SystemMessageId.EQUIPMENT_S1_S2_REMOVED);
sm.addNumber(equippedItem.getEnchantLevel());
sm.addItemName(equippedItem);
}
else
{
sm = SystemMessage.getSystemMessage(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 */
private class FeedTask implements Runnable
{
@Override
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(SystemMessage.getSystemMessage(SystemMessageId.OUT_OF_FEED_MOUNT_CANCELED));
}
int[] foodIds = getPetData(getMountNpcId()).getFood();
if (foodIds.length == 0)
return;
L2ItemInstance food = null;
for (int id : foodIds)
{
//TODO: possibly pet inv?
food = getInventory().getItemByItemId(id);
if (food != null)
break;
}
if (food != null && isHungry())
{
IItemHandler handler = ItemHandler.getInstance().getItemHandler(food.getEtcItem());
if (handler != null)
{
handler.useItem(L2PcInstance.this, food, false);
SystemMessage sm = SystemMessage.getSystemMessage(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().getControlObjectId();
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");
}
}
private final void clearPetData()
{
_data = null;
}
private final L2PetData getPetData(int npcId)
{
if (_data == null)
_data = PetDataTable.getInstance().getPetData(npcId);
return _data;
}
private final L2PetLevelData getPetLevelData(int npcId)
{
if (_leveldata == null)
_leveldata = PetDataTable.getInstance().getPetData(npcId).getPetLevelData(getMountLevel());
return _leveldata;
}
public int getCurrentFeed() { return _curFeed; }
private int getFeedConsume()
{
// if pet is attacking
if (isAttackingNow())
return getPetLevelData(_mountNpcId).getPetFeedBattle();
else
return getPetLevelData(_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);
}
private int getMaxFeed()
{
return getPetLevelData(_mountNpcId).getPetMaxFeed();
}
private boolean isHungry()
{
return _canFeed ? (getCurrentFeed() < (getPetData(getMountNpcId()).getHungry_limit() / 100f * getPetLevelData(getMountNpcId()).getPetMaxFeed())):false;
}
private class Dismount implements Runnable
{
@Override
public void run()
{
try
{
L2PcInstance.this.dismount();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception on dismount(): " + e.getMessage(), e);
}
}
}
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
{
L2DatabaseFactory.close(con);
}
}
}
/** 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 event effect id
*/
public int getEventEffectId()
{
return _eventEffectId ;
}
public void startEventEffect(AbnormalEffect mask)
{
_eventEffectId |= mask.getMask();
broadcastUserInfo();
}
public void stopEventEffect(AbnormalEffect mask)
{
_eventEffectId &= ~mask.getMask();
broadcastUserInfo();
}
public void setIsInSiege(boolean b)
{
_isInSiege = b;
}
public boolean isInSiege()
{
return _isInSiege;
}
public FloodProtectors getFloodProtectors()
{
return getClient().getFloodProtectors();
}
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(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(SystemMessageId.FORCE_MAXLEVEL_REACHED));
}
else
{
SystemMessage sm = SystemMessage.getSystemMessage(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(), 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
{
@Override
public void run()
{
L2PcInstance.this.clearCharges();
}
}
public static 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.log(Level.WARNING, "Could not update character teleport bookmark data: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
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.log(Level.WARNING, "Could not delete character teleport bookmark data: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
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(SystemMessage.getSystemMessage(2359));
return;
}
SystemMessage sm = SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_DURING_A_BATTLE));
return false;
}
else if (this.isInSiege() || this.getSiegeState() != 0)
{
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_WHILE_PARTICIPATING));
return false;
}
else if (this.isInDuel())
{
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_DURING_A_DUEL));
return false;
}
else if (this.isFlying())
{
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_WHILE_FLYING));
return false;
}
else if (this.isInOlympiadMode())
{
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_WHILE_PARTICIPATING_IN_AN_OLYMPIAD_MATCH));
return false;
}
else if (this.isParalyzed())
{
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_WHILE_YOU_ARE_PARALYZED));
return false;
}
else if (this.isDead())
{
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_WHILE_YOU_ARE_DEAD));
return false;
}
else if (type == 1 && (isIn7sDungeon() || (isInParty() && getParty().isInDimensionalRift())))
{
sendPacket(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_IN_THIS_AREA));
else if (type == 1)
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_TO_REACH_THIS_AREA));
return false;
}
else if (this.isInWater())
{
sendPacket(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_TO_REACH_THIS_AREA));
return false;
}
else if (isInsideZone(ZONE_NOBOOKMARK))
{
if(type == 0)
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_CANNOT_USE_MY_TELEPORTS_IN_THIS_AREA));
else if (type == 1)
sendPacket(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(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(SystemMessage.getSystemMessage(2358));
return;
}
if(getInventory().getInventoryItemCount(20033, 0) == 0)
{
sendPacket(SystemMessage.getSystemMessage(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 = SystemMessage.getSystemMessage(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.log(Level.WARNING, "Could not insert character teleport bookmark data: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
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
{
L2DatabaseFactory.close(con);
}
}
@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);
Integer oldrelation = getKnownList().getKnownRelations().get(activeChar.getObjectId());
if (oldrelation != null && oldrelation != relation1)
{
activeChar.sendPacket(new RelationChanged(this, relation1, isAutoAttackable(activeChar)));
if (getPet() != null)
activeChar.sendPacket(new RelationChanged(getPet(), relation1, isAutoAttackable(activeChar)));
}
oldrelation = activeChar.getKnownList().getKnownRelations().get(getObjectId());
if (oldrelation != null && oldrelation != relation2)
{
sendPacket(new RelationChanged(activeChar, relation2, activeChar.isAutoAttackable(this)));
if (activeChar.getPet() != null)
sendPacket(new RelationChanged(activeChar.getPet(), relation2, activeChar.isAutoAttackable(this)));
}
activeChar.sendPacket(new GetOnVehicle(getObjectId(), getBoat().getObjectId(), getInVehiclePosition()));
}
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);
Integer oldrelation = getKnownList().getKnownRelations().get(activeChar.getObjectId());
if (oldrelation != null && oldrelation != relation1)
{
activeChar.sendPacket(new RelationChanged(this, relation1, isAutoAttackable(activeChar)));
if (getPet() != null)
activeChar.sendPacket(new RelationChanged(getPet(), relation1, isAutoAttackable(activeChar)));
}
oldrelation = activeChar.getKnownList().getKnownRelations().get(getObjectId());
if (oldrelation != null && oldrelation != relation2)
{
sendPacket(new RelationChanged(activeChar, relation2, activeChar.isAutoAttackable(this)));
if (activeChar.getPet() != null)
sendPacket(new RelationChanged(activeChar.getPet(), relation2, activeChar.isAutoAttackable(this)));
}
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);
Integer oldrelation = getKnownList().getKnownRelations().get(activeChar.getObjectId());
if (oldrelation != null && oldrelation != relation1)
{
activeChar.sendPacket(new RelationChanged(this, relation1, isAutoAttackable(activeChar)));
if (getPet() != null)
activeChar.sendPacket(new RelationChanged(getPet(), relation1, isAutoAttackable(activeChar)));
}
oldrelation = activeChar.getKnownList().getKnownRelations().get(getObjectId());
if (oldrelation != null && oldrelation != relation2)
{
sendPacket(new RelationChanged(activeChar, relation2, activeChar.isAutoAttackable(this)));
if (activeChar.getPet() != null)
sendPacket(new RelationChanged(activeChar.getPet(), relation2, activeChar.isAutoAttackable(this)));
}
}
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)
{
if (_movieId > 0) //already in movie
return;
abortAttack();
abortCast();
stopMove(null);
_movieId = id;
sendPacket(new ExStartScenePlayer(id));
}
public boolean isAllowedToEnchantSkills()
{
if (isLocked())
return false;
if (isTransformed() || isInStance())
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 final 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.log(Level.WARNING, "Error found in " + getName() + "'s FriendList: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
/**
*
*/
private void notifyFriends()
{
FriendStatusPacket pkt = new FriendStatusPacket(getObjectId());
for(int id : _friendList)
{
L2PcInstance friend = L2World.getInstance().getPlayer(id);
if (friend != null)
friend.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();
PreparedStatement statement2 = con.prepareStatement("INSERT INTO character_recipeshoplist (charId, Recipeid, Price, Pos) VALUES (?, ?, ?, ?)");
for (L2ManufactureItem item : list.getList())
{
statement2.setInt(1, getObjectId());
statement2.setInt(2, item.getRecipeId());
statement2.setLong(3, item.getCost());
statement2.setInt(4, _position);
statement2.execute();
statement2.clearParameters();
_position++;
}
statement2.close();
}
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Could not store recipe shop for playerID " + getObjectId() + ": ", e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
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
{
L2DatabaseFactory.close(con);
}
}
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;
}
public final int getClientX()
{
return _clientX;
}
public final int getClientY()
{
return _clientY;
}
public final int getClientZ()
{
return _clientZ;
}
public final int getClientHeading()
{
return _clientHeading;
}
public final void setClientX(int val)
{
_clientX=val;
}
public final void setClientY(int val)
{
_clientY=val;
}
public final void setClientZ(int val)
{
_clientZ=val;
}
public final void setClientHeading(int val)
{
_clientHeading=val;
}
/**
* Return true if character falling now
* On the start of fall return false for correct coord sync !
*/
public final boolean isFalling(int z)
{
if (isDead()
|| isFlying()
|| isFlyingMounted()
|| isInsideZone(ZONE_WATER))
return false;
if (System.currentTimeMillis() < _fallingTimestamp)
return true;
final int deltaZ = getZ() - z;
if (deltaZ <= getBaseTemplate().getFallHeight())
return false;
final int damage = (int)Formulas.calcFallDam(this, deltaZ);
if (damage > 0)
{
reduceCurrentHp(Math.min(damage, getCurrentHp() - 1), null, false, true, null);
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.FALL_DAMAGE_S1).addNumber(damage));
}
setFalling();
return false;
}
/**
* Set falling timestamp
*/
public final void setFalling()
{
_fallingTimestamp = System.currentTimeMillis() + FALLING_VALIDATION_DELAY;
}
/**
* @return the _movieId
*/
public int getMovieId()
{
return _movieId;
}
public void setMovieId(int id)
{
_movieId = id;
}
/**
* Update last item auction request timestamp to current
*/
public void updateLastItemAuctionRequest()
{
_lastItemAuctionInfoRequest = System.currentTimeMillis();
}
/**
* Returns true if receiving item auction requests
* (last request was in 2 seconds before)
*/
public boolean isItemAuctionPolling()
{
return System.currentTimeMillis() - _lastItemAuctionInfoRequest < 2000;
}
/* (non-Javadoc)
* @see com.l2jserver.gameserver.model.actor.L2Character#isMovementDisabled()
*/
@Override
public boolean isMovementDisabled()
{
return super.isMovementDisabled() || _movieId > 0;
}
private void restoreUISettings()
{
_uiKeySettings = new L2UIKeysSettings(this);
}
private void storeUISettings()
{
if (_uiKeySettings == null)
return;
if (!_uiKeySettings.isSaved())
_uiKeySettings.saveInDB();
}
public L2UIKeysSettings getUISettings()
{
return _uiKeySettings;
}
public String getHtmlPrefix()
{
if (!Config.L2JMOD_MULTILANG_ENABLE)
return null;
return _htmlPrefix;
}
public String getLang()
{
return _lang;
}
public boolean setLang(String lang)
{
boolean result = false;
if (Config.L2JMOD_MULTILANG_ENABLE)
{
if (Config.L2JMOD_MULTILANG_ALLOWED.contains(lang))
{
_lang = lang;
result = true;
}
else
_lang = Config.L2JMOD_MULTILANG_DEFAULT;
_htmlPrefix = "data/lang/" + _lang + "/";
}
else
{
_lang = null;
_htmlPrefix = null;
}
return result;
}
public long getOfflineStartTime()
{
return _offlineShopStart;
}
public void setOfflineStartTime(long time)
{
_offlineShopStart = time;
}
/**
* Remove player from BossZones (used on char logout/exit)
*/
public void removeFromBossZone()
{
try
{
for (L2BossZone _zone : GrandBossManager.getInstance().getZones())
{
_zone.removePlayer(this);
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception on removeFromBossZone(): " + e.getMessage(), e);
}
}
/**
* Check all player skills for skill level. If player level is lower than skill learn level - 9, skill level is decreased to next possible level.
*/
public void checkPlayerSkills()
{
for (int id : _skills.keySet())
{
int level = getSkillLevel(id);
if (level >= 100) // enchanted skill
level = SkillTable.getInstance().getMaxLevel(id);
final L2SkillLearn learn = SkillTreesData.getInstance().getClassSkill(id, level, getClassId());
// not found - not a learn skill?
if (learn == null)
{
continue;
}
else
{
// player level is too low for such skill level
if (getLevel() < (learn.getGetLevel() - 9))
deacreaseSkillLevel(id);
}
}
}
private void deacreaseSkillLevel(int id)
{
int nextLevel = -1;
final FastMap<Integer, L2SkillLearn> skillTree = SkillTreesData.getInstance().getCompleteClassSkillTree(getClassId());
for (L2SkillLearn sl : skillTree.values())
{
if (sl.getSkillId() == id && nextLevel < sl.getSkillLevel() && getLevel() >= (sl.getGetLevel() - 9))
{
// next possible skill level
nextLevel = sl.getSkillLevel();
}
}
if (nextLevel == -1) // there is no lower skill
{
_log.info("Removing skill id "+id+ " level "+getSkillLevel(id)+" from player "+this);
removeSkill(_skills.get(id), true);
}
else // replace with lower one
{
_log.info("Decreasing skill id "+id+" from "+getSkillLevel(id)+" to "+nextLevel+" for "+this);
addSkill(SkillTable.getInstance().getInfo(id, nextLevel), true);
}
}
public boolean canMakeSocialAction()
{
if (getPrivateStoreType() == 0 && getActiveRequester() == null
&& !isAlikeDead() && (!isAllSkillsDisabled() || isInDuel())
&& !isCastingNow() && !isCastingSimultaneouslyNow()
&& getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE
&& !AttackStanceTaskManager.getInstance().getAttackStanceTask(this)
&& !isInOlympiadMode())
{
return true;
}
else
return false;
}
public void setMultiSocialAction(int id, int targetId)
{
_multiSociaAction = id;
_multiSocialTarget = targetId;
}
public int getMultiSociaAction()
{
return _multiSociaAction;
}
public int getMultiSocialTarget()
{
return _multiSocialTarget;
}
public List<TeleportBookmark> getTpbookmark()
{
return tpbookmark;
}
public int getBookmarkslot()
{
return _bookmarkslot;
}
/**
* @return
*/
public int getQuestInventoryLimit()
{
return Config.INVENTORY_MAXIMUM_QUEST_ITEMS;
}
public boolean canAttackCharacter(L2Character cha)
{
if(cha instanceof L2Attackable)
{
return true;
}
else if(cha instanceof L2Playable)
{
if(cha.isInsideZone(L2Character.ZONE_PVP) && !cha.isInsideZone(L2Character.ZONE_SIEGE))
return true;
L2PcInstance target;
if (cha instanceof L2Summon)
target = ((L2Summon) cha).getOwner();
else
target = (L2PcInstance) cha;
if (isInDuel() && target.isInDuel() && (target.getDuelId() == getDuelId()))
{
return true;
}
else if (isInParty() && target.isInParty())
{
if(getParty() == target.getParty())
return false;
if((getParty().getCommandChannel() != null || target.getParty().getCommandChannel() != null) && (getParty().getCommandChannel() == target.getParty().getCommandChannel()))
return false;
}
else if (getClan() != null && target.getClan() != null)
{
if (getClanId() == target.getClanId())
return false;
if ((getAllyId() > 0 || target.getAllyId() > 0) && (getAllyId() == target.getAllyId()))
return false;
if(getClan().isAtWarWith(target.getClan().getClanId()) && target.getClan().isAtWarWith(getClan().getClanId()))
return true;
}
else if (getClan() == null || target.getClan() == null)
{
if(target.getPvpFlag() == 0 && target.getKarma() == 0)
return false;
}
}
return true;
}
/**
* Test if player inventory is under 80% capaity
* @param includeQuestInv check also quest inventory
* @return
*/
public boolean isInventoryUnder80(boolean includeQuestInv)
{
if (getInventory().getSize(false) <= (getInventoryLimit() * 0.8))
{
if (includeQuestInv)
{
if (getInventory().getSize(true) <= (getQuestInventoryLimit() * 0.8))
return true;
}
else
return true;
}
return false;
}
public boolean havePetInvItems()
{
return _petItems;
}
public void setPetInvItems(boolean haveit)
{
_petItems = haveit;
}
private void checkPetInvItems()
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT object_id FROM `items` WHERE `owner_id`=? AND (`loc`='PET' OR `loc`='PET_EQUIP') LIMIT 1;");
statement.setInt(1, getObjectId());
ResultSet rset = statement.executeQuery();
if (rset.next() && rset.getInt("object_id") > 0)
setPetInvItems(true);
else
setPetInvItems(false);
rset.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Could not check Items in Pet Inventory for playerId: "+getObjectId(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
public String getAdminConfirmCmd()
{
return _adminConfirmCmd;
}
public void setAdminConfirmCmd(String adminConfirmCmd)
{
_adminConfirmCmd = adminConfirmCmd;
}
public void setBlockCheckerArena(byte arena)
{
_handysBlockCheckerEventArena = arena;
}
public int getBlockCheckerArena()
{
return _handysBlockCheckerEventArena;
}
/**
* Load L2PcInstance Recommendations data.<BR><BR>
*/
private long loadRecommendations()
{
long _time_left = 0;
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT rec_have,rec_left,time_left FROM character_reco_bonus WHERE charId=? LIMIT 1");
statement.setInt(1, getObjectId());
ResultSet rset = statement.executeQuery();
if(rset.next())
{
setRecomHave(rset.getInt("rec_have"));
setRecomLeft(rset.getInt("rec_left"));
_time_left = rset.getLong("time_left");
}
else
{
_time_left = 3600000;
}
rset.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Could not restore Recommendations for player: "+getObjectId(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
return _time_left;
}
/**
* Update L2PcInstance Recommendations data.<BR><BR>
*/
public void storeRecommendations()
{
long _recoTaskEnd = 0;
if(_recoBonusTask != null)
_recoTaskEnd = Math.max(0, _recoBonusTask.getDelay(TimeUnit.MILLISECONDS));
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("INSERT INTO character_reco_bonus (charId,rec_have,rec_left,time_left) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE rec_have=?, rec_left=?, time_left=?");
statement.setInt(1, getObjectId());
statement.setInt(2, getRecomHave());
statement.setInt(3, getRecomLeft());
statement.setLong(4, _recoTaskEnd);
// Update part
statement.setInt(5, getRecomHave());
statement.setInt(6, getRecomLeft());
statement.setLong(7, _recoTaskEnd);
statement.execute();
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Could not update Recommendations for player: "+getObjectId(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
public void checkRecoBonusTask()
{
// Load data
long _task_time = loadRecommendations();
if(_task_time > 0)
{
// Add 20 recos on first login
if(_task_time == 3600000)
setRecomLeft(getRecomLeft()+20);
// If player have some timeleft, start bonus task
_recoBonusTask = ThreadPoolManager.getInstance().scheduleGeneral(new RecoBonusTaskEnd(), _task_time);
}
// Create task to give new recommendations
_recoGiveTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new RecoGiveTask(), 7200000, 3600000);
// Store new data
storeRecommendations();
}
public void stopRecoBonusTask()
{
if (_recoBonusTask != null)
{
_recoBonusTask.cancel(false);
_recoBonusTask = null;
}
}
public void stopRecoGiveTask()
{
if (_recoGiveTask != null)
{
_recoGiveTask.cancel(false);
_recoGiveTask = null;
}
}
private class RecoGiveTask implements Runnable
{
@Override
public void run()
{
if (L2PcInstance.this == null)
{
//stopRecoGiveTask(); why is this here? it will lead to NPE
return;
}
int reco_to_give;
// 10 recommendations to give out after 2 hours of being logged in
// 1 more recommendation to give out every hour after that.
if(_recoTwoHoursGiven)
reco_to_give = 1;
else
reco_to_give = 10;
_recoTwoHoursGiven = true;
setRecomLeft(getRecomLeft()+reco_to_give);
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_OBTAINED_S1_RECOMMENDATIONS);
sm.addNumber(reco_to_give);
L2PcInstance.this.sendPacket(sm);
L2PcInstance.this.sendPacket(new UserInfo(L2PcInstance.this));
}
}
private class RecoBonusTaskEnd implements Runnable
{
@Override
public void run()
{
if (L2PcInstance.this == null)
return;
L2PcInstance.this.sendPacket(new ExVoteSystemInfo(L2PcInstance.this));
}
}
public int getRecomBonusTime()
{
if(_recoBonusTask != null)
return (int) Math.max(0, _recoBonusTask.getDelay(TimeUnit.SECONDS));
return 0;
}
public int getRecomBonusType()
{
// Maintain = 1
return 0;
}
public void setLastPetitionGmName(String gmName)
{
_lastPetitionGmName = gmName;
}
public String getLastPetitionGmName()
{
return _lastPetitionGmName;
}
public L2ContactList getContactList()
{
return _contactList;
}
public void setEventStatus()
{
eventStatus = new PlayerEventStatus(this);
}
public void setEventStatus(PlayerEventStatus pes)
{
eventStatus = pes;
}
public PlayerEventStatus getEventStatus()
{
return eventStatus;
}
}